Replace Markings Map with POJO (#3469)

update accumulo-utils to use a POJO for storing markings and then
updated the rest of the codebase that referenced it.
replaced some of the ColumnVisibility usage with AccessExpression to
improve performance.

---------

Co-authored-by: Joe Alphonso <[email protected]>
This commit is contained in:
Joseph AlphonsoandJoe Alphonso authored and Joe Alphonso committed 2026-06-12 15:25:43 -04:00
1 parent 8b044420ec
commit 336293cafc
210 files changed
+2694 -1820

No files matched your search

@@ -1,8 +1,7 @@
package datawave.marking;
import static com.google.common.base.Charsets.UTF_8;
import static datawave.marking.AccessExpressionMarkings.ACCESS;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -12,7 +11,7 @@ import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.accumulo.access.AccessExpression;
import com.google.common.base.Preconditions;
@@ -31,7 +30,7 @@ public class ColumnVisibilitySecurityMarking implements SecurityMarking {
if (null == values) {
throw new IllegalArgumentException("Required parameter " + VISIBILITY_MARKING + " not found");
}
if (values.isEmpty() || values.size() > 1) {
if (values.size() != 1) {
throw new IllegalArgumentException("Required parameter " + VISIBILITY_MARKING + " only accepts one value");
}
columnVisibility = values.get(0);
@@ -47,8 +46,16 @@ public class ColumnVisibilitySecurityMarking implements SecurityMarking {
}
@Override
public ColumnVisibility toColumnVisibility() {
return new ColumnVisibility(columnVisibility);
public AccessExpression toAccessExpression() {
if (columnVisibility == null || columnVisibility.isEmpty()) {
return ACCESS.newExpression("");
}
return ACCESS.newExpression(columnVisibility);
}
@Override
public Markings<?> toMarkings() {
return AccessExpressionMarkings.builder().accessExpression(toAccessExpression()).build();
}
@Override
@@ -72,65 +79,29 @@ public class ColumnVisibilitySecurityMarking implements SecurityMarking {
if (this.columnVisibility == null && other.columnVisibility != null) {
return false;
}
if (this.columnVisibility == null && other.columnVisibility == null) {
if (this.columnVisibility == null) {
return true;
}
if (this.columnVisibility.equals(other.columnVisibility)) {
return true;
} else {
return false;
}
return this.columnVisibility.equals(other.columnVisibility);
}
return false;
}
@Override
public String toString() {
return toColumnVisibilityString();
return toAccessExpressionString();
}
@Override
public String toColumnVisibilityString() {
public String toAccessExpressionString() {
if (null == this.columnVisibility) {
return null;
}
return new String(toColumnVisibility().flatten(), UTF_8);
return AccessExpressionUtil.normalize(columnVisibility).getExpression();
}
public void clear() {
this.columnVisibility = null;
}
@Override
public Map<String,String> toMap() {
return Collections.singletonMap(VISIBILITY_MARKING, this.columnVisibility);
}
@Override
public void fromMap(Map<String,String> map) {
this.columnVisibility = map.get(VISIBILITY_MARKING);
}
/**
* Turn this set of markings into a serializable string
*
* @return String
*/
@Override
public String mapToString() {
return MarkingFunctions.Encoding.toString(toMap());
}
/**
* Fill this security markings given an encoded string
*
* @param encodedMarkings
*/
@Override
public void fromString(String encodedMarkings) {
Map<String,String> markings = MarkingFunctions.Encoding.fromString(encodedMarkings);
this.columnVisibility = markings.get(VISIBILITY_MARKING);
Preconditions.checkNotNull(columnVisibility);
}
}
@@ -1,24 +1,16 @@
package datawave.marking;
import java.util.Map;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.accumulo.access.AccessExpression;
import datawave.validation.ParameterValidator;
public interface SecurityMarking extends ParameterValidator {
ColumnVisibility toColumnVisibility() throws MarkingFunctions.Exception;
AccessExpression toAccessExpression() throws MarkingFunctions.Exception;
String toColumnVisibilityString();
String toAccessExpressionString();
Map<String,String> toMap();
void fromMap(Map<String,String> map);
String mapToString();
void fromString(String xmlString);
Markings<?> toMarkings() throws MarkingFunctions.Exception;
void clear();
}
@@ -1,10 +1,10 @@
package datawave.webservice.query.result.event;
import java.util.Map;
import datawave.marking.Markings;
public interface HasMarkings {
void setMarkings(Map<String,String> markings);
void setMarkings(Markings<?> markings);
Map<String,String> getMarkings();
Markings<?> getMarkings();
}
@@ -7,26 +7,24 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import datawave.data.type.Type;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.webservice.query.cachedresults.CacheableQueryRow;
import datawave.webservice.query.data.ObjectSizeOf;
import datawave.webservice.query.util.TypedValue;
public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSizeOf {
private static Logger log = LoggerFactory.getLogger(CacheableQueryRowImpl.class);
private static final Logger LOGGER = LoggerFactory.getLogger(CacheableQueryRowImpl.class);
private String user = null;
private String queryId = null;
@@ -35,77 +33,52 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
private String eventId = null;
private String row = null;
private String colFam = null;
private Map<String,String> markings = new HashMap<>();
private Map<String,Map<String,String>> columnMarkingsMap = new HashMap<>();
private Markings<?> markings = null;
private Map<String,Markings<?>> columnMarkingsMap = new HashMap<>();
private Map<String,String> columnColumnVisibilityMap = new HashMap<>();
private Map<String,String> columnTypeMap = Maps.newHashMap();
private Map<String,String> columnTypeMap = new HashMap<>();
private Map<String,Long> columnTimestampMap = new HashMap<>();
private Map<String,Set<String>> columnValues = new HashMap<>();
private Set<String> variableColumnNames = new TreeSet<>();
private String queryOrigin = null;
private String resultOrigin = null;
public void addColumn(String columnName, String columnValueString, Map<String,String> markings, String columnVisibility, Long timestamp) {
public void addColumn(String columnName, String columnValueString, Markings<?> markings, String columnVisibility, Long timestamp) {
addColumn(columnName, new TypedValue(columnValueString), markings, columnVisibility, timestamp);
}
public void addColumn(String columnName, TypedValue columnTypedValue, Map<String,String> markings, String columnVisibility, Long timestamp) {
public void addColumn(String columnName, TypedValue columnTypedValue, Markings<?> markings, String columnVisibility, Long timestamp) {
columnName = columnName.replaceAll(" ", "_");
final String cleanColumnName = columnName.replace(' ', '_');
// if new markings are the same as the old markings, skip all of this
// they are the same and the markings value has already been validated
if (this.markings.equals(markings) == false) {
if (this.markings.isEmpty()) {
// validate the markings
try {
markingFunctions.translateToColumnVisibility(markings);
if (this.markings.isEmpty()) {
// markings were empty, so use the one passed in.
this.markings = markings;
}
} catch (MarkingFunctions.Exception e) {
log.error("Invalid markings {} skipping column {} = {}", markings, columnName, columnTypedValue, e);
return;
}
} else {
try {
Set<ColumnVisibility> columnVisibilities = Sets.newHashSet();
columnVisibilities.add(markingFunctions.translateToColumnVisibility(this.markings));
columnVisibilities.add(markingFunctions.translateToColumnVisibility(markings));
ColumnVisibility combinedVisibility = markingFunctions.combine(columnVisibilities);
// use combined marking as new markings
this.markings = markingFunctions.translateFromColumnVisibility(combinedVisibility);
} catch (MarkingFunctions.Exception e) {
log.error("Invalid markings {} skipping column {} = {}", markings, columnName, columnTypedValue, e);
return;
}
}
try {
this.markings = markingFunctions.combine(this.markings, markings);
} catch (MarkingFunctions.Exception e) {
LOGGER.error("Invalid markings {} skipping column {} = {}", markings, cleanColumnName, columnTypedValue, e);
return;
}
Long currTimestamp = columnTimestampMap.get(columnName);
Long currTimestamp = columnTimestampMap.get(cleanColumnName);
if (currTimestamp == null || timestamp > currTimestamp) {
columnTimestampMap.put(columnName, timestamp);
columnTimestampMap.put(cleanColumnName, timestamp);
}
Type<?> datawaveType = null;
String typedColumnName = "";
if (columnTypedValue.getValue() instanceof Type<?>) {
datawaveType = (Type<?>) columnTypedValue.getValue();
typedColumnName = columnTypedValue.getType().replaceAll(":", "_").toUpperCase();
typedColumnName += "_" + columnName;
typedColumnName = columnTypedValue.getType().replace(':', '_').toUpperCase();
typedColumnName += "_" + cleanColumnName;
}
manageColumnInsert(datawaveType, columnName, columnTypedValue, markings, columnVisibility);
if (!typedColumnName.isEmpty() && typedColumnName.startsWith("XS_STRING") == false) {
manageColumnInsert(datawaveType, cleanColumnName, columnTypedValue, markings, columnVisibility);
if (!typedColumnName.isEmpty() && !typedColumnName.startsWith("XS_STRING")) {
manageColumnInsert(datawaveType, typedColumnName, columnTypedValue, markings, columnVisibility);
}
}
private void manageColumnInsert(Type<?> datawaveType, String columnName, TypedValue columnTypedValue, Map<String,String> markings,
String columnVisibility) {
if (this.columnValues.containsKey(columnName) == false) {
private void manageColumnInsert(Type<?> datawaveType, String columnName, TypedValue columnTypedValue, Markings<?> markings, String columnVisibility) {
if (!this.columnValues.containsKey(columnName)) {
Set<String> valuesSet = Sets.newLinkedHashSet();
if (datawaveType != null) {
@@ -121,8 +94,8 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
this.columnValues.put(columnName, valuesSet);
this.columnMarkingsMap.put(columnName, markings);
this.columnColumnVisibilityMap.put(columnName, columnVisibility);
} else {
} else {
if (datawaveType != null) {
if (columnName.startsWith("XS")) {
columnValues.get(columnName).add(datawaveType.getNormalizedValue());
@@ -133,18 +106,18 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
} else {
columnValues.get(columnName).add(columnTypedValue.getValue().toString());
}
Map<String,String> currMarkings = columnMarkingsMap.get(columnName);
Markings<?> currMarkings = columnMarkingsMap.get(columnName);
if (currMarkings.equals(markings) == false) {
if (currMarkings == null) {
// existing marking was null so we update with new one
columnMarkingsMap.put(columnName, markings);
columnColumnVisibilityMap.put(columnName, columnVisibility);
} else if (!currMarkings.equals(markings)) {
try {
Set<ColumnVisibility> columnVisibilities = Sets.newHashSet();
columnVisibilities.add(markingFunctions.translateToColumnVisibility(currMarkings));
columnVisibilities.add(markingFunctions.translateToColumnVisibility(markings));
ColumnVisibility combinedVisibility = markingFunctions.combine(columnVisibilities);
Map<String,String> minMarkings = markingFunctions.translateFromColumnVisibility(combinedVisibility);
Markings<?> combinedMarkings = markingFunctions.combine(currMarkings, markings);
// use combined marking as new markings
columnMarkingsMap.put(columnName, minMarkings);
columnMarkingsMap.put(columnName, combinedMarkings);
// new combined marking means that this colVis is greater than old colVis
columnColumnVisibilityMap.put(columnName, columnVisibility);
} catch (MarkingFunctions.Exception e) {
@@ -183,21 +156,19 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
return colFam;
}
public Map<String,String> getMarkings() {
return Maps.newHashMap(markings);
public Markings<?> getMarkings() {
return markings;
}
public Map<String,String> getColumnMarkings(String columnName) {
columnName = columnName.replaceAll(" ", "_");
Map<String,String> markings = null;
if (this.columnMarkingsMap.containsKey(columnName)) {
markings = this.columnMarkingsMap.get(columnName);
public Markings<?> getColumnMarkings(String columnName) {
final String cleanColumnName = columnName.replace(' ', '_');
Markings<?> markings;
if (this.columnMarkingsMap.containsKey(cleanColumnName)) {
markings = this.columnMarkingsMap.get(cleanColumnName);
} else {
markings = this.columnMarkingsMap.get("_DEFAULT_");
}
if (markings == null)
markings = Maps.newHashMap();
return markings;
}
@@ -209,11 +180,7 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
Integer currColumnNumber = columnMap.get(currColumnName);
if (currColumnNumber != null) {
Long currLong = entry.getValue();
Set<String> columnSet = timestampMap.get(currLong);
if (columnSet == null) {
columnSet = new TreeSet<>();
timestampMap.put(currLong, columnSet);
}
Set<String> columnSet = timestampMap.computeIfAbsent(currLong, k -> new TreeSet<>());
columnSet.add(currColumnName);
}
}
@@ -243,10 +210,10 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
}
public String getColumnVisibility(String columnName) {
columnName = columnName.replaceAll(" ", "_");
String columnVisibility = null;
if (this.columnColumnVisibilityMap.containsKey(columnName)) {
columnVisibility = this.columnColumnVisibilityMap.get(columnName);
final String cleanColumnName = columnName.replace(' ', '_');
String columnVisibility;
if (this.columnColumnVisibilityMap.containsKey(cleanColumnName)) {
columnVisibility = this.columnColumnVisibilityMap.get(cleanColumnName);
} else {
columnVisibility = this.columnColumnVisibilityMap.get("_DEFAULT_");
}
@@ -255,10 +222,10 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
public Long getColumnTimestamp(String columnName) {
columnName = columnName.replaceAll(" ", "_");
final String cleanColumnName = columnName.replace(' ', '_');
Long timestamp = null;
if (this.columnTimestampMap.containsKey(columnName)) {
timestamp = this.columnTimestampMap.get(columnName);
if (this.columnTimestampMap.containsKey(cleanColumnName)) {
timestamp = this.columnTimestampMap.get(cleanColumnName);
} else {
timestamp = this.columnTimestampMap.get("_DEFAULT_");
}
@@ -289,17 +256,11 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
this.colFam = colFam;
}
public void setMarkings(Map<String,String> markings) {
// validate the markings
try {
markingFunctions.translateToColumnVisibility(markings);
this.markings = markings;
} catch (MarkingFunctions.Exception e) {
log.error("Invalid markings {}", markings, e);
}
public void setMarkings(Markings<?> markings) {
this.markings = markings;
}
public void setColumnMarkingsMap(Map<String,Map<String,String>> columnMarkingsMap) {
public void setColumnMarkingsMap(Map<String,Markings<?>> columnMarkingsMap) {
this.columnMarkingsMap = columnMarkingsMap;
}
@@ -317,14 +278,12 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
for (String field : columnMarkingsMap.keySet()) {
// sort the map
Map<String,String> m = columnMarkingsMap.get(field);
Markings<?> m = columnMarkingsMap.get(field);
String v = columnColumnVisibilityMap.get(field);
if (m == null) {
m = new HashMap<>();
String mStr = "";
if (m != null && !m.isEmpty()) {
mStr = m.toAccessExpression().getExpression();
}
// use TreeMap to sort the map
String mStr = MarkingFunctions.Encoding.toString(new TreeMap<>(m));
if (v == null) {
combinedMap.put(field, mStr);
} else {
@@ -338,11 +297,7 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
Map<String,Set<String>> markingToField = new HashMap<>();
for (Map.Entry<String,String> entry : combinedMap.entrySet()) {
String combinedMarking = entry.getValue();
Set<String> fields = markingToField.get(combinedMarking);
if (fields == null) {
fields = new HashSet<>();
markingToField.put(combinedMarking, fields);
}
Set<String> fields = markingToField.computeIfAbsent(combinedMarking, k -> new HashSet<>());
fields.add(entry.getKey());
if (fields.size() > largestSetCount) {
largestSetCount = fields.size();
@@ -377,9 +332,7 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
}
public List<String> getVariableColumnNames() {
List<String> l = new ArrayList<>();
l.addAll(variableColumnNames);
return l;
return new ArrayList<>(variableColumnNames);
}
public void setVariableColumnNames(Collection<String> c) {
@@ -9,10 +9,12 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.webservice.query.cachedresults.CacheableQueryRow;
import datawave.webservice.query.result.event.ResponseObjectFactory;
@@ -20,8 +22,9 @@ public class CacheableQueryRowReader {
private static Logger log = LoggerFactory.getLogger(CacheableQueryRowReader.class);
@SuppressWarnings("unchecked")
public static CacheableQueryRow createRow(ResultSet cachedRowSet, Set<String> fixedFieldsInEvent, ResponseObjectFactory responseObjectFactory,
MarkingFunctions markingFunctions) {
MarkingFunctions<?> markingFunctions) {
CacheableQueryRow cqfc = responseObjectFactory.getCacheableQueryRow();
cqfc.setMarkingFunctions(markingFunctions);
@@ -86,22 +89,25 @@ public class CacheableQueryRowReader {
}
if (columnToIndexMap.get("_markings_") != null) {
String mStr = cachedRowSet.getString(columnToIndexMap.get("_markings_"));
cqfc.setMarkings(MarkingFunctions.Encoding.fromString(mStr));
if (mStr != null && !mStr.isEmpty()) {
cqfc.setMarkings(markingFunctions.translateFromColumnVisibility(new ColumnVisibility(mStr)));
}
}
if (columnToIndexMap.get("_column_markings_") != null) {
String columnMarkings = cachedRowSet.getString(columnToIndexMap.get("_column_markings_"));
Map<String,String> combinedColumnMarkings = parseColumnMarkings(columnMarkings, columnToIndexMap);
Map<String,Map<String,String>> columnMarkingsMap = new HashMap<>();
Map<String,Markings<?>> columnMarkingsMap = new HashMap<>();
Map<String,String> columnVisibilityMap = new HashMap<>();
for (Map.Entry<String,String> entry : combinedColumnMarkings.entrySet()) {
String columnName = entry.getKey();
String combinedString = entry.getValue();
int x = combinedString.lastIndexOf(':');
if (x >= 0) {
columnMarkingsMap.put(columnName, MarkingFunctions.Encoding.fromString(combinedString.substring(0, x)));
String markingStr = combinedString.substring(0, x);
columnMarkingsMap.put(columnName, markingFunctions.translateFromColumnVisibility(new ColumnVisibility(markingStr)));
columnVisibilityMap.put(columnName, combinedString.substring(x + 1));
} else {
columnMarkingsMap.put(columnName, MarkingFunctions.Encoding.fromString(combinedString));
columnMarkingsMap.put(columnName, markingFunctions.translateFromColumnVisibility(new ColumnVisibility(combinedString)));
columnVisibilityMap.put(columnName, "");
}
}
@@ -115,6 +121,8 @@ public class CacheableQueryRowReader {
} catch (SQLException e) {
log.error(e.getMessage(), e);
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException(e);
}
return cqfc;
-4
View File
@@ -13,10 +13,6 @@
<dependencies />
</dependencyManagement>
<dependencies>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>datawave-core-connection-pool</artifactId>
@@ -27,6 +27,9 @@ public interface ClassCache {
* @param name
* the class name
* @return a {@link Class}
*
* @throws ClassNotFoundException
* if class not found
*/
Class<?> get(String name) throws ClassNotFoundException;
}
@@ -50,7 +50,9 @@ import datawave.data.ColumnFamilyConstants;
import datawave.data.type.Type;
import datawave.ingest.protobuf.Uid;
import datawave.ingest.protobuf.Uid.List.Builder;
import datawave.marking.AccessExpressionUtil;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.microservice.query.DefaultQueryParameters;
import datawave.microservice.query.QueryPersistence;
import datawave.modification.configuration.ModificationServiceConfiguration;
@@ -204,7 +206,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
protected String reverseIndexTableName = null;
protected String metadataTableName = null;
protected MetadataHelperFactory metadataHelperFactory;
protected MarkingFunctions markingFunctions = null;
protected MarkingFunctions<?> markingFunctions = null;
// a map of event fields to index only/derived fields to enable appropriate deleting of event fields and all derivatives
protected Multimap<String,String> indexOnlyMap = null;
@@ -247,11 +249,11 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
this.metadataTableName = metadataTableName;
}
public MarkingFunctions getMarkingFunctions() {
public MarkingFunctions<?> getMarkingFunctions() {
return markingFunctions;
}
public void setMarkingFunctions(MarkingFunctions markingFunctions) {
public void setMarkingFunctions(MarkingFunctions<?> markingFunctions) {
this.markingFunctions = markingFunctions;
}
@@ -310,6 +312,24 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
this.process(client, request, mutableFieldList, userAuths, userDetails, false, true);
}
/**
* Convert legacy Map&lt;String,String&gt; field markings (from DefaultModificationRequest) to Markings&lt;?&gt;.
*/
private Markings<?> convertFieldMarkings(Map<String,String> rawMarkings) {
if (rawMarkings == null || rawMarkings.isEmpty()) {
return null;
}
String vis = rawMarkings.getOrDefault("columnVisibility", "");
if (vis.isEmpty()) {
return null;
}
try {
return markingFunctions.translateFromColumnVisibility(new ColumnVisibility(vis));
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException(e);
}
}
public void process(AccumuloClient client, ModificationRequestBase request, Map<String,Set<String>> mutableFieldList, Set<Authorizations> userAuths,
ProxiedUserDetails userDetails, boolean purgeIndex, boolean insertHistory) throws Exception {
@@ -334,7 +354,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
String eventUid = e.getEventUid();
String oldFieldValue = null;
Map<String,String> oldFieldMarkings = null;
Markings<?> oldFieldMarkings = null;
String oldColumnVisibility = null;
List<Pair<Key,Value>> currentEntryList = null;
int valHistoryCount = 0;
@@ -358,8 +378,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
// Count the history entries if history is going to be inserted.
if (insertHistory && (MODE.INSERT.equals(mode) || MODE.UPDATE.equals(mode))) {
List<Pair<Key,Value>> fieldHistoryList = getField(client, userAuths, shardId, datatype, eventUid, "HISTORY_" + fieldName, null,
new HashMap<>(), null);
List<Pair<Key,Value>> fieldHistoryList = getField(client, userAuths, shardId, datatype, eventUid, "HISTORY_" + fieldName, null, null, null);
for (Pair<Key,Value> p : fieldHistoryList) {
if (p.getLeft().getColumnQualifier().find(mr.getFieldValue()) > -1) {
@@ -371,13 +390,13 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
if (MODE.UPDATE.equals(mode) || MODE.DELETE.equals(mode)) {
if (MODE.UPDATE.equals(mode)) {
oldFieldValue = mr.getOldFieldValue();
oldFieldMarkings = mr.getOldFieldMarkings();
oldFieldMarkings = convertFieldMarkings(mr.getOldFieldMarkings());
oldColumnVisibility = mr.getOldColumnVisibility();
if (null == oldFieldValue)
throw new IllegalArgumentException("fieldValue parameter required for update");
} else {
oldFieldValue = mr.getFieldValue();
oldFieldMarkings = mr.getFieldMarkings();
oldFieldMarkings = convertFieldMarkings(mr.getFieldMarkings());
oldColumnVisibility = mr.getColumnVisibility();
if (null == oldFieldValue)
throw new IllegalArgumentException("fieldValue parameter required for delete");
@@ -399,7 +418,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
if (MODE.INSERT.equals(mode)) {
String fieldValue = mr.getFieldValue();
Map<String,String> fieldMarkings = mr.getFieldMarkings();
Markings<?> fieldMarkings = convertFieldMarkings(mr.getFieldMarkings());
String columnVisibility = mr.getColumnVisibility();
ColumnVisibility colviz = null;
if (null != columnVisibility) {
@@ -414,7 +433,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
delete(writer, client, userAuths, currentEntryList, isIndexOnly, isIndexed, isReverseIndexed, isContent, dataTypes, user, MODE.UPDATE,
origTimestamp + valHistoryCount, purgeIndex, insertHistory);
String fieldValue = mr.getFieldValue();
Map<String,String> fieldMarkings = mr.getFieldMarkings();
Markings<?> fieldMarkings = convertFieldMarkings(mr.getFieldMarkings());
String columnVisibility = mr.getColumnVisibility();
ColumnVisibility colviz = null;
if (null != columnVisibility) {
@@ -636,7 +655,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
* @throws Exception
* if there are issues
*/
protected void insert(MultiTableBatchWriter writer, String shardId, String datatype, String eventUid, Map<String,String> markings, ColumnVisibility viz,
protected void insert(MultiTableBatchWriter writer, String shardId, String datatype, String eventUid, Markings<?> markings, ColumnVisibility viz,
String fieldName, String fieldValue, boolean isIndexOnlyField, boolean isIndexed, boolean isReverseIndexed, Set<Type<?>> dataTypes,
String user, MODE mode, long ts, boolean insertHistory) throws Exception {
@@ -644,7 +663,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
if (null == markings || markings.isEmpty())
throw new IllegalArgumentException("No security information specified. Security markings must be supplied");
viz = markingFunctions.translateToColumnVisibility(markings);
viz = markings.toColumnVisibility();
}
insert(writer, shardId, datatype, eventUid, viz, fieldName, fieldValue, ts, isIndexOnlyField, isIndexed, isReverseIndexed, dataTypes, false,
@@ -816,7 +835,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
* if there are issues
*/
protected List<Pair<Key,Value>> getField(AccumuloClient client, Set<Authorizations> userAuths, String shardId, String datatype, String eventUid,
String fieldName, String oldFieldValue, Map<String,String> oldFieldMarkings, ColumnVisibility oldColumnVisibility) throws Exception {
String fieldName, String oldFieldValue, Markings<?> oldFieldMarkings, ColumnVisibility oldColumnVisibility) throws Exception {
Text family = new Text(datatype);
TextUtil.textAppend(family, eventUid);
@@ -847,19 +866,28 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
}
if (null != oldColumnVisibility) {
// need to compare the flattened values for equivalence. It's possible for the visibility to be in a different order
String oldColViz = new String(oldColumnVisibility.flatten(), "UTF-8");
String thisVis = new String(thisViz.flatten(), "UTF-8");
// need to compare the normalized values for equivalence. It's possible for the visibility to be in a different order
String oldColViz = AccessExpressionUtil.normalize(oldColumnVisibility).getExpression();
String thisVis = AccessExpressionUtil.normalize(thisViz).getExpression();
if (!oldColViz.equals(thisVis)) {
log.trace("Skipping key that does not match with column visibility: {}", e.getKey());
if (log.isTraceEnabled()) {
log.trace("Skipping key that does not match with column visibility: {}", e.getKey());
}
continue;
}
} else {
Map<String,String> markings = markingFunctions.translateFromColumnVisibilityForAuths(e.getKey().getColumnVisibilityParsed(), userAuths);
if (null != oldFieldMarkings && !oldFieldMarkings.equals(markings)) {
log.trace("Skipping key that does not match with markings: {}", e.getKey());
continue;
try {
Markings<?> markings = markingFunctions.translateFromColumnVisibilityForAuths(e.getKey().getColumnVisibilityParsed(), userAuths);
if (null != oldFieldMarkings && !oldFieldMarkings.equals(markings)) {
if (log.isTraceEnabled()) {
log.trace("Skipping key that does not match with markings: {}", e.getKey());
}
continue;
}
} catch (MarkingFunctions.Exception ex) {
throw new RuntimeException(ex);
}
}
results.add(Pair.of(e.getKey(), e.getValue()));
}
@@ -126,7 +126,7 @@ class MutableMetadataHandlerTestSupport {
request.setFieldName(fieldName);
request.setFieldValue(fieldValue);
Map<String,String> markings = new HashMap<>();
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, columnVisibility);
markings.put("columnVisibility", columnVisibility);
request.setFieldMarkings(markings);
request.setColumnVisibility(null);
return request;
@@ -47,7 +47,7 @@ public abstract class BaseQueryLogic<T> implements QueryLogic<T> {
protected ProxiedUserDetails serverUser;
protected Set<String> requiredRoles;
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
protected ResponseObjectFactory responseObjectFactory;
protected SelectorExtractor selectorExtractor;
protected ResponseEnricherBuilder responseEnricherBuilder = null;
@@ -100,11 +100,11 @@ public abstract class BaseQueryLogic<T> implements QueryLogic<T> {
return settings.getQuery();
}
public MarkingFunctions getMarkingFunctions() {
public MarkingFunctions<?> getMarkingFunctions() {
return markingFunctions;
}
public void setMarkingFunctions(MarkingFunctions markingFunctions) {
public void setMarkingFunctions(MarkingFunctions<?> markingFunctions) {
this.markingFunctions = markingFunctions;
}
@@ -4,9 +4,9 @@ import datawave.marking.MarkingFunctions;
public abstract class BaseQueryLogicTransformer<I,O> extends AbstractQueryLogicTransformer<I,O> implements QueryLogicTransformer<I,O> {
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
public BaseQueryLogicTransformer(MarkingFunctions markingFunctions) {
public BaseQueryLogicTransformer(MarkingFunctions<?> markingFunctions) {
if (null == markingFunctions) {
throw new IllegalArgumentException("MarkingFunctions must be set");
}
@@ -251,12 +251,12 @@ public abstract class DelegatingQueryLogic implements QueryLogic<Object> {
}
@Override
public MarkingFunctions getMarkingFunctions() {
public MarkingFunctions<?> getMarkingFunctions() {
return delegate.getMarkingFunctions();
}
@Override
public void setMarkingFunctions(MarkingFunctions markingFunctions) {
public void setMarkingFunctions(MarkingFunctions<?> markingFunctions) {
delegate.setMarkingFunctions(markingFunctions);
}
@@ -317,9 +317,9 @@ public interface QueryLogic<T> extends Iterable<T>, Cloneable, ParameterValidato
Set<String> getRequiredRoles();
MarkingFunctions getMarkingFunctions();
MarkingFunctions<?> getMarkingFunctions();
void setMarkingFunctions(MarkingFunctions markingFunctions);
void setMarkingFunctions(MarkingFunctions<?> markingFunctions);
ResponseObjectFactory getResponseObjectFactory();
+74 -7
View File
@@ -9,6 +9,7 @@
<artifactId>accumulo-utils</artifactId>
<name>${project.artifactId}</name>
<properties>
<datawave.webservice.namespace>http://webservice.datawave.nsa/v1</datawave.webservice.namespace>
<version.dropwizard>4.1.2</version.dropwizard>
<!-- snappy and dropwizard required to allow miniaccumulo to work with upgraded zookeeper -->
<version.snappy>1.1.7</version.snappy>
@@ -67,15 +68,14 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.accumulo</groupId>
<artifactId>accumulo-core</artifactId>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
<artifactId>accumulo-access-core</artifactId>
<version>1.0.0-beta3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
@@ -85,6 +85,10 @@
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
@@ -103,11 +107,22 @@
<artifactId>spring-jcl</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${version.jaxb-impl}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>gov.nsa.datawave</groupId>
<artifactId>datawave-in-memory-accumulo</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
@@ -126,4 +141,56 @@
<url>https://maven.pkg.github.com/NationalSecurityAgency/datawave</url>
</repository>
</repositories>
<build>
<resources>
<resource>
<filtering>true</filtering>
<directory>src/main/resources</directory>
<excludes>
<exclude>source-templates/**</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-templated-sources</id>
<goals>
<goal>copy-resources</goal>
</goals>
<phase>validate</phase>
<configuration>
<outputDirectory>${project.build.directory}/generated-sources/templated-sources</outputDirectory>
<resources>
<resource>
<directory>src/main/resources/source-templates</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<goals>
<goal>add-source</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<sources>
<source>target/generated-sources/templated-sources</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,185 @@
package datawave.marking;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.accumulo.access.Access;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.hadoop.io.Text;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.protostuff.Input;
import io.protostuff.Output;
import io.protostuff.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.NONE)
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
public class AccessExpressionMarkings implements Markings<AccessExpression> {
public static final Access ACCESS = Access.builder().build();
public static final String COLUMN_VISIBILITY_KEY = "columnVisibility";
private AccessExpression accessExpression;
@Override
public AccessExpression getMarkings() {
return getAccessExpression();
}
@Override
public AccessExpression toAccessExpression() {
return accessExpression;
}
@Override
public ColumnVisibility toColumnVisibility() {
return AccessExpressionUtil.toColumnVisibility(AccessExpressionUtil.normalize(accessExpression));
}
@Override
public boolean isEmpty() {
return accessExpression == null || accessExpression.getExpression().isEmpty();
}
@JsonProperty(COLUMN_VISIBILITY_KEY)
@XmlElement(name = COLUMN_VISIBILITY_KEY)
public String getColumnVisibilityString() {
return accessExpression != null ? accessExpression.getExpression() : null;
}
// required for JAXB unmarshalling
public void setColumnVisibilityString(String ae) {
this.accessExpression = ae != null ? ACCESS.newExpression(ae) : null;
}
@JsonCreator
public static AccessExpressionMarkings create(@JsonProperty(COLUMN_VISIBILITY_KEY) String cv) {
if (cv != null && !cv.isEmpty()) {
return AccessExpressionMarkings.builder().columnVisibility(cv).build();
}
return null;
}
public static AccessExpressionMarkings createMarkings(ColumnVisibility cv) {
if (null == cv) {
return null;
}
return create(new String(cv.getExpression(), StandardCharsets.UTF_8));
}
public static AccessExpressionMarkings createMarkings(AccessExpression ae) {
if (null == ae) {
return null;
}
return create(ae.getExpression());
}
public static AccessExpressionMarkings createMarkings(Text cv) {
if (null == cv) {
return null;
}
return create(cv.toString());
}
public static AccessExpressionMarkings createMarkings(String cv) {
if (null == cv) {
return null;
}
return create(cv);
}
public static class AccessExpressionMarkingsBuilder {
public AccessExpressionMarkingsBuilder columnVisibility(String cv) {
this.accessExpression = cv != null ? ACCESS.newExpression(cv) : null;
return this;
}
}
@XmlTransient
public static final Schema<AccessExpressionMarkings> SCHEMA = new Schema<>() {
private final HashMap<String,Integer> fieldMap = new HashMap<>();
{
fieldMap.put(COLUMN_VISIBILITY_KEY, 1);
}
@Override
public String getFieldName(int number) {
if (number == 1) {
return COLUMN_VISIBILITY_KEY;
}
return null;
}
@Override
public int getFieldNumber(String name) {
final Integer number = fieldMap.get(name);
return number == null ? 0 : number;
}
@Override
public boolean isInitialized(AccessExpressionMarkings message) {
return true;
}
@Override
public AccessExpressionMarkings newMessage() {
return AccessExpressionMarkings.builder().build();
}
@Override
public String messageName() {
return AccessExpressionMarkings.class.getSimpleName();
}
@Override
public String messageFullName() {
return AccessExpressionMarkings.class.getName();
}
@Override
public Class<? super AccessExpressionMarkings> typeClass() {
return AccessExpressionMarkings.class;
}
@Override
public void mergeFrom(Input input, AccessExpressionMarkings message) throws IOException {
int number;
while ((number = input.readFieldNumber(this)) != 0) {
if (number == 1) {
String expr = input.readString();
if (expr != null && !expr.isEmpty()) {
message.accessExpression = ACCESS.newExpression(expr);
}
} else {
input.handleUnknownField(number, this);
}
}
}
@Override
public void writeTo(Output output, AccessExpressionMarkings message) throws IOException {
if (message.accessExpression != null) {
output.writeString(1, message.accessExpression.getExpression(), false);
}
}
};
}
@@ -0,0 +1,281 @@
package datawave.marking;
import static java.nio.charset.StandardCharsets.UTF_8;
import static datawave.marking.AccessExpressionMarkings.ACCESS;
import static org.apache.accumulo.access.ParsedAccessExpression.ExpressionType.AND;
import static org.apache.accumulo.access.ParsedAccessExpression.ExpressionType.AUTHORIZATION;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.accumulo.access.Access;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.ParsedAccessExpression;
import org.apache.accumulo.core.security.ColumnVisibility;
/**
* Utility for bridging between Accumulo's {@link ColumnVisibility} (from accumulo-core) and {@link AccessExpression} (from accumulo-access).
* <p>
* Many modules still require {@link ColumnVisibility} for the native Accumulo Key/Mutation API, while the marking functions layer has migrated to
* {@link AccessExpression}. This utility provides zero-copy-where-possible conversions between the two.
*/
public final class AccessExpressionUtil {
private static final AccessExpression EMPTY_EXPRESSION = ACCESS.newExpression("");
private static final ColumnVisibility EMPTY_VISIBILITY = new ColumnVisibility();
private AccessExpressionUtil() {}
/**
* Convert an {@link AccessExpression} to a {@link ColumnVisibility}.
*
* @param ae
* the access expression
* @return the equivalent column visibility
*/
public static ColumnVisibility toColumnVisibility(AccessExpression ae) {
if (null == ae) {
return null;
}
String expr = ae.getExpression();
if (expr.isEmpty()) {
return EMPTY_VISIBILITY;
}
return new ColumnVisibility(expr);
}
/**
* Convert a {@link ColumnVisibility} to an {@link AccessExpression}.
*
* @param cv
* the column visibility
* @return the equivalent access expression
*/
public static AccessExpression toAccessExpression(ColumnVisibility cv) {
if (null == cv) {
return null;
}
byte[] expr = cv.getExpression();
return toAccessExpression(expr);
}
/**
* Convert a visibility String to an {@link AccessExpression}.
*
* @param visibility
* the visibility String
* @return the equivalent access expression
*/
public static AccessExpression toAccessExpression(String visibility) {
if (visibility == null || visibility.isEmpty()) {
return EMPTY_EXPRESSION;
}
return ACCESS.newExpression(visibility);
}
/**
* Convert a raw visibility byte array (e.g. from {@code Key.getColumnVisibilityData()}) to an {@link AccessExpression}.
*
* @param visibilityBytes
* the raw visibility bytes
* @return the equivalent access expression
*/
public static AccessExpression toAccessExpression(byte[] visibilityBytes) {
if (visibilityBytes == null || visibilityBytes.length == 0) {
return EMPTY_EXPRESSION;
}
return ACCESS.newExpression(new String(visibilityBytes, UTF_8));
}
/**
* Normalize an {@link AccessExpression} by deduplicating and sorting terms. This is the replacement for the old {@code ColumnVisibility.flatten()}
* behavior.
*
* @param expression
* the expression to normalize
* @return a normalized {@link AccessExpression}
*/
public static AccessExpression normalize(AccessExpression expression) {
if (null == expression) {
return null;
}
return normalize(expression.getExpression());
}
/**
* Normalize a ColumnVisibility by deduplicating and sorting terms. This is the replacement for the old {@code ColumnVisibility.flatten()} behavior.
*
* @param cv
* the column visibility to normalize
* @return a normalized {@link AccessExpression}
*/
public static AccessExpression normalize(ColumnVisibility cv) {
if (null == cv) {
return null;
}
return normalize(new String(cv.getExpression(), UTF_8));
}
/**
* Normalize a ColumnVisibility String by deduplicating and sorting terms. This is the replacement for the old {@code ColumnVisibility.flatten()} behavior.
*
* @param cv
* the column visibility to normalize
* @return a normalized {@link AccessExpression}
*/
public static AccessExpression normalize(String cv) {
if (null == cv) {
return null;
}
ParsedAccessExpression parsed = ACCESS.newParsedExpression(cv);
return ACCESS.newExpression(normalize(parsed).expression);
}
/**
* @return the shared {@link Access} instance used by this utility
*/
public static Access getAccess() {
return ACCESS;
}
/**
* @return a cached empty {@link AccessExpression}
*/
public static AccessExpression emptyExpression() {
return EMPTY_EXPRESSION;
}
/**
* As part of normalizing access expression this class is used to sort and dedupe sub-expressions in a tree set.
*/
public static class NormalizedExpression implements Comparable<NormalizedExpression> {
public final String expression;
public final ParsedAccessExpression.ExpressionType type;
NormalizedExpression(String expression, ParsedAccessExpression.ExpressionType type) {
this.expression = expression;
this.type = type;
}
// determines the sort order of different kinds of subexpressions.
private static int typeOrder(ParsedAccessExpression.ExpressionType type) {
switch (type) {
case AUTHORIZATION:
return 1;
case OR:
return 2;
case AND:
return 3;
case EMPTY:
default:
throw new IllegalArgumentException("Unexpected type " + type);
}
}
@Override
public int compareTo(NormalizedExpression o) {
// Changing this comparator would significantly change how expressions are normalized.
int cmp = typeOrder(type) - typeOrder(o.type);
if (cmp == 0) {
if (type == AUTHORIZATION) {
// sort based on the unquoted and unescaped form of the authorization
cmp = ACCESS.unquote(expression).compareTo(ACCESS.unquote(o.expression));
} else {
cmp = expression.compareTo(o.expression);
}
}
return cmp;
}
@Override
public boolean equals(Object o) {
return this == o || (o instanceof NormalizedExpression && compareTo((NormalizedExpression) o) == 0);
}
@Override
public int hashCode() {
return expression.hashCode();
}
}
/**
* This method helps with the flattening aspect of normalization by recursing down as far as possible the parse tree in the case when the expression type is
* the same. As long as the type is the same in the sub expression, keep using the same set.
*/
private static void flatten(ParsedAccessExpression.ExpressionType parentType, ParsedAccessExpression parsed,
SortedSet<NormalizedExpression> normalizedExpressions) {
if (parsed.getType() == parentType) {
for (var child : parsed.getChildren()) {
flatten(parentType, child, normalizedExpressions);
}
} else {
// The type changed, so start again on the subexpression.
normalizedExpressions.add(normalize(parsed));
}
}
/**
* <p>
* For a given access expression this example will deduplicate, sort, flatten, and remove unneeded parentheses or quotes in the expressions. The following
* list gives examples of what each normalization step does.
*
* <ul>
* <li>As an example of flattening, the expression {@code A&(B&C)} flattens to {@code
* A&B&C}.</li>
* <li>As an example of sorting, the expression {@code (Z&Y)|(C&B)} sorts to {@code
* (B&C)|(Y&Z)}</li>
* <li>As an example of deduplication, the expression {@code X&Y&X} normalizes to {@code X&Y}</li>
* <li>As an example of unneeded quotes, the expression {@code "ABC"&"XYZ"} normalizes to {@code ABC&XYZ}</li>
* <li>As an example of unneeded parentheses, the expression {@code (((ABC)|(XYZ)))} normalizes to {@code ABC|XYZ}</li>
* </ul>
*
* <p>
* This algorithm attempts to have the same behavior as the one in the Accumulo 2.1 ColumnVisibility class. However the implementation is very different.
*/
public static NormalizedExpression normalize(ParsedAccessExpression parsed) {
if (parsed.getType() == AUTHORIZATION) {
// If the authorization is quoted and it does not need to be quoted then the following two
// lines will remove the unnecessary quoting.
String unquoted = ACCESS.unquote(parsed.getExpression());
String quoted = ACCESS.quote(unquoted);
return new NormalizedExpression(quoted, parsed.getType());
} else {
// The tree set does the work of sorting and deduplicating sub expressions.
TreeSet<NormalizedExpression> normalizedChildren = new TreeSet<>();
for (var child : parsed.getChildren()) {
flatten(parsed.getType(), child, normalizedChildren);
}
if (normalizedChildren.size() == 1) {
return normalizedChildren.first();
} else {
StringBuilder builder = getStringBuilder(parsed, normalizedChildren);
return new NormalizedExpression(builder.toString(), parsed.getType());
}
}
}
private static StringBuilder getStringBuilder(ParsedAccessExpression parsed, TreeSet<NormalizedExpression> normalizedChildren) {
String operator = parsed.getType() == AND ? "&" : "|";
String sep = "";
StringBuilder builder = new StringBuilder();
for (var child : normalizedChildren) {
builder.append(sep);
if (child.type == AUTHORIZATION) {
builder.append(child.expression);
} else {
builder.append("(");
builder.append(child.expression);
builder.append(")");
}
sep = operator;
}
return builder;
}
}
@@ -1,133 +0,0 @@
package datawave.marking;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.accumulo.core.security.ColumnVisibility.Node;
import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
import org.apache.accumulo.core.security.VisibilityEvaluator;
import org.apache.accumulo.core.security.VisibilityParseException;
import org.apache.log4j.Logger;
import datawave.marking.MarkingFunctions.Exception;
public class ColumnVisibilityHelper {
protected static final Charset charset = StandardCharsets.UTF_8;
private static Logger log = Logger.getLogger(ColumnVisibilityHelper.class);
public static ColumnVisibility simplifyColumnVisibilityForAuthorizations(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations)
throws MarkingFunctions.Exception {
ColumnVisibility simplifiedCV = columnVisibility;
Node node = columnVisibility.getParseTree();
if (node.getType() == NodeType.OR) {
if (log.isTraceEnabled()) {
log.trace("Top level OR Node, removing unsatisfied branches from: " + columnVisibility);
}
byte[] expression = columnVisibility.getExpression();
if (authorizations != null) {
HashSet<VisibilityEvaluator> ve = new HashSet<>();
for (Authorizations a : authorizations)
ve.add(new VisibilityEvaluator(a));
removeUnsatisfiedTopLevelOrNodes(ve, expression, node);
}
simplifiedCV = ColumnVisibilityHelper.flatten(node, expression);
if (log.isTraceEnabled()) {
log.trace("removed unsatisfied branches, visibility now: " + simplifiedCV);
}
}
return simplifiedCV;
}
public static ColumnVisibility removeUndisplayedVisibilities(ColumnVisibility columnVisibility, Set<String> undisplayedVisibilities)
throws MarkingFunctions.Exception {
ColumnVisibility newColumnVisibility = columnVisibility;
if (undisplayedVisibilities != null && !undisplayedVisibilities.isEmpty()) {
byte[] expression = columnVisibility.getExpression();
Node node = columnVisibility.getParseTree();
removeUndisplayedVisibilities(node, expression, undisplayedVisibilities);
newColumnVisibility = flatten(node, expression);
}
return newColumnVisibility;
}
private static void removeUnsatisfiedTopLevelOrNodes(Set<VisibilityEvaluator> ve, byte[] expression, Node node) throws Exception {
if (node.getType() == NodeType.OR) {
List<Node> children = node.getChildren();
int lastNode = children.size() - 1;
for (int x = lastNode; x >= 0; x--) {
Node currNode = children.get(x);
boolean remove = isUnsatisfied(x, ve, currNode, expression);
if (remove == true) {
children.remove(x);
}
}
}
}
private static boolean isUnsatisfied(int position, Set<VisibilityEvaluator> ve, Node currNode, byte[] expression) throws Exception {
boolean unsatisfied = false;
try {
ColumnVisibility currVis = ColumnVisibilityHelper.flatten(currNode, expression);
for (VisibilityEvaluator v : ve) {
if (!v.evaluate(currVis))
unsatisfied = true;
}
} catch (VisibilityParseException e) {
throw new MarkingFunctions.Exception(e);
}
return unsatisfied;
}
private static String termNodeToString(Node termNode, byte[] expression) throws Exception {
int start = termNode.getTermStart();
int end = termNode.getTermEnd();
String str = "[ERROR]";
try {
str = new String(expression, start, end - start, charset);
} catch (RuntimeException e) {
log.error("Error converting term: start:" + start + " length:" + (end - start) + "of expression:" + expression + " -- " + e.getMessage());
throw new MarkingFunctions.Exception(e);
}
return str;
}
private static ColumnVisibility flatten(Node node, byte[] expression) {
Node newNode = ColumnVisibility.normalize(node, expression);
StringBuilder sb = new StringBuilder();
ColumnVisibility.stringify(newNode, expression, sb);
return new ColumnVisibility(sb.toString());
}
private static void removeUndisplayedVisibilities(Node node, byte[] expression, Set<String> undisplayedVisibilities) throws MarkingFunctions.Exception {
List<Node> children = node.getChildren();
// walk backwards so we don't change the index that we need to remove
int lastNode = children.size() - 1;
for (int x = lastNode; x >= 0; x--) {
Node currNode = children.get(x);
if (currNode.getType() == NodeType.TERM) {
String nodeString = termNodeToString(currNode, expression);
if (undisplayedVisibilities.contains(nodeString)) {
children.remove(x);
}
} else {
removeUndisplayedVisibilities(currNode, expression, undisplayedVisibilities);
// if all children of this NodeType.AND or NodeType.OR node have been removed, remove the node itself.
if (currNode.getChildren().isEmpty()) {
children.remove(x);
}
}
}
}
}
@@ -13,7 +13,7 @@ import org.apache.accumulo.core.security.ColumnVisibility;
*
*/
public class FlattenedVisibilityCache {
private static Map<ColumnVisibility,byte[]> flattenedVisCache = Collections.synchronizedMap(new HashMap<>());
private static final Map<ColumnVisibility,byte[]> flattenedVisCache = Collections.synchronizedMap(new HashMap<>());
/**
* Create a flattened visibility, using the cache if possible
@@ -1,27 +1,23 @@
package datawave.marking;
import static java.nio.charset.StandardCharsets.UTF_8;
import static datawave.marking.AccessExpressionMarkings.ACCESS;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.ParsedAccessExpression;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.collect.Maps;
/**
* Accumulo marks all data with a columnVisibility that declares and controls access. MarkingFunctions provide a pattern for mapping a user's preferred means of
* declaring access controls with the Accumulo columnVisibility pattern. As an example, James Bond might use MarkingFunctions to translate a the
@@ -29,26 +25,23 @@ import com.google.common.collect.Maps;
* human-readable marking like "Patient Privileged Information"
*/
public interface MarkingFunctions {
public interface MarkingFunctions<T extends Markings<?>> {
ColumnVisibility combine(Collection<ColumnVisibility> columnVisibilities) throws MarkingFunctions.Exception;
ColumnVisibility combineVisibilities(Collection<ColumnVisibility> visibilities) throws MarkingFunctions.Exception;
@SuppressWarnings("unchecked")
Map<String,String> combine(Map<String,String>... markings) throws MarkingFunctions.Exception;
T combine(Collection<Markings<?>> markings) throws MarkingFunctions.Exception;
ColumnVisibility translateToColumnVisibility(Map<String,String> markings) throws MarkingFunctions.Exception;
T combine(Markings<?> markings1, Markings<?> markings2) throws MarkingFunctions.Exception;
Map<String,String> translateFromColumnVisibility(ColumnVisibility columnVisibility) throws MarkingFunctions.Exception;
Markings<?> translateFromColumnVisibility(ColumnVisibility columnVisibility) throws MarkingFunctions.Exception;
Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations)
Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations)
throws MarkingFunctions.Exception;
Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations)
throws MarkingFunctions.Exception;
Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations) throws MarkingFunctions.Exception;
byte[] flatten(ColumnVisibility vis);
@SuppressWarnings("serial")
class Exception extends java.lang.Exception {
public Exception() {
@@ -72,47 +65,100 @@ public interface MarkingFunctions {
}
}
class Default implements MarkingFunctions {
public static final String COLUMN_VISIBILITY = "columnVisibility";
class Default implements MarkingFunctions<AccessExpressionMarkings> {
@Override
public ColumnVisibility combine(Collection<ColumnVisibility> expressions) {
public ColumnVisibility combineVisibilities(Collection<ColumnVisibility> visibilities) {
AccessExpressionMarkings accessExpressionMarkings = combine(
visibilities.stream().filter(Objects::nonNull).map(AccessExpressionMarkings::createMarkings).collect(Collectors.toList()));
// filter out any empty expressions, then flatten each one (to de-dupe) and concatenate with '&'
// flatten the final combined ColumnVisibility and use that to make the ColumnVisibility to return
return new ColumnVisibility(new ColumnVisibility(expressions.stream().map(ColumnVisibility::flatten).filter(b -> b.length > 0)
.map(b -> "(" + new String(b, UTF_8) + ")").collect(Collectors.joining("&")).getBytes(UTF_8)).flatten());
if (null == accessExpressionMarkings) {
// is this correct behavior, does it match other implementations?
// switching to null causes lots of NPEs so leaving this as is
return new ColumnVisibility();
}
return accessExpressionMarkings.toColumnVisibility();
}
@Override
@SafeVarargs
public final Map<String,String> combine(Map<String,String>... markings) {
// translate COLUMN_VISIBILITY values to ColumnVisibility, combine them and
// return translated back to Map
return translateFromColumnVisibility(combine(Arrays.stream(markings).filter(m -> m.containsKey(COLUMN_VISIBILITY))
.map(this::translateToColumnVisibility).collect(Collectors.toSet())));
public AccessExpressionMarkings combine(Collection<Markings<?>> markings) {
Set<AccessExpressionMarkings> uniqueMarkings = new HashSet<>();
for (Markings<?> marking : markings) {
if (null == marking) {
continue;
}
if (!(marking instanceof AccessExpressionMarkings)) {
throw new RuntimeException(String.format("Unknown markings class %s", marking.getClass().getName()));
}
uniqueMarkings.add((AccessExpressionMarkings) marking);
}
if (uniqueMarkings.isEmpty()) {
return null;
}
if (uniqueMarkings.size() == 1) {
return uniqueMarkings.stream().findFirst().get();
}
Set<AccessExpression> uniqueExpressions = uniqueMarkings.stream().map(AccessExpressionMarkings::getMarkings).collect(Collectors.toSet());
// filter out any empty expressions and concatenate with '&'
// @formatter:off
ParsedAccessExpression expression = ACCESS.newParsedExpression(uniqueExpressions
.stream()
.map(AccessExpression::getExpression)
.filter(str -> !str.isEmpty())
.map(str -> "(" + str + ")")
.collect(Collectors.joining("&"))
);
// @formatter:on
// normalize the Parsed Expression and then return a copy without the parse tree
return AccessExpressionMarkings.builder().columnVisibility(AccessExpressionUtil.normalize(expression).expression).build();
}
@Override
public ColumnVisibility translateToColumnVisibility(Map<String,String> markings) {
ColumnVisibility cv = new ColumnVisibility(markings.get(COLUMN_VISIBILITY));
return new ColumnVisibility(cv.flatten());
public AccessExpressionMarkings combine(Markings<?> markings1, Markings<?> markings2) {
if (markings1 == null && markings2 == null) {
return null;
}
if (markings2 == null) {
return (AccessExpressionMarkings) markings1;
}
if (markings1 == null) {
return (AccessExpressionMarkings) markings2;
}
if (markings1 instanceof AccessExpressionMarkings && markings2 instanceof AccessExpressionMarkings) {
AccessExpressionMarkings aem1 = (AccessExpressionMarkings) markings1;
AccessExpressionMarkings aem2 = (AccessExpressionMarkings) markings2;
return combine(List.of(aem1, aem2));
}
throw new RuntimeException(String.format("Unknown markings class %s or %s", markings1.getClass().getName(), markings2.getClass().getName()));
}
@Override
public Map<String,String> translateFromColumnVisibility(ColumnVisibility expression) {
Map<String,String> markings = Maps.newHashMap();
markings.put(COLUMN_VISIBILITY, new String(expression.getExpression(), Charsets.UTF_8));
return markings;
public Markings<?> translateFromColumnVisibility(ColumnVisibility expression) {
String cv = new String(expression.getExpression(), StandardCharsets.UTF_8);
return AccessExpressionMarkings.builder().accessExpression(AccessExpressionUtil.normalize(cv)).build();
}
@Override
public Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations) {
public Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations) {
return translateFromColumnVisibility(columnVisibility);
}
@Override
public Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations) {
public Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations) {
return translateFromColumnVisibility(columnVisibility);
}
@@ -120,58 +166,6 @@ public interface MarkingFunctions {
public byte[] flatten(ColumnVisibility vis) {
return FlattenedVisibilityCache.flatten(vis);
}
}
class Util {
public static Object populate(Object obj, Map<String,String> source) {
try {
BeanUtils.populate(obj, source);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Error populating object: " + obj.getClass().getName(), e);
}
return obj;
}
}
class Encoding {
static private Logger log = LoggerFactory.getLogger(Encoding.class);
/**
* Turn a set of markings into a serializable string
*
* @param markings
* the markings map to convert to a string
* @return a serialized String version of {@code markings}
*/
public static String toString(Map<String,String> markings) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(markings);
} catch (JsonProcessingException e) {
log.error("could not serialize " + markings);
return "";
}
}
/**
* Turn a serialized set of markings into a map
*
* @param encodedMarkings
* the serialized String markings to convert back to a markings Map
* @return a {@link Map} of the de-serialized markings from {@code encodedMarkings}
*/
public static Map<String,String> fromString(String encodedMarkings) {
ObjectMapper objectMapper = new ObjectMapper();
try {
// noinspection unchecked
return objectMapper.readValue(encodedMarkings, Map.class);
} catch (IOException e) {
log.error("could not deserialize " + encodedMarkings);
return Collections.emptyMap();
}
}
}
/**
@@ -180,9 +174,9 @@ public interface MarkingFunctions {
class Factory {
public static final Logger log = LoggerFactory.getLogger(Factory.class);
private static MarkingFunctions markingFunctions;
private static MarkingFunctions<?> markingFunctions;
public static synchronized MarkingFunctions createMarkingFunctions() {
public static synchronized MarkingFunctions<?> createMarkingFunctions() {
if (markingFunctions != null)
return markingFunctions;
ClassLoader thisClassLoader = Factory.class.getClassLoader();
@@ -0,0 +1,20 @@
package datawave.marking;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.security.ColumnVisibility;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public interface Markings<T> {
T getMarkings();
AccessExpression toAccessExpression();
ColumnVisibility toColumnVisibility();
default boolean isEmpty() {
return getMarkings() == null;
}
}
@@ -1,46 +0,0 @@
package datawave.marking;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Arrays;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.accumulo.core.security.ColumnVisibility.Node;
import org.apache.accumulo.core.security.ColumnVisibility.NodeComparator;
import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
import org.apache.hadoop.io.Text;
public class VisibilityFlattener {
public static ColumnVisibility flatten(Node root, byte[] expression, boolean sort) {
StringBuilder out = new StringBuilder();
flatten(root, expression, out, sort);
return new ColumnVisibility(out.toString());
}
public static Text flattenToText(Node root, byte[] expression, boolean sort) {
StringBuilder out = new StringBuilder();
flatten(root, expression, out, sort);
return new Text(out.toString());
}
private static void flatten(Node root, byte[] expression, StringBuilder out, boolean sort) {
if (root.getType() == NodeType.TERM)
out.append(new String(expression, root.getTermStart(), root.getTermEnd() - root.getTermStart(), UTF_8));
else {
String sep = "";
Node[] children = root.getChildren().toArray(new Node[] {});
if (sort)
Arrays.sort(children, new NodeComparator(expression));
for (Node c : children) {
out.append(sep);
boolean parens = (c.getType() != NodeType.TERM && root.getType() != c.getType());
if (parens)
out.append("(");
flatten(c, expression, out, sort);
if (parens)
out.append(")");
sep = root.getType() == NodeType.AND ? "&" : "|";
}
}
}
}
@@ -0,0 +1,6 @@
@XmlSchema(namespace="${datawave.webservice.namespace}", elementFormDefault=XmlNsForm.QUALIFIED, xmlns={@XmlNs(prefix = "", namespaceURI = "${datawave.webservice.namespace}")})
package datawave.marking;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
@@ -0,0 +1,385 @@
package datawave.marking;
import static datawave.marking.AccessExpressionMarkings.ACCESS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.hadoop.io.Text;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
public class AccessExpressionMarkingsTest {
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final Schema<AccessExpressionMarkings> SCHEMA = AccessExpressionMarkings.SCHEMA;
// -- getMarkings / toAccessExpression --
@Test
public void testGetMarkingsReturnsAccessExpression() {
AccessExpression ae = ACCESS.newExpression("A&B");
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(ae).build();
assertEquals(ae, markings.getMarkings());
assertEquals(ae, markings.toAccessExpression());
}
// -- toColumnVisibility --
@Test
public void testToColumnVisibility() {
AccessExpressionMarkings markings = AccessExpressionMarkings.create("B&A");
ColumnVisibility cv = markings.toColumnVisibility();
// normalized: sorted
assertEquals("A&B", new String(cv.getExpression()));
}
// -- isEmpty --
@Test
public void testIsEmptyWithNullExpression() {
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(null).build();
assertTrue(markings.isEmpty());
}
@Test
public void testIsEmptyWithEmptyExpression() {
assertNull(AccessExpressionMarkings.create(""));
}
@Test
public void testIsEmptyWithNonEmptyExpression() {
AccessExpressionMarkings markings = AccessExpressionMarkings.create("A");
assertFalse(markings.isEmpty());
}
// -- getColumnVisibilityString --
@Test
public void testGetColumnVisibilityString() {
AccessExpressionMarkings markings = AccessExpressionMarkings.create("X|Y");
assertEquals("X|Y", markings.getColumnVisibilityString());
}
@Test
public void testGetColumnVisibilityStringNull() {
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(null).build();
assertNull(markings.getColumnVisibilityString());
}
// -- create (JsonCreator) --
@Test
public void testCreateWithNull() {
assertNull(AccessExpressionMarkings.create(null));
}
@Test
public void testCreateWithExpression() {
AccessExpressionMarkings markings = AccessExpressionMarkings.create("A&B&C");
assertEquals("A&B&C", markings.getColumnVisibilityString());
}
@Test
public void testCreateIllegalOperator1() {
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("A&&B&C"));
}
@Test
public void testCreateIllegalOperator2() {
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("A||B&C"));
}
@Test
public void testCreateMalformed1() {
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("(A&B&C))"));
}
@Test
public void testCreateMalformed2() {
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("(A&B,C))"));
}
// -- createMarkings(ColumnVisibility) --
@Test
public void testCreateMarkingsFromColumnVisibilityNull() {
assertNull(AccessExpressionMarkings.createMarkings((ColumnVisibility) null));
}
@Test
public void testCreateMarkingsFromColumnVisibility() {
ColumnVisibility cv = new ColumnVisibility("A|B");
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings(cv);
assertEquals("A|B", markings.getColumnVisibilityString());
}
// -- createMarkings(AccessExpression) --
@Test
public void testCreateMarkingsFromAccessExpressionNull() {
assertNull(AccessExpressionMarkings.createMarkings((AccessExpression) null));
}
@Test
public void testCreateMarkingsFromAccessExpression() {
AccessExpression ae = ACCESS.newExpression("C&D");
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings(ae);
assertEquals("C&D", markings.getColumnVisibilityString());
}
// -- createMarkings(Text) --
@Test
public void testCreateMarkingsFromTextNull() {
assertNull(AccessExpressionMarkings.createMarkings((Text) null));
}
@Test
public void testCreateMarkingsFromText() {
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings(new Text("E|F"));
assertEquals("E|F", markings.getColumnVisibilityString());
}
// -- createMarkings(String) --
@Test
public void testCreateMarkingsFromStringNull() {
assertNull(AccessExpressionMarkings.createMarkings((String) null));
}
@Test
public void testCreateMarkingsFromString() {
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings("G&H");
assertEquals("G&H", markings.getColumnVisibilityString());
}
// -- JSON round-trip --
@Test
public void testJsonSerialization() throws Exception {
AccessExpressionMarkings original = AccessExpressionMarkings.create("A&B");
String json = MAPPER.writeValueAsString(original);
assertTrue(json.contains("\"columnVisibility\":\"A&B\""));
}
@Test
public void testJsonDeserialization() throws Exception {
String json = "{\"@class\":\"datawave.marking.AccessExpressionMarkings\",\"columnVisibility\":\"X|Y\"}";
AccessExpressionMarkings markings = MAPPER.readValue(json, AccessExpressionMarkings.class);
assertEquals("X|Y", markings.getColumnVisibilityString());
}
@Test
public void testJsonRoundTrip() throws Exception {
AccessExpressionMarkings original = AccessExpressionMarkings.create("A&B&C");
String json = MAPPER.writeValueAsString(original);
// round-trip through the polymorphic Markings type
Markings<?> deserialized = MAPPER.readValue(json, Markings.class);
assertInstanceOf(AccessExpressionMarkings.class, deserialized);
assertEquals(original.getColumnVisibilityString(), ((AccessExpressionMarkings) deserialized).getColumnVisibilityString());
}
// -- equals via Lombok @Data --
@Test
public void testEquality() {
AccessExpressionMarkings a = AccessExpressionMarkings.create("A&B");
AccessExpressionMarkings b = AccessExpressionMarkings.create("A&B");
assertEquals(a, b);
assertEquals(a.hashCode(), b.hashCode());
}
// -- JAXB round-trip --
@Test
public void testJaxbMarshal() throws Exception {
AccessExpressionMarkings original = AccessExpressionMarkings.create("A&B");
String xml = makeJaxbMarshall(original);
assertTrue(xml.contains("<columnVisibility>A&amp;B</columnVisibility>"), "XML should contain the columnVisibility element: " + xml);
}
@Test
public void testJaxbUnmarshal() throws Exception {
String expression = "X|Y";
AccessExpressionMarkings markings = makeJaxbUnmarshall(expression);
assertEquals("X|Y", markings.getColumnVisibilityString());
assertFalse(markings.isEmpty());
}
@Test
public void testJaxbRoundTrip() throws Exception {
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|C");
AccessExpressionMarkings result = makeJaxbRoundTrip(original);
assertEquals(original.getColumnVisibilityString(), result.getColumnVisibilityString());
}
@Test
public void testJaxbRoundTripEmpty() throws Exception {
AccessExpressionMarkings original = AccessExpressionMarkings.builder().build();
AccessExpressionMarkings result = makeJaxbRoundTrip(original);
assertNull(result.getColumnVisibilityString());
assertTrue(result.isEmpty());
}
@Test
public void testJaxbRoundTripComplexExpression() throws Exception {
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|(C&D&E)");
AccessExpressionMarkings result = makeJaxbRoundTrip(original);
assertEquals("(A&B)|(C&D&E)", result.getColumnVisibilityString());
assertFalse(result.isEmpty());
}
// -- Protostuff Schema metadata --
@Test
public void testSchemaGetFieldNameKnown() {
assertEquals(AccessExpressionMarkings.COLUMN_VISIBILITY_KEY, SCHEMA.getFieldName(1));
}
@Test
public void testSchemaGetFieldNameUnknown() {
assertNull(SCHEMA.getFieldName(0));
assertNull(SCHEMA.getFieldName(2));
}
@Test
public void testSchemaGetFieldNumberKnown() {
assertEquals(1, SCHEMA.getFieldNumber(AccessExpressionMarkings.COLUMN_VISIBILITY_KEY));
}
@Test
public void testSchemaGetFieldNumberUnknown() {
assertEquals(0, SCHEMA.getFieldNumber("nonExistentField"));
}
@Test
public void testSchemaIsInitialized() {
assertTrue(SCHEMA.isInitialized(AccessExpressionMarkings.create("A")));
assertTrue(SCHEMA.isInitialized(AccessExpressionMarkings.builder().build()));
}
@Test
public void testSchemaNewMessage() {
AccessExpressionMarkings msg = SCHEMA.newMessage();
assertNotNull(msg);
assertTrue(msg.isEmpty());
}
@Test
public void testSchemaMessageName() {
assertEquals("AccessExpressionMarkings", SCHEMA.messageName());
}
@Test
public void testSchemaMessageFullName() {
assertEquals("datawave.marking.AccessExpressionMarkings", SCHEMA.messageFullName());
}
@Test
public void testSchemaTypeClass() {
assertEquals(AccessExpressionMarkings.class, SCHEMA.typeClass());
}
// -- Protostuff Schema round-trip serialization --
@Test
public void testProtostuffRoundTrip() {
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|C");
AccessExpressionMarkings deserialized = makeProtostuffRoundTrip(original);
assertEquals(original.getColumnVisibilityString(), deserialized.getColumnVisibilityString());
}
@Test
public void testProtostuffRoundTripEmpty() {
AccessExpressionMarkings original = AccessExpressionMarkings.builder().build();
AccessExpressionMarkings deserialized = makeProtostuffRoundTrip(original);
assertTrue(deserialized.isEmpty());
}
@Test
public void testProtostuffRoundTripComplexExpression() {
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|(C&D&E)");
AccessExpressionMarkings deserialized = makeProtostuffRoundTrip(original);
assertEquals("(A&B)|(C&D&E)", deserialized.getColumnVisibilityString());
assertFalse(deserialized.isEmpty());
}
private static String makeJaxbMarshall(AccessExpressionMarkings original) throws JAXBException {
JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class);
ByteArrayOutputStream out = marshal(original, ctx);
return out.toString();
}
private static AccessExpressionMarkings makeJaxbUnmarshall(String expression) throws JAXBException, IOException {
JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class);
String xml = String.format(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+ "<markings xmlns=\"http://webservice.datawave.nsa/v1\"><columnVisibility>%s</columnVisibility></markings>",
expression);
JAXBElement<AccessExpressionMarkings> element;
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
out.write(xml.getBytes());
element = unmarshal(out, ctx);
}
return element.getValue();
}
private static AccessExpressionMarkings makeJaxbRoundTrip(AccessExpressionMarkings original) throws JAXBException {
JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class);
ByteArrayOutputStream out = marshal(original, ctx);
JAXBElement<AccessExpressionMarkings> result = unmarshal(out, ctx);
return result.getValue();
}
private static ByteArrayOutputStream marshal(AccessExpressionMarkings original, JAXBContext ctx) throws JAXBException {
Marshaller marshaller = ctx.createMarshaller();
JAXBElement<AccessExpressionMarkings> element = new JAXBElement<>(new QName("http://webservice.datawave.nsa/v1", "markings"),
AccessExpressionMarkings.class, original);
ByteArrayOutputStream out = new ByteArrayOutputStream();
marshaller.marshal(element, out);
return out;
}
private static JAXBElement<AccessExpressionMarkings> unmarshal(ByteArrayOutputStream out, JAXBContext ctx) throws JAXBException {
Unmarshaller unmarshaller = ctx.createUnmarshaller();
return unmarshaller.unmarshal(new StreamSource(new ByteArrayInputStream(out.toByteArray())), AccessExpressionMarkings.class);
}
private static AccessExpressionMarkings makeProtostuffRoundTrip(AccessExpressionMarkings original) {
LinkedBuffer buffer = LinkedBuffer.allocate();
byte[] bytes = ProtostuffIOUtil.toByteArray(original, SCHEMA, buffer);
AccessExpressionMarkings deserialized = SCHEMA.newMessage();
ProtostuffIOUtil.mergeFrom(bytes, deserialized, SCHEMA);
return deserialized;
}
}
@@ -0,0 +1,215 @@
package datawave.marking;
import static datawave.marking.AccessExpressionMarkings.ACCESS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.ParsedAccessExpression;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.junit.jupiter.api.Test;
public class AccessExpressionUtilTest {
// -- toColumnVisibility --
@Test
public void testToColumnVisibilityNull() {
assertNull(AccessExpressionUtil.toColumnVisibility(null));
}
@Test
public void testToColumnVisibilityEmpty() {
AccessExpression ae = ACCESS.newExpression("");
ColumnVisibility cv = AccessExpressionUtil.toColumnVisibility(ae);
assertEquals(0, cv.getExpression().length);
}
@Test
public void testToColumnVisibilitySimple() {
AccessExpression ae = ACCESS.newExpression("A&B");
ColumnVisibility cv = AccessExpressionUtil.toColumnVisibility(ae);
assertEquals("A&B", new String(cv.getExpression()));
}
// -- toAccessExpression(ColumnVisibility) --
@Test
public void testToAccessExpressionFromColumnVisibilityNull() {
assertNull(AccessExpressionUtil.toAccessExpression((ColumnVisibility) null));
}
@Test
public void testToAccessExpressionFromColumnVisibilityEmpty() {
ColumnVisibility cv = new ColumnVisibility();
AccessExpression ae = AccessExpressionUtil.toAccessExpression(cv);
assertEquals("", ae.getExpression());
}
@Test
public void testToAccessExpressionFromColumnVisibility() {
ColumnVisibility cv = new ColumnVisibility("A|B");
AccessExpression ae = AccessExpressionUtil.toAccessExpression(cv);
assertEquals("A|B", ae.getExpression());
}
// -- toAccessExpression(String) --
@Test
public void testToAccessExpressionFromStringNull() {
AccessExpression ae = AccessExpressionUtil.toAccessExpression((String) null);
assertEquals("", ae.getExpression());
}
@Test
public void testToAccessExpressionFromStringEmpty() {
AccessExpression ae = AccessExpressionUtil.toAccessExpression("");
assertEquals("", ae.getExpression());
}
@Test
public void testToAccessExpressionFromString() {
AccessExpression ae = AccessExpressionUtil.toAccessExpression("X&Y");
assertEquals("X&Y", ae.getExpression());
}
// -- toAccessExpression(byte[]) --
@Test
public void testToAccessExpressionFromBytesNull() {
AccessExpression ae = AccessExpressionUtil.toAccessExpression((byte[]) null);
assertEquals("", ae.getExpression());
}
@Test
public void testToAccessExpressionFromBytesEmpty() {
AccessExpression ae = AccessExpressionUtil.toAccessExpression(new byte[0]);
assertEquals("", ae.getExpression());
}
@Test
public void testToAccessExpressionFromBytes() {
AccessExpression ae = AccessExpressionUtil.toAccessExpression("C&D".getBytes());
assertEquals("C&D", ae.getExpression());
}
// -- normalize --
@Test
public void testNormalizeEmpty() {
AccessExpression ae = ACCESS.newExpression("");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("", normalized.getExpression());
}
@Test
public void testNormalizeSortsTerms() {
AccessExpression ae = ACCESS.newExpression("Z&Y&X");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("X&Y&Z", normalized.getExpression());
}
@Test
public void testNormalizeDeduplicates() {
AccessExpression ae = ACCESS.newExpression("A&B&A");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("A&B", normalized.getExpression());
}
@Test
public void testNormalizeFlattensNestedAnds() {
AccessExpression ae = ACCESS.newExpression("A&(B&C)");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("A&B&C", normalized.getExpression());
}
@Test
public void testNormalizeSortsOrSubExpressions() {
AccessExpression ae = ACCESS.newExpression("(Z&Y)|(C&B)");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("(B&C)|(Y&Z)", normalized.getExpression());
}
@Test
public void testNormalizeRemovesUnnecessaryQuotes() {
AccessExpression ae = ACCESS.newExpression("\"ABC\"&\"XYZ\"");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("ABC&XYZ", normalized.getExpression());
}
@Test
public void testNormalizeRemovesUnnecessaryParentheses() {
AccessExpression ae = ACCESS.newExpression("(((ABC)|(XYZ)))");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("ABC|XYZ", normalized.getExpression());
}
@Test
public void testNormalizeSingleAuth() {
AccessExpression ae = ACCESS.newExpression("ALPHA");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("ALPHA", normalized.getExpression());
}
@Test
public void testNormalizeComplex1() {
AccessExpression ae = ACCESS.newExpression("(A&A)|(B&B)|(A&A&A)");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("A|B", normalized.getExpression());
}
@Test
public void testNormalizeComplex2() {
AccessExpression ae = ACCESS.newExpression("(Y|B|Y)&(Z|A|Z)");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("(A|Z)&(B|Y)", normalized.getExpression());
}
@Test
public void testNormalizeAlreadyOptimal() {
AccessExpression ae = ACCESS.newExpression("(A|B|C)&(B|C|D)");
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
assertEquals("(A|B|C)&(B|C|D)", normalized.getExpression());
}
// -- emptyExpression / getAccess --
@Test
public void testEmptyExpression() {
assertEquals("", AccessExpressionUtil.emptyExpression().getExpression());
}
@Test
public void testGetAccess() {
assertEquals(ACCESS, AccessExpressionUtil.getAccess());
}
// -- round-trip --
@Test
public void testRoundTripColumnVisibilityToAccessExpression() {
ColumnVisibility original = new ColumnVisibility("A&B&C");
AccessExpression ae = AccessExpressionUtil.toAccessExpression(original);
ColumnVisibility roundTripped = AccessExpressionUtil.toColumnVisibility(ae);
assertEquals(new String(original.getExpression()), new String(roundTripped.getExpression()));
}
// -- NormalizedExpression --
@Test
public void testNormalizedExpressionCompareTo() {
var a = new AccessExpressionUtil.NormalizedExpression("A", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
var b = new AccessExpressionUtil.NormalizedExpression("B", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
assertTrue(a.compareTo(b) < 0);
assertTrue(b.compareTo(a) > 0);
assertEquals(0, a.compareTo(a));
}
@Test
public void testNormalizedExpressionEquals() {
var a = new AccessExpressionUtil.NormalizedExpression("A", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
var aDuplicate = new AccessExpressionUtil.NormalizedExpression("A", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
assertEquals(a, aDuplicate);
}
}
@@ -1,61 +1,99 @@
package datawave.marking;
import static datawave.marking.MarkingFunctions.Default.COLUMN_VISIBILITY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.junit.jupiter.api.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
public class MarkingFunctionsDefaultCombineTest {
@Test
public void testCombineAnds() throws MarkingFunctions.Exception {
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
ColumnVisibility oneAnna = new ColumnVisibility("A&B");
ColumnVisibility twoAnna = new ColumnVisibility("A&C");
AccessExpressionMarkings oneAnna = AccessExpressionMarkings.builder().columnVisibility("A&B").build();
AccessExpressionMarkings twoAnna = AccessExpressionMarkings.builder().columnVisibility("A&C").build();
ColumnVisibility combined = markingFunctions.combine(Sets.newHashSet(oneAnna, twoAnna));
assertEquals(new ColumnVisibility("A&B&C"), combined);
AccessExpressionMarkings combined = markingFunctions.combine(List.of(oneAnna, twoAnna));
assertEquals(AccessExpressionMarkings.builder().columnVisibility("A&B&C").build(), combined);
}
@Test
public void testCombineOrs() throws MarkingFunctions.Exception {
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
ColumnVisibility oneOr = new ColumnVisibility("A|B");
ColumnVisibility twoOr = new ColumnVisibility("A|C");
AccessExpressionMarkings oneOr = AccessExpressionMarkings.builder().columnVisibility("A|B").build();
AccessExpressionMarkings twoOr = AccessExpressionMarkings.builder().columnVisibility("A|C").build();
ColumnVisibility combined = markingFunctions.combine(Sets.newHashSet(oneOr, twoOr));
assertEquals(new ColumnVisibility("(A|B)&(A|C)"), combined);
AccessExpressionMarkings combined = markingFunctions.combine(List.of(oneOr, twoOr));
assertEquals(AccessExpressionMarkings.builder().columnVisibility("(A|B)&(A|C)").build(), combined);
}
@Test
public void testCombineMapsOfAnds() throws MarkingFunctions.Exception {
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
Map<String,String> mapOne = ImmutableMap.of(COLUMN_VISIBILITY, "A&B");
Map<String,String> mapTwo = ImmutableMap.of(COLUMN_VISIBILITY, "A&C");
AccessExpressionMarkings cv1 = AccessExpressionMarkings.builder().columnVisibility("A&B").build();
AccessExpressionMarkings cv2 = AccessExpressionMarkings.builder().columnVisibility("A&C").build();
AccessExpressionMarkings expected = AccessExpressionMarkings.builder().columnVisibility("A&B&C").build();
Map<String,String> expected = ImmutableMap.of(COLUMN_VISIBILITY, "A&B&C");
assertEquals(expected, markingFunctions.combine(mapOne, mapTwo));
assertEquals(expected, markingFunctions.combine(List.of(cv1, cv2)));
}
@Test
public void testCombineMapsOfOrs() throws MarkingFunctions.Exception {
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
Map<String,String> mapOne = ImmutableMap.of(COLUMN_VISIBILITY, "A|B");
Map<String,String> mapTwo = ImmutableMap.of(COLUMN_VISIBILITY, "A|C");
AccessExpressionMarkings cv1 = AccessExpressionMarkings.builder().columnVisibility("A|B").build();
AccessExpressionMarkings cv2 = AccessExpressionMarkings.builder().columnVisibility("A|C").build();
AccessExpressionMarkings expected = AccessExpressionMarkings.builder().columnVisibility("(A|B)&(A|C)").build();
Map<String,String> expected = ImmutableMap.of(COLUMN_VISIBILITY, "(A|B)&(A|C)");
assertEquals(expected, markingFunctions.combine(List.of(cv1, cv2)));
}
assertEquals(expected, markingFunctions.combine(mapOne, mapTwo));
@Test
public void testCombineSkipsNullMarkings() throws MarkingFunctions.Exception {
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
AccessExpressionMarkings aem1 = AccessExpressionMarkings.builder().columnVisibility("A&B").build();
AccessExpressionMarkings aem2 = AccessExpressionMarkings.builder().columnVisibility("A&C").build();
AccessExpressionMarkings expected = AccessExpressionMarkings.builder().columnVisibility("A&B&C").build();
Collection<Markings<?>> markings = new ArrayList<>(Arrays.asList(aem1, null, aem2, null));
assertEquals(expected, markingFunctions.combine(markings));
}
@Test
public void testCombineAllNullMarkingsReturnsNull() throws MarkingFunctions.Exception {
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
Collection<Markings<?>> markings = new ArrayList<>(Arrays.asList(null, null));
assertNull(markingFunctions.combine(markings));
}
@Test
public void testCombineVisibilitiesSkipsNullElements() throws MarkingFunctions.Exception {
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
ColumnVisibility vis1 = new ColumnVisibility("A&B");
ColumnVisibility vis2 = new ColumnVisibility("A&C");
Collection<ColumnVisibility> visibilities = new ArrayList<>(Arrays.asList(vis1, null, vis2, null));
ColumnVisibility combined = markingFunctions.combineVisibilities(visibilities);
assertEquals(new ColumnVisibility("A&B&C"), combined);
}
@Test
public void testCombineVisibilitiesAllNullsReturnsEmpty() throws MarkingFunctions.Exception {
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
Collection<ColumnVisibility> visibilities = new ArrayList<>(Arrays.asList(null, null));
assertEquals(new ColumnVisibility(), markingFunctions.combineVisibilities(visibilities));
}
}
@@ -54,7 +54,7 @@ public class FrequencyMetadataAggregator extends WrappingIterator implements Opt
private static final Logger log = Logger.getLogger(FrequencyMetadataAggregator.class);
private static final String NULL_BYTE = "\0";
private static final MarkingFunctions markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
private final MarkingFunctions<?> markingFunctions;
private boolean combineVisibilities;
private String columnsOption;
@@ -82,6 +82,7 @@ public class FrequencyMetadataAggregator extends WrappingIterator implements Opt
cache = new TreeMap<>();
visibilityToDateFrequencies = new HashMap<>();
visibilityToMaxTimestamp = new HashMap<>();
markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
}
@Override
@@ -584,9 +585,8 @@ public class FrequencyMetadataAggregator extends WrappingIterator implements Opt
private ColumnVisibility combineAllVisibilities() {
Set<ColumnVisibility> visibilities = visibilityToDateFrequencies.keySet();
try {
return markingFunctions.combine(visibilities);
return markingFunctions.combineVisibilities(visibilities);
} catch (MarkingFunctions.Exception e) {
log.error("Failed to combine visibilities " + visibilities);
throw new IllegalArgumentException("Failed to combine visibilities " + visibilities, e);
}
}
@@ -127,6 +127,9 @@ public class ModelKeyParser {
}
public static Key createKey(FieldMapping mapping, String modelName) {
if (null == mapping.getColumnVisibility()) {
throw new RuntimeException("ColumnVisibility was null, unable to create Accumulo mutation");
}
ColumnVisibility cv = new ColumnVisibility(mapping.getColumnVisibility());
String dataType = StringUtils.isEmpty(mapping.getDatatype()) ? "" : NULL_BYTE + mapping.getDatatype().trim();
@@ -185,6 +188,9 @@ public class ModelKeyParser {
}
public static Mutation createMutation(FieldMapping mapping, String modelName) {
if (null == mapping.getColumnVisibility()) {
throw new RuntimeException("ColumnVisibility was null, unable to create Accumulo mutation");
}
ColumnVisibility cv = new ColumnVisibility(mapping.getColumnVisibility());
Mutation m;
String dataType = StringUtils.isEmpty(mapping.getDatatype()) ? "" : NULL_BYTE + mapping.getDatatype().trim();
@@ -208,6 +214,9 @@ public class ModelKeyParser {
}
public static Mutation createDeleteMutation(FieldMapping mapping, String modelName) {
if (null == mapping.getColumnVisibility()) {
throw new RuntimeException("ColumnVisibility was null, unable to create Accumulo mutation");
}
ColumnVisibility cv = new ColumnVisibility(mapping.getColumnVisibility());
Mutation m;
String dataType = StringUtils.isEmpty(mapping.getDatatype()) ? "" : NULL_BYTE + mapping.getDatatype().trim();
+1
View File
@@ -10,6 +10,7 @@
|datawave\.test.*|
|gov.nsa.datawave.*)" regex="true" strategyOnMismatch="allowed">
<!-- API packages -->
<allow pkg="org.apache.accumulo.access"/>
<allow pkg="org.apache.accumulo.core.client"/>
<allow pkg="org.apache.accumulo.core.data"/>
<allow pkg="org.apache.accumulo.core.security"/>
@@ -51,12 +51,6 @@
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
<version>${version.datawave}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
@@ -2,16 +2,15 @@ package datawave.webservice.response.objects;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import org.apache.accumulo.access.AccessExpression;
import org.apache.commons.codec.binary.Base64;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import datawave.webservice.query.util.TypedValue;
@XmlAccessorType(XmlAccessType.NONE)
@@ -87,18 +86,14 @@ public class DefaultKey extends KeyBase {
}
@Override
public void setMarkings(Map<String,String> markings) {
HashMap<String,String> markingMap = new HashMap<>();
if (markings != null) {
markingMap.putAll(markings);
}
this.markings = markingMap;
setColumnVisibility(markingMap.getOrDefault(MarkingFunctions.Default.COLUMN_VISIBILITY, ""));
public void setMarkings(Markings<?> markings) {
this.markings = markings;
AccessExpression ae = markings.toAccessExpression();
this.columnVisibility = new TypedValue(ae != null ? ae.getExpression() : "");
}
@Override
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return this.markings;
}
@@ -116,11 +111,8 @@ public class DefaultKey extends KeyBase {
public void setColumnVisibility(String colVis) {
this.columnVisibility = (colVis == null) ? new TypedValue("") : new TypedValue(colVis);
if (markings == null) {
markings = new HashMap<>();
}
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, this.columnVisibility.getValue().toString());
String expr = this.columnVisibility.getValue().toString();
this.markings = AccessExpressionMarkings.builder().columnVisibility(expr).build();
}
public void setTimestamp(long timestamp) {
@@ -1,18 +1,17 @@
package datawave.webservice.response.objects;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlSeeAlso;
import datawave.marking.Markings;
import datawave.webservice.query.result.event.HasMarkings;
@XmlAccessorType(XmlAccessType.NONE)
@XmlSeeAlso(DefaultKey.class)
public abstract class KeyBase implements HasMarkings {
protected Map<String,String> markings;
protected Markings<?> markings;
public abstract String getRow();
@@ -1,17 +1,13 @@
package datawave.webservice.response.objects;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.bind.annotation.XmlTransient;
import datawave.webservice.xml.util.StringMapAdapter;
import datawave.marking.Markings;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
@@ -20,9 +16,8 @@ public class Visibility {
@XmlAttribute(name = "valid")
private Boolean valid;
@XmlElement(name = "markings")
@XmlJavaTypeAdapter(StringMapAdapter.class)
private HashMap<String,String> markings;
@XmlTransient
private Markings<?> markings;
@XmlAttribute(name = "visibility")
private String visibility;
@@ -43,16 +38,12 @@ public class Visibility {
this.visibility = visibility;
}
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return markings;
}
public void setMarkings(Map<String,String> markings) {
if (this.markings == null) {
this.markings = new HashMap<String,String>();
}
this.markings.clear();
this.markings.putAll(markings);
public void setMarkings(Markings<?> markings) {
this.markings = markings;
}
}
@@ -6,9 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -19,6 +17,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import datawave.marking.AccessExpressionMarkings;
import datawave.webservice.query.exception.QueryExceptionType;
import datawave.webservice.response.objects.DefaultKey;
import datawave.webservice.response.objects.Entry;
@@ -39,8 +38,7 @@ public class LookupResponseTest {
lookupResponse = new LookupResponse();
List<Entry> entryList = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "A&B&C" + i);
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().columnVisibility("A&B&C" + i).build();
KeyBase responseKey = new DefaultKey();
responseKey.setRow("row" + i);
responseKey.setColFam("cf" + i);
@@ -69,6 +69,11 @@
<artifactId>base-rest-responses</artifactId>
<version>${version.datawave}</version>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>datawave-core-common-util</artifactId>
<version>${version.datawave}</version>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>type-utils</artifactId>
@@ -229,6 +234,10 @@
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>base-rest-responses</artifactId>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>datawave-core-common-util</artifactId>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>type-utils</artifactId>
@@ -42,6 +42,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.webservice.query.util.OptionallyEncodedString;
import datawave.webservice.request.UpdateRequest;
import datawave.webservice.request.objects.MutationEntry;
@@ -68,11 +69,11 @@ import datawave.webservice.result.VoidResponse;
public class AdminService {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private final MarkingFunctions markingFunctions;
private final MarkingFunctions<?> markingFunctions;
private final AccumuloClient warehouseAccumuloClient;
@Autowired
public AdminService(@Qualifier("warehouse") AccumuloClient warehouseAccumuloClient, MarkingFunctions markingFunctions) {
public AdminService(@Qualifier("warehouse") AccumuloClient warehouseAccumuloClient, MarkingFunctions<?> markingFunctions) {
this.warehouseAccumuloClient = warehouseAccumuloClient;
this.markingFunctions = markingFunctions;
}
@@ -569,7 +570,7 @@ public class AdminService {
vis.setValid(false);
visibilityList.add(vis);
try {
Map<String,String> markings = markingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility(v), authorizations);
Markings<?> markings = markingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility(v), authorizations);
vis.setVisibility(v);
vis.setValid(true);
vis.setMarkings(markings);
@@ -37,7 +37,7 @@ public class AccumuloConfiguration {
@Bean
@ConditionalOnMissingBean
public MarkingFunctions markingFunctions() {
public MarkingFunctions<?> markingFunctions() {
return new MarkingFunctions.Default();
}
@@ -36,6 +36,7 @@ import com.google.common.base.Preconditions;
import datawave.accumulo.util.security.UserAuthFunctions;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.marking.SecurityMarking;
import datawave.microservice.accumulo.lookup.config.LookupAuditProperties;
import datawave.microservice.accumulo.lookup.config.LookupProperties;
@@ -82,7 +83,7 @@ public class LookupService {
}
private final SecurityMarking auditSecurityMarking;
private final MarkingFunctions markingFunctions;
private final MarkingFunctions<?> markingFunctions;
private final AccumuloClient connection;
private final LookupAuditProperties lookupAuditProperties;
private final LookupProperties lookupProperties;
@@ -97,7 +98,7 @@ public class LookupService {
public LookupService(
@Qualifier("auditLookupSecurityMarking")
SecurityMarking auditSecurityMarking,
MarkingFunctions markingFunctions,
MarkingFunctions<?> markingFunctions,
@Qualifier("warehouse")
AccumuloClient connection,
LookupAuditProperties lookupAuditProperties,
@@ -218,12 +219,7 @@ public class LookupService {
continue;
}
//@formatter:off
final Map<String,String> markings = markingFunctions.translateFromColumnVisibilityForAuths(
new ColumnVisibility(k.getColumnVisibility()),
mergedAuths
);
//@formatter:on
final Markings<?> markings = markingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility(k.getColumnVisibility()), mergedAuths);
final KeyBase responseKey = responseObjectFactory.createKey();
responseKey.setRow(currRow);
@@ -31,6 +31,11 @@
<artifactId>guava</artifactId>
<version>${version.guava}</version>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
<version>${version.datawave}</version>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>base-rest-responses</artifactId>
@@ -69,6 +74,10 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>base-rest-responses</artifactId>
@@ -2,17 +2,17 @@ package datawave.webservice.dictionary.data;
import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.xml.bind.annotation.XmlAccessOrder;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorOrder;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import datawave.webservice.query.result.event.MapSchema;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import io.protostuff.Input;
import io.protostuff.Message;
import io.protostuff.Output;
@@ -29,11 +29,12 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
this.description = description;
}
public DefaultDescription(String description, Map<String,String> markings) {
public DefaultDescription(String description, Markings<?> markings) {
this.description = description;
this.markings = markings;
}
@XmlElement(name = "description")
public String getDescription() {
return description;
}
@@ -43,12 +44,14 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
}
@Override
public void setMarkings(Map<String,String> markings) {
this.markings = markings;
@XmlElement(name = "markings", type = AccessExpressionMarkings.class)
public Markings<?> getMarkings() {
return this.markings;
}
public Map<String,String> getMarkings() {
return this.markings;
@Override
public void setMarkings(Markings<?> markings) {
this.markings = markings;
}
@Override
@@ -86,7 +89,7 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
}
@XmlTransient
private static final Schema<DefaultDescription> SCHEMA = new Schema<DefaultDescription>() {
private static final Schema<DefaultDescription> SCHEMA = new Schema<>() {
public DefaultDescription newMessage() {
return new DefaultDescription();
}
@@ -112,7 +115,7 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
output.writeString(1, message.description, false);
}
if (message.markings != null)
output.writeObject(1, message.markings, MapSchema.SCHEMA, false);
output.writeObject(2, (AccessExpressionMarkings) message.markings, AccessExpressionMarkings.SCHEMA, false);
}
public void mergeFrom(Input input, DefaultDescription message) throws IOException {
@@ -123,8 +126,8 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
message.description = input.readString();
break;
case 2:
message.markings = new HashMap<String,String>();
input.mergeObject(message.markings, MapSchema.SCHEMA);
message.markings = AccessExpressionMarkings.builder().build();
input.mergeObject((AccessExpressionMarkings) message.markings, AccessExpressionMarkings.SCHEMA);
break;
default:
input.handleUnknownField(number, this);
@@ -1,25 +1,18 @@
package datawave.webservice.dictionary.data;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import datawave.marking.Markings;
import datawave.webservice.query.result.event.HasMarkings;
import datawave.webservice.xml.util.StringMapAdapter;
import io.protostuff.Message;
@XmlAccessorType(XmlAccessType.NONE)
public abstract class DescriptionBase<T> implements HasMarkings, Message<T> {
@XmlElement(name = "description")
protected String description;
@XmlElement(name = "markings")
@XmlJavaTypeAdapter(StringMapAdapter.class)
protected Map<String,String> markings;
protected Markings<?> markings;
public abstract String getDescription();
@@ -24,6 +24,7 @@ import io.protostuff.Input;
import io.protostuff.Message;
import io.protostuff.Output;
import io.protostuff.Schema;
import lombok.Setter;
@XmlRootElement(name = "EdgeDictionary")
@XmlAccessorType(XmlAccessType.NONE)
@@ -33,6 +34,7 @@ public class DefaultEdgeDictionary extends EdgeDictionaryBase<DefaultEdgeDiction
private static final long serialVersionUID = 1L;
private static final String TITLE = "Edge Dictionary", SEP = ", ";
@Setter
private String edgeDictionarySystem = null;
@XmlElementWrapper(name = "EdgeMetadata")
@@ -64,10 +66,6 @@ public class DefaultEdgeDictionary extends EdgeDictionaryBase<DefaultEdgeDiction
return edgeDictionarySystem == null ? null : edgeDictionarySystem;
}
public void setEdgeDictionarySystem(String edgeDictionarySystem) {
this.edgeDictionarySystem = edgeDictionarySystem;
}
public static Schema<DefaultEdgeDictionary> getSchema() {
return SCHEMA;
}
@@ -227,7 +225,7 @@ public class DefaultEdgeDictionary extends EdgeDictionaryBase<DefaultEdgeDiction
fieldBuilder.append(field).append(SEP);
}
String fieldNames = fieldBuilder.toString().substring(0, fieldBuilder.length() - 2);
String fieldNames = fieldBuilder.substring(0, fieldBuilder.length() - 2);
String date = metadata.getStartDate();
builder.append("<td>").append(type).append("</td>");
@@ -1,14 +1,12 @@
package datawave.webservice.dictionary.edge;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlSeeAlso;
import com.google.common.collect.Maps;
import datawave.marking.Markings;
import datawave.webservice.query.result.event.HasMarkings;
import io.protostuff.Message;
@@ -16,19 +14,13 @@ import io.protostuff.Message;
@XmlSeeAlso(DefaultMetadata.class)
public abstract class MetadataBase<T> implements HasMarkings, Message<T> {
protected transient Map<String,String> markings;
protected transient Markings<?> markings;
public Map<String,String> getMarkings() {
assureMarkings();
public Markings<?> getMarkings() {
return markings;
}
protected void assureMarkings() {
if (this.markings == null)
this.markings = Maps.newHashMap();
}
public void setMarkings(Map<String,String> markings) {
public void setMarkings(Markings<?> markings) {
this.markings = markings;
}
@@ -7,7 +7,6 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.annotation.XmlAccessType;
@@ -21,9 +20,9 @@ import javax.xml.bind.annotation.XmlType;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import datawave.marking.AccessExpressionMarkings;
import datawave.webservice.dictionary.data.DefaultDescription;
import datawave.webservice.dictionary.data.DescriptionBase;
import datawave.webservice.query.result.event.MapSchema;
import io.protostuff.Input;
import io.protostuff.Message;
import io.protostuff.Output;
@@ -73,7 +72,7 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
private String lastUpdated;
public Boolean isIndexOnly() {
return indexOnly == null ? false : indexOnly;
return indexOnly != null && indexOnly;
}
public Boolean isForwardIndexed() {
@@ -137,7 +136,7 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
}
@XmlTransient
private static final Schema<DefaultMetadataField> SCHEMA = new Schema<DefaultMetadataField>() {
private static final Schema<DefaultMetadataField> SCHEMA = new Schema<>() {
private final HashMap<String,Integer> fieldMap = new HashMap<>();
{
fieldMap.put("fieldName", 1);
@@ -250,8 +249,8 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
int size = input.readInt32();
message.descriptions = new HashSet<>(size);
for (int i = 0; i < size; i++) {
Map<String,String> markings = new HashMap<>();
input.mergeObject(markings, MapSchema.SCHEMA);
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().build();
input.mergeObject(markings, AccessExpressionMarkings.SCHEMA);
message.descriptions.add(new DefaultDescription(input.readString(), markings));
}
break;
@@ -295,7 +294,7 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
output.writeInt32(9, message.getDescriptions().size(), false);
for (DescriptionBase desc : message.getDescriptions()) {
output.writeString(9, desc.getDescription(), true);
output.writeObject(9, desc.getMarkings(), MapSchema.SCHEMA, false);
output.writeObject(9, (AccessExpressionMarkings) desc.getMarkings(), AccessExpressionMarkings.SCHEMA, false);
}
output.writeString(10, message.lastUpdated, false);
output.writeBool(11, message.tokenized, false);
@@ -7,10 +7,8 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXBContext;
@@ -21,17 +19,31 @@ import javax.xml.bind.annotation.XmlSchema;
import org.junit.jupiter.api.Test;
import datawave.marking.AccessExpressionMarkings;
public class DefaultDescriptionTest {
@Test
public void testMarshall() throws JAXBException {
JAXBContext j = JAXBContext.newInstance(DefaultFields.class);
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultFields dicFieldsList = getDefaultFields();
Marshaller m = j.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
m.marshal(dicFieldsList, out);
String result = out.toString();
assertTrue(result.contains("<columnVisibility>PRIVATE</columnVisibility>"));
assertTrue(result.contains("<description>my description</description>"));
}
private static DefaultFields getDefaultFields() {
DefaultDescription desc = new DefaultDescription();
desc.setMarkings(markings);
desc.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
desc.setDescription("my description");
Set<DefaultDescription> descs = new HashSet<>();
@@ -47,18 +59,7 @@ public class DefaultDescriptionTest {
DefaultFields dicFieldsList = new DefaultFields();
dicFieldsList.setFields(dicFields);
Marshaller m = j.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
m.marshal(dicFieldsList, out);
String result = out.toString();
assertTrue(result.contains("<key>columnVisibility</key>"));
assertTrue(result.contains("<value>PRIVATE</value>"));
assertTrue(result.contains("<description>my description</description>"));
return dicFieldsList;
}
@Test
@@ -83,10 +84,7 @@ public class DefaultDescriptionTest {
+ " <descriptions>\n"
+ " <description>my description</description>\n"
+ " <markings>\n"
+ " <entry>\n"
+ " <key>columnVisibility</key>\n"
+ " <value>PRIVATE</value>\n"
+ " </entry>\n"
+ " <columnVisibility>PRIVATE</columnVisibility>\n"
+ " </markings>\n"
+ " </descriptions>\n"
+ " <fieldName>myField</fieldName>\n"
@@ -107,9 +105,9 @@ public class DefaultDescriptionTest {
assertEquals("myType", f.getDatatype());
for (DefaultDescription d : f.getDescriptions()) {
assertEquals("my description", d.getDescription());
Map<String,String> m = d.getMarkings();
assertEquals("PRIVATE", m.get("columnVisibility"));
markingCount = m.size();
assertTrue(d.getMarkings() instanceof AccessExpressionMarkings);
AccessExpressionMarkings aem = (AccessExpressionMarkings) d.getMarkings();
assertEquals("PRIVATE", aem.getColumnVisibilityString());
descriptionCount++;
}
fieldCount++;
@@ -117,6 +115,5 @@ public class DefaultDescriptionTest {
assertEquals(1, fieldCount);
assertEquals(1, descriptionCount);
assertEquals(1, markingCount);
}
}
@@ -14,6 +14,8 @@ import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import datawave.microservice.AccumuloConnectionService;
import datawave.microservice.Connection;
import datawave.microservice.authorization.user.DatawaveUserDetails;
@@ -167,8 +169,7 @@ public class DataDictionaryControllerLogic<DESC extends DescriptionBase<DESC>,DI
public VoidResponse setDescriptionPost(String fieldName, String datatype, String description, String modelName, String modelTable, String columnVisibility,
DatawaveUserDetails currentUser) throws Exception {
DESC desc = this.responseObjectFactory.getDescription();
Map<String,String> markings = Maps.newHashMap();
markings.put("columnVisibility", columnVisibility);
Markings<?> markings = AccessExpressionMarkings.builder().columnVisibility(columnVisibility).build();
desc.setMarkings(markings);
desc.setDescription(description);
@@ -281,8 +282,7 @@ public class DataDictionaryControllerLogic<DESC extends DescriptionBase<DESC>,DI
*/
public VoidResponse deleteDescription(String fieldName, String datatype, String modelName, String modelTable, String columnVisibility,
DatawaveUserDetails currentUser) throws Exception {
Map<String,String> markings = Maps.newHashMap();
markings.put("columnVisibility", columnVisibility);
Markings<?> markings = AccessExpressionMarkings.builder().columnVisibility(columnVisibility).build();
DESC desc = this.responseObjectFactory.getDescription();
desc.setDescription("");
desc.setMarkings(markings);
@@ -46,14 +46,14 @@ public class DictionaryServiceConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
public MetadataDescriptionsHelper<DefaultDescription> metadataHelperWithDescriptions(MarkingFunctions markingFunctions,
public MetadataDescriptionsHelper<DefaultDescription> metadataHelperWithDescriptions(MarkingFunctions<?> markingFunctions,
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory) {
return new MetadataDescriptionsHelper<>(markingFunctions, responseObjectFactory);
}
@Bean
@ConditionalOnMissingBean
public DataDictionary datawaveDataDictionary(MarkingFunctions markingFunctions,
public DataDictionary datawaveDataDictionary(MarkingFunctions<?> markingFunctions,
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory,
MetadataHelperFactory metadataHelperFactory, MetadataDescriptionsHelperFactory<DefaultDescription> metadataDescriptionsHelperFactory) {
return new DataDictionaryImpl(markingFunctions, responseObjectFactory, metadataHelperFactory, metadataDescriptionsHelperFactory);
@@ -32,14 +32,14 @@ import datawave.webservice.metadata.DefaultMetadataField;
public class DataDictionaryImpl implements DataDictionary<DefaultMetadataField,DefaultDescription,DefaultDictionaryField> {
private final MarkingFunctions markingFunctions;
private final MarkingFunctions<?> markingFunctions;
private final ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory;
private final MetadataHelperFactory metadataHelperFactory;
private final MetadataDescriptionsHelperFactory<DefaultDescription> metadataDescriptionsHelperFactory;
private Map<String,String> normalizationMap = Maps.newHashMap();
private String dataDictionarySystem = "";
public DataDictionaryImpl(MarkingFunctions markingFunctions,
public DataDictionaryImpl(MarkingFunctions<?> markingFunctions,
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory,
MetadataHelperFactory metadataHelperFactory, MetadataDescriptionsHelperFactory<DefaultDescription> metadataDescriptionsHelperFactory) {
this.markingFunctions = markingFunctions;
@@ -39,13 +39,13 @@ public class DefaultMetadataFieldScanner {
private static final String TIMESTAMP_FORMAT = "yyyyMMddHHmmss";
private static final Value EMPTY_VALUE = new Value();
private final MarkingFunctions markingFunctions;
private final MarkingFunctions<?> markingFunctions;
private final ResponseObjectFactory<DefaultDescription,?,DefaultMetadataField,?,?> responseObjectFactory;
private final Map<String,String> normalizationMap;
private final Connection connectionConfig;
private final int numThreads;
public DefaultMetadataFieldScanner(MarkingFunctions markingFunctions,
public DefaultMetadataFieldScanner(MarkingFunctions<?> markingFunctions,
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory,
Map<String,String> normalizationMap, Connection connectionConfig, int numThreads) {
this.markingFunctions = markingFunctions;
@@ -3,10 +3,8 @@ package datawave.microservice.metadata;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.accumulo.core.client.AccumuloClient;
@@ -34,6 +32,7 @@ import com.google.common.collect.SetMultimap;
import datawave.data.ColumnFamilyConstants;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.microservice.dictionary.config.ResponseObjectFactory;
import datawave.query.util.MetadataEntry;
import datawave.security.util.ScannerHelper;
@@ -48,14 +47,14 @@ import datawave.webservice.dictionary.data.DescriptionBase;
public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
private static final Logger log = LoggerFactory.getLogger(MetadataDescriptionsHelper.class);
private final MarkingFunctions markingFunctions;
private final MarkingFunctions<?> markingFunctions;
private final ResponseObjectFactory<DESC,?,?,?,?> responseObjectFactory;
private String metadataTableName;
private AccumuloClient accumuloClient;
private Set<Authorizations> fullUserAuths;
public MetadataDescriptionsHelper(MarkingFunctions markingFunctions, ResponseObjectFactory<DESC,?,?,?,?> responseObjectFactory) {
public MetadataDescriptionsHelper(MarkingFunctions<?> markingFunctions, ResponseObjectFactory<DESC,?,?,?,?> responseObjectFactory) {
this.markingFunctions = markingFunctions;
this.responseObjectFactory = responseObjectFactory;
}
@@ -85,8 +84,7 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
return descs;
}
public SetMultimap<String,DESC> getFieldDescriptions(Set<String> ingestTypeFilter)
throws TableNotFoundException, ExecutionException, MarkingFunctions.Exception {
public SetMultimap<String,DESC> getFieldDescriptions(Set<String> ingestTypeFilter) throws TableNotFoundException, MarkingFunctions.Exception {
SetMultimap<MetadataEntry,DESC> descriptions = getDescriptions(ingestTypeFilter);
SetMultimap<String,DESC> fieldDescriptions = HashMultimap.create();
@@ -118,16 +116,21 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
setDescriptions(entry, Collections.singleton(desc));
}
public void setDescriptions(MetadataEntry entry, Set<? extends DescriptionBase> descs)
throws TableNotFoundException, MutationsRejectedException, MarkingFunctions.Exception {
public void setDescriptions(MetadataEntry entry, Set<? extends DescriptionBase> descs) throws TableNotFoundException, MutationsRejectedException {
BatchWriter bw = null;
try {
BatchWriterConfig bwConfig = new BatchWriterConfig().setMaxMemory(10000L).setMaxLatency(100L, TimeUnit.MILLISECONDS).setMaxWriteThreads(1);
bw = accumuloClient.createBatchWriter(metadataTableName, bwConfig);
Mutation m = new Mutation(entry.getFieldName());
for (DescriptionBase desc : descs) {
m.put(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), markingFunctions.translateToColumnVisibility(desc.getMarkings()),
new Value(desc.getDescription().getBytes(UTF_8)));
ColumnVisibility cv = null;
if (desc.getMarkings() != null) {
cv = desc.getMarkings().toColumnVisibility();
}
if (null == cv || cv.getExpression().length == 0) {
throw new IllegalArgumentException("ColumnVisibility was null or empty, unable to create Accumulo mutation");
}
m.put(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), cv, new Value(desc.getDescription().getBytes(UTF_8)));
}
bw.addMutation(m);
} finally {
@@ -153,14 +156,20 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
* @throws MutationsRejectedException
* if writing the update to Accumulo fails
*/
public void removeDescription(MetadataEntry entry, DescriptionBase desc)
throws TableNotFoundException, MutationsRejectedException, MarkingFunctions.Exception {
public void removeDescription(MetadataEntry entry, DescriptionBase desc) throws TableNotFoundException, MutationsRejectedException {
BatchWriter bw = null;
try {
BatchWriterConfig bwConfig = new BatchWriterConfig().setMaxMemory(10000L).setMaxLatency(100L, TimeUnit.MILLISECONDS).setMaxWriteThreads(1);
bw = accumuloClient.createBatchWriter(metadataTableName, bwConfig);
Mutation m = new Mutation(entry.getFieldName());
m.putDelete(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), this.markingFunctions.translateToColumnVisibility(desc.getMarkings()));
ColumnVisibility cv = null;
if (desc.getMarkings() != null) {
cv = desc.getMarkings().toColumnVisibility();
}
if (null == cv || cv.getExpression().length == 0) {
throw new IllegalArgumentException("ColumnVisibility was null or empty, unable to create Accumulo mutation");
}
m.putDelete(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), cv);
bw.addMutation(m);
} finally {
if (null != bw) {
@@ -199,11 +208,7 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
}
private Map<String,String> getMarkings(Key k) throws MarkingFunctions.Exception {
return getMarkings(k.getColumnVisibilityParsed());
}
private Map<String,String> getMarkings(ColumnVisibility visibility) throws MarkingFunctions.Exception {
return markingFunctions.translateFromColumnVisibility(visibility);
private Markings<?> getMarkings(Key k) throws MarkingFunctions.Exception {
return markingFunctions.translateFromColumnVisibility(k.getColumnVisibilityParsed());
}
}
@@ -2,8 +2,6 @@ package datawave.microservice.dictionary;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import org.apache.accumulo.core.client.AccumuloClient;
@@ -32,7 +30,7 @@ import com.google.common.collect.Multimap;
import datawave.accumulo.inmemory.InMemoryAccumuloClient;
import datawave.accumulo.inmemory.InMemoryInstance;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.microservice.ControllerIT;
import datawave.microservice.dictionary.config.DataDictionaryProperties;
import datawave.webservice.dictionary.data.DefaultDataDictionary;
@@ -129,11 +127,9 @@ public class DataDictionaryControllerTest extends ControllerIT {
.build();
// @formatter:on
HashMap<String,String> markings = new HashMap<>();
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "USER|ADMIN");
Multimap<Map.Entry<String,String>,DefaultDescription> descriptions = HashMultimap.create();
descriptions.put(new AbstractMap.SimpleEntry<>("fooField", "fooType"), new DefaultDescription("my foo field", markings));
descriptions.put(new AbstractMap.SimpleEntry<>("barField", "barType"), new DefaultDescription("my bar field", markings));
descriptions.put(Map.entry("fooField", "fooType"), new DefaultDescription("my foo field", AccessExpressionMarkings.create("USER")));
descriptions.put(Map.entry("barField", "barType"), new DefaultDescription("my bar field", AccessExpressionMarkings.create("ADMIN")));
DefaultFields postBody = new DefaultFields(descriptions);
MultiValueMap<String,String> additionalHeaders = new LinkedMultiValueMap<>();
additionalHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
@@ -28,6 +28,7 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.MarkingFunctions;
import datawave.microservice.Connection;
import datawave.microservice.dictionary.config.ResponseObjectFactory;
@@ -59,7 +60,7 @@ public class DataDictionaryImplTest {
private AccumuloClient accumuloClient;
@Mock
private MarkingFunctions markingFunctions;
private MarkingFunctions<?> markingFunctions;
@Mock
private ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory;
@@ -88,11 +89,8 @@ public class DataDictionaryImplTest {
@Test
public void whenSettingDescription_givenSingleDefaultDescription_shouldSetDescription() throws Exception {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultDescription description = new DefaultDescription();
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
description.setDescription("my ultra cool description");
// Ensure no alias will be found.
@@ -110,11 +108,8 @@ public class DataDictionaryImplTest {
@Test
public void whenSettingDescription_givenDefaultDictionaryField_shouldSetDescriptionFromProperties() throws Exception {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultDescription description = new DefaultDescription();
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
description.setDescription("my ultra cool description");
Set<DefaultDescription> descriptions = Collections.singleton(description);
@@ -138,11 +133,8 @@ public class DataDictionaryImplTest {
@Test
public void whenSettingDescription_givenNoAlias_shouldSetDescriptionWithOriginalFieldName() throws Exception {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultDescription description = new DefaultDescription();
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
description.setDescription("my ultra cool description");
Set<DefaultDescription> descriptions = Collections.singleton(description);
@@ -161,11 +153,8 @@ public class DataDictionaryImplTest {
@Test
public void whenSettingDescription_givenAlias_shouldSetDescriptionWithAlias() throws Exception {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultDescription description = new DefaultDescription();
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
description.setDescription("my ultra cool description");
Set<DefaultDescription> descriptions = Collections.singleton(description);
@@ -294,11 +283,8 @@ public class DataDictionaryImplTest {
@Test
public void whenDeletingDescription_givenNoAlias_shouldDeleteDescriptionWithOriginalFieldName() throws Exception {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultDescription description = new DefaultDescription();
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
description.setDescription("my ultra cool description");
// Ensure no alias will be found.
@@ -315,11 +301,8 @@ public class DataDictionaryImplTest {
@Test
public void whenDeletingDescription_givenAlias_shouldDeleteDescriptionWithAlias() throws Exception {
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE");
DefaultDescription description = new DefaultDescription();
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
description.setDescription("my ultra cool description");
// Ensure an alias will be found.
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
import datawave.accumulo.inmemory.InMemoryAccumuloClient;
import datawave.accumulo.inmemory.InMemoryInstance;
import datawave.data.ColumnFamilyConstants;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.MarkingFunctions;
import datawave.microservice.Connection;
import datawave.microservice.dictionary.config.ResponseObjectFactory;
@@ -50,7 +51,7 @@ public class DefaultMetadataFieldScannerTest {
private static final String[] AUTH = {"PRIVATE"};
private static final Set<Authorizations> AUTHS = Collections.singleton(new Authorizations(AUTH));
private static final ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> RESPONSE_OBJECT_FACTORY = new ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields>() {
private static final ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> RESPONSE_OBJECT_FACTORY = new ResponseObjectFactory<>() {
@Override
public DefaultDataDictionary getDataDictionary() {
return null;
@@ -276,11 +277,7 @@ public class DefaultMetadataFieldScannerTest {
private DefaultDescription createDescription(String descriptionText) {
DefaultDescription description = new DefaultDescription();
description.setDescription(descriptionText);
Map<String,String> markings = new HashMap<>();
markings.put("columnVisibility", "PRIVATE}");
description.setMarkings(markings);
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
return description;
}
}
@@ -63,12 +63,6 @@
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
<version>${version.datawave}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.accumulo.access.AccessExpression;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
@@ -34,7 +35,8 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonIgnore;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import datawave.microservice.query.Query;
import datawave.microservice.query.QueryImpl.Parameter;
import datawave.webservice.query.exception.QueryException;
@@ -1165,21 +1167,21 @@ public abstract class BaseQueryMetric implements HasMarkings, Serializable {
}
@Override
public void setMarkings(Map<String,String> markings) {
public void setMarkings(Markings<?> markings) {
if (markings == null || markings.isEmpty()) {
this.columnVisibility = null;
} else {
this.columnVisibility = markings.get(MarkingFunctions.Default.COLUMN_VISIBILITY);
AccessExpression ae = markings.toAccessExpression();
this.columnVisibility = ae.getExpression();
}
}
@Override
public Map<String,String> getMarkings() {
Map<String,String> markings = new HashMap<>();
public Markings<?> getMarkings() {
if (this.columnVisibility != null) {
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, this.columnVisibility);
return AccessExpressionMarkings.builder().columnVisibility(this.columnVisibility).build();
}
return markings;
return null;
}
public Schema<? extends BaseQueryMetric> getSchemaInstance() {
@@ -14,9 +14,7 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
@@ -28,7 +26,7 @@ import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.microservice.querymetric.BaseQueryMetric.Lifecycle;
import datawave.microservice.querymetric.BaseQueryMetric.PageMetric;
import datawave.microservice.querymetric.BaseQueryMetric.Prediction;
@@ -43,7 +41,6 @@ import io.protostuff.Schema;
public class QueryMetricTest {
private static QueryMetric queryMetric = null;
private static Map<String,String> markings = null;
private static List<String> negativeSelectors = null;
private static ArrayList<PageMetric> pageTimes = null;
private static List<String> positiveSelectors = null;
@@ -53,9 +50,7 @@ public class QueryMetricTest {
@BeforeAll
public static void setup() {
queryMetric = new QueryMetric();
markings = new HashMap<>();
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "PUBLIC");
queryMetric.setMarkings(markings);
queryMetric.setMarkings(AccessExpressionMarkings.builder().columnVisibility("PUBLIC").build());
negativeSelectors = new ArrayList<>();
negativeSelectors.add("negativeSelector1");
positiveSelectors = new ArrayList<>();
@@ -104,7 +99,7 @@ public class QueryMetricTest {
queryMetric.setHost("host");
queryMetric.setLastUpdated(d);
queryMetric.setLifecycle(Lifecycle.INITIALIZED);
queryMetric.setMarkings(markings);
queryMetric.setMarkings(AccessExpressionMarkings.builder().columnVisibility("PUBLIC").build());
queryMetric.setNegativeSelectors(negativeSelectors);
queryMetric.setNumUpdates(0);
queryMetric.setPageTimes(pageTimes);
@@ -131,7 +126,7 @@ public class QueryMetricTest {
assertEquals("host", queryMetric.getHost());
assertEquals(d, queryMetric.getLastUpdated());
assertEquals(Lifecycle.INITIALIZED, queryMetric.getLifecycle());
assertEquals("PUBLIC", queryMetric.getMarkings().get(MarkingFunctions.Default.COLUMN_VISIBILITY));
assertEquals("PUBLIC", queryMetric.getColumnVisibility());
assertEquals("negativeSelector1", queryMetric.getNegativeSelectors().get(0));
assertEquals(1, queryMetric.getNumPages());
assertEquals(0, queryMetric.getNumResults());
@@ -234,7 +229,7 @@ public class QueryMetricTest {
qm.setHost("host");
qm.setLastUpdated(d);
qm.setLifecycle(BaseQueryMetric.Lifecycle.INITIALIZED);
qm.setMarkings(markings);
qm.setMarkings(AccessExpressionMarkings.builder().columnVisibility("PUBLIC").build());
qm.setNegativeSelectors(negativeSelectors);
qm.setNumUpdates(0);
qm.setPageTimes(pageTimes);
@@ -135,12 +135,6 @@
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
<version>${version.datawave}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
@@ -87,7 +87,7 @@ public class QueryMetricOperations {
private QueryGeometryHandler geometryHandler;
private CacheManager cacheManager;
private Cache incomingQueryMetricsCache;
private MarkingFunctions markingFunctions;
private MarkingFunctions<?> markingFunctions;
private QueryMetricResponseFactory queryMetricResponseFactory;
private MergeLockLifecycleListener mergeLock;
private Correlator correlator;
@@ -141,7 +141,7 @@ public class QueryMetricOperations {
*/
@Autowired
public QueryMetricOperations(@Qualifier("queryMetricCacheManager") CacheManager cacheManager, ShardTableQueryMetricHandler handler,
QueryGeometryHandler geometryHandler, MarkingFunctions markingFunctions, QueryMetricResponseFactory queryMetricResponseFactory,
QueryGeometryHandler geometryHandler, MarkingFunctions<?> markingFunctions, QueryMetricResponseFactory queryMetricResponseFactory,
MergeLockLifecycleListener mergeLock, Correlator correlator, MetricUpdateEntryProcessorFactory entryProcessorFactory,
QueryMetricOperationsStats stats, QueryMetricClient queryMetricClient, DnUtils dnUtils) {
this.handler = handler;
@@ -478,11 +478,14 @@ public class QueryMetricOperations {
private boolean canViewMetric(DatawaveUserDetails currentUser, BaseQueryMetric metric) throws Exception {
boolean userCanViewMetric = true;
ColumnVisibility columnVisibility = this.markingFunctions.translateToColumnVisibility(metric.getMarkings());
ColumnVisibility columnVisibility = null;
if (null != metric.getMarkings()) {
columnVisibility = metric.getMarkings().toColumnVisibility();
}
for (DatawaveUser user : currentUser.getProxiedUsers()) {
Authorizations authorizations = new Authorizations(user.getAuths().toArray(new String[0]));
VisibilityEvaluator visibilityEvaluator = new VisibilityEvaluator(authorizations);
if (visibilityEvaluator.evaluate(columnVisibility) == false) {
if (!visibilityEvaluator.evaluate(columnVisibility)) {
userCanViewMetric = false;
break;
}
@@ -99,7 +99,7 @@ public class QueryMetricHandlerConfiguration {
@ConditionalOnMissingBean
public ShardTableQueryMetricHandler shardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties,
AccumuloConnectionFactory connectionFactory, QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory,
MarkingFunctions markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
MarkingFunctions<?> markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
ResponseObjectFactory responseObjectFactory, WebClient.Builder webClientBuilder,
@Autowired(required = false) JWTTokenHandler jwtTokenHandler, DnUtils dnUtils, QueryMetricResponseFactory queryMetricResponseFactory) {
ShardTableQueryMetricHandler handler;
@@ -16,14 +16,14 @@ import datawave.webservice.query.result.event.ResponseObjectFactory;
@Component
public class QueryMetricQueryLogicFactory implements FactoryBean<ShardQueryLogic> {
private MarkingFunctions markingFunctions;
private MarkingFunctions<?> markingFunctions;
private ResponseObjectFactory responseObjectFactory;
private QueryMetricHandlerProperties queryMetricHandlerProperties;
private DateIndexHelperFactory dateIndexHelperFactory;
private MetadataHelperFactory metadataHelperFactory;
@Autowired
public QueryMetricQueryLogicFactory(MarkingFunctions markingFunctions, ResponseObjectFactory responseObjectFactory,
public QueryMetricQueryLogicFactory(MarkingFunctions<?> markingFunctions, ResponseObjectFactory responseObjectFactory,
DateIndexHelperFactory dateIndexHelperFactory, MetadataHelperFactory metadataHelperFactory,
QueryMetricHandlerProperties queryMetricHandlerProperties) {
this.markingFunctions = markingFunctions;
@@ -48,7 +48,7 @@ public class LocalShardTableQueryMetricHandler<T extends BaseQueryMetric> extend
protected ExecutorService executorService;
public LocalShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, DnUtils dnUtils) {
super(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions, queryMetricCombiner, luceneToJexlQueryParser,
dnUtils);
@@ -39,7 +39,7 @@ public class RemoteShardTableQueryMetricHandler<T extends BaseQueryMetric> exten
private final JWTTokenHandler jwtTokenHandler;
public RemoteShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, ResponseObjectFactory responseObjectFactory,
WebClient.Builder webClientBuilder, JWTTokenHandler jwtTokenHandler, DnUtils dnUtils) {
super(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions, queryMetricCombiner, luceneToJexlQueryParser,
@@ -63,6 +63,7 @@ import datawave.ingest.mapreduce.job.BulkIngestKey;
import datawave.ingest.protobuf.Uid;
import datawave.ingest.table.config.TableConfigHelper;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.microservice.authorization.user.DatawaveUserDetails;
import datawave.microservice.query.Query;
import datawave.microservice.query.QueryImpl;
@@ -106,13 +107,13 @@ public abstract class ShardTableQueryMetricHandler<T extends BaseQueryMetric> ex
protected QueryMetricFactory metricFactory;
protected UIDBuilder<UID> uidBuilder = UID.builder();
protected QueryMetricCombiner queryMetricCombiner;
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
protected DnUtils dnUtils;
// this lock is necessary for when there is an error condition and the accumuloRecordWriter needs to be replaced
protected ReentrantReadWriteLock accumuloRecordWriterLock = new ReentrantReadWriteLock();
public ShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, DnUtils dnUtils) {
super(luceneToJexlQueryParser);
this.queryMetricHandlerProperties = queryMetricHandlerProperties;
@@ -365,14 +366,9 @@ public abstract class ShardTableQueryMetricHandler<T extends BaseQueryMetric> ex
event.setDataType(type);
event.setTimestamp(updatedQueryMetric.getCreateDate().getTime());
// get markings from metric, otherwise use the default markings
Map<String,String> markings = updatedQueryMetric.getMarkings();
Markings<?> markings = updatedQueryMetric.getMarkings();
if (markings != null && !markings.isEmpty()) {
try {
event.setVisibility(this.markingFunctions.translateToColumnVisibility(updatedQueryMetric.getMarkings()));
} catch (MarkingFunctions.Exception e) {
log.error(e.getMessage(), e);
event.setVisibility(this.queryMetricHandlerProperties.getDefaultMetricVisibility());
}
event.setVisibility(markings.toColumnVisibility());
} else {
event.setVisibility(this.queryMetricHandlerProperties.getDefaultMetricVisibility());
}
@@ -11,8 +11,8 @@ import java.util.TreeSet;
import java.util.stream.Collectors;
import org.apache.accumulo.core.security.Authorizations;
import org.junit.Assert;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -79,6 +79,7 @@ public class MetadataCachingTest extends QueryMetricTestBase {
metadataHelper.getDatatypes(Collections.singleton("querymetrics"));
metadataHelper.getFieldsForDatatype(LcNoDiacriticsType.class);
metadataHelper.getFieldsToDatatypes(Collections.singleton("querymetrics"));
metadataHelper.getHiddenFields(Collections.singleton("querymetrics"));
metadataHelper.getContentFields(Collections.singleton("querymetrics"));
metadataHelper.getHiddenFields(Collections.singleton("querymetrics"));
metadataHelper.getExpansionFields(Collections.singleton("querymetrics"));
@@ -111,7 +112,7 @@ public class MetadataCachingTest extends QueryMetricTestBase {
expectedCacheNames.addAll(getCacheNamesForCacheableMethods(AllFieldMetadataHelper.class));
expectedCacheNames.addAll(getCacheNamesForCacheableMethods(DateIndexHelper.class));
Assert.assertEquals(expectedCacheNames, cacheNames);
Assertions.assertEquals(expectedCacheNames, cacheNames);
}
private List<String> getCacheNamesForCacheableMethods(Class clazz) {
@@ -23,7 +23,7 @@ import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import datawave.marking.MarkingFunctions;
import datawave.marking.ColumnVisibilitySecurityMarking;
import datawave.microservice.querymetric.config.QueryMetricTransportType;
import datawave.microservice.querymetric.config.TimelyProperties;
import datawave.microservice.querymetric.function.QueryMetricSupplier;
@@ -53,7 +53,7 @@ public class NonWebApplicationMessagingTest {
@BeforeEach
public void setup() {
this.metricMarkings = new HashMap<>();
this.metricMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "A&C");
this.metricMarkings.put(ColumnVisibilitySecurityMarking.VISIBILITY_MARKING, "A&C");
this.storedMetricUpdates.clear();
}
@@ -1,5 +1,6 @@
package datawave.microservice.querymetric;
import static datawave.marking.AccessExpressionMarkings.ACCESS;
import static datawave.microservice.querymetric.config.HazelcastMetricCacheConfiguration.INCOMING_METRICS;
import static datawave.security.authorization.DatawaveUser.UserType.USER;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -12,13 +13,13 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.client.AccumuloClient;
import org.apache.accumulo.core.client.BatchScanner;
import org.apache.accumulo.core.client.BatchWriter;
@@ -65,7 +66,8 @@ import com.hazelcast.spring.cache.HazelcastCacheManager;
import datawave.core.common.connection.AccumuloConnectionFactory;
import datawave.ingest.protobuf.Uid;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import datawave.microservice.authorization.preauth.ProxiedEntityX509Filter;
import datawave.microservice.authorization.user.DatawaveUserDetails;
import datawave.microservice.querymetric.config.QueryMetricClientProperties;
@@ -144,14 +146,14 @@ public class QueryMetricTestBase {
protected DatawaveUserDetails nonAdminUser;
protected static boolean isHazelCast;
protected static CacheManager staticCacheManager;
protected static Map<String,String> metricMarkings;
protected static Markings<?> metricMarkings;
protected List<String> tables;
protected Collection<String> auths;
protected AccumuloClient accumuloClient;
static {
metricMarkings = new HashMap<>();
metricMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "A&C");
AccessExpression ae = ACCESS.newExpression("A&C");
metricMarkings = AccessExpressionMarkings.builder().accessExpression(ae).build();
}
@AfterAll
@@ -48,7 +48,7 @@ public class AlternateQueryMetricConfiguration {
@Bean
public ShardTableQueryMetricHandler shardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties,
AccumuloConnectionFactory connectionFactory, QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory,
MarkingFunctions markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
MarkingFunctions<?> markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
DnUtils dnUtils) {
return new AlternateShardTableQueryMetricHandler(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions,
queryMetricCombiner, luceneToJexlQueryParser, dnUtils);
@@ -18,7 +18,7 @@ import datawave.webservice.query.result.event.FieldBase;
public class AlternateShardTableQueryMetricHandler extends LocalShardTableQueryMetricHandler<AlternateQueryMetric> {
public AlternateShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, DnUtils dnUtils) {
super(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions, queryMetricCombiner, luceneToJexlQueryParser,
dnUtils);
@@ -75,6 +75,11 @@
<artifactId>datawave-query-core</artifactId>
<version>${version.datawave}</version>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
<version>${version.datawave}</version>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>base-rest-responses</artifactId>
@@ -367,6 +372,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>base-rest-responses</artifactId>
@@ -165,7 +165,7 @@ public class AuditClient {
params.set(AuditParameters.QUERY_AUDIT_TYPE, b.auditType.name());
}
if (null != b.marking) {
params.set(AuditParameters.QUERY_SECURITY_MARKING_COLVIZ, b.marking.toColumnVisibilityString());
params.set(AuditParameters.QUERY_SECURITY_MARKING_COLVIZ, b.marking.toAccessExpressionString());
}
if (null != b.queryLogic) {
params.set(AuditParameters.QUERY_LOGIC_CLASS, b.queryLogic);
-6
View File
@@ -90,12 +90,6 @@
<groupId>gov.nsa.datawave.core</groupId>
<artifactId>accumulo-utils</artifactId>
<version>${version.datawave}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gov.nsa.datawave.core</groupId>
@@ -24,7 +24,7 @@ public class MarkingConfig {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "datawave.defaults.MarkingFunctions.enabled", havingValue = "true", matchIfMissing = true)
public MarkingFunctions markingFunctions() {
public MarkingFunctions<?> markingFunctions() {
return new MarkingFunctions.Default();
}
+7
View File
@@ -124,6 +124,7 @@
<version.kryo>2.20</version.kryo>
<version.kryonet>2.20</version.kryonet>
<version.log4j>2.25.4</version.log4j>
<version.lombok>1.18.36</version.lombok>
<version.lucene>7.5.0</version.lucene>
<version.metrics-cdi>1.6.0</version.metrics-cdi>
<version.minlog>1.2</version.minlog>
@@ -1375,6 +1376,12 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${version.lombok}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-security</artifactId>
@@ -21,13 +21,13 @@ public class MarkingFunctionsFactory {
@Inject
@SpringBean(refreshable = true)
private static MarkingFunctions applicationMarkingFunctions;
private static MarkingFunctions<?> applicationMarkingFunctions;
public static final Logger log = LoggerFactory.getLogger(MarkingFunctionsFactory.class);
private static MarkingFunctions markingFunctions;
private static MarkingFunctions<?> markingFunctions;
public static synchronized MarkingFunctions createMarkingFunctions() {
public static synchronized MarkingFunctions<?> createMarkingFunctions() {
if (markingFunctions != null)
return markingFunctions;
@@ -15,8 +15,8 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.hadoop.conf.Configurable;
@@ -36,7 +36,8 @@ import datawave.ingest.data.TypeRegistry;
import datawave.ingest.data.config.ConfigurationHelper;
import datawave.ingest.data.config.ingest.IgnorableErrorHelperInterface;
import datawave.ingest.protobuf.RawRecordContainer.Data;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import datawave.util.CompositeTimestamp;
public class RawRecordContainerImpl implements Writable, Configurable, RawRecordContainer {
@@ -81,56 +82,41 @@ public class RawRecordContainerImpl implements Writable, Configurable, RawRecord
private Map<String,String> auxMap = null;
// RawRecordContainer support
Map<String,String> securityMarkings = null;
Markings<?> securityMarkings = null;
public RawRecordContainerImpl() {
uidBuilder = UID.builder();
}
@Override
public Map<String,String> getSecurityMarkings() {
public Markings<?> getSecurityMarkings() {
return this.securityMarkings;
}
@Override
public void setSecurityMarkings(Map<String,String> securityMarkings) {
this.securityMarkings = (securityMarkings == null ? null : new HashMap<>(securityMarkings));
public void setSecurityMarkings(Markings<?> securityMarkings) {
this.securityMarkings = securityMarkings;
syncSecurityMarkingsToFields();
}
@Override
public void addSecurityMarking(String domain, String marking) {
if (null == securityMarkings) {
securityMarkings = new HashMap<>();
}
securityMarkings.put(domain, marking);
syncSecurityMarkingsToFields();
}
@Override
public boolean hasSecurityMarking(String domain, String marking) {
return null != securityMarkings && securityMarkings.containsKey(domain) && StringUtils.equals(securityMarkings.get(domain), marking);
}
protected void syncSecurityMarkingsToFields() {
if (securityMarkings != null) {
setVisibility(securityMarkings.get(MarkingFunctions.Default.COLUMN_VISIBILITY));
AccessExpression ae = securityMarkings.toAccessExpression();
if (ae != null) {
setVisibilityNoSync(ae.getExpression());
} else {
setVisibilityNoSync(null);
}
} else {
setVisibility((String) null);
setVisibilityNoSync(null);
}
}
protected void syncFieldsToSecurityMarkings() {
if (visibility != null) {
if (securityMarkings == null) {
securityMarkings = new HashMap<>();
}
securityMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, new String(visibility.getExpression()));
} else if (securityMarkings != null) {
securityMarkings.remove(MarkingFunctions.Default.COLUMN_VISIBILITY);
}
if (securityMarkings != null && securityMarkings.isEmpty()) {
String expr = new String(visibility.getExpression());
securityMarkings = AccessExpressionMarkings.builder().columnVisibility(expr).build();
} else {
securityMarkings = null;
}
}
@@ -4,11 +4,11 @@ import java.io.DataOutput;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import org.apache.accumulo.core.security.ColumnVisibility;
import datawave.data.hash.UID;
import datawave.marking.Markings;
import datawave.util.CompositeTimestamp;
/**
@@ -17,13 +17,9 @@ import datawave.util.CompositeTimestamp;
*/
public interface RawRecordContainer {
Map<String,String> getSecurityMarkings();
Markings<?> getSecurityMarkings();
void setSecurityMarkings(Map<String,String> securityMarkings);
void addSecurityMarking(String domain, String marking);
boolean hasSecurityMarking(String domain, String marking);
void setSecurityMarkings(Markings<?> securityMarkings);
UID getId();
@@ -1,11 +1,10 @@
package datawave.ingest.data.config;
import java.util.Map;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import datawave.data.type.Type;
import datawave.marking.Markings;
/**
* Base container class implementation of the NormalizedContentInterface. This class is utilized to retain the original and transformed content and labels for a
@@ -22,7 +21,7 @@ public class BaseNormalizedContent implements NormalizedContentInterface, Clonea
protected String _indexedFieldValue = null;
/** The security markings for the field value pair. */
protected Map<String,String> _markings = null;
protected Markings<?> _markings = null;
/** The field processing error if any. */
protected Throwable error = null;
@@ -40,7 +39,7 @@ public class BaseNormalizedContent implements NormalizedContentInterface, Clonea
_indexedFieldValue = value;
}
public BaseNormalizedContent(String field, String value, Map<String,String> markings) {
public BaseNormalizedContent(String field, String value, Markings<?> markings) {
this(field, value);
_markings = markings;
}
@@ -117,12 +116,12 @@ public class BaseNormalizedContent implements NormalizedContentInterface, Clonea
}
@Override
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return _markings;
}
@Override
public void setMarkings(Map<String,String> markings) {
public void setMarkings(Markings<?> markings) {
hashCode = null;
this._markings = markings;
}
@@ -8,7 +8,8 @@ import org.apache.hadoop.conf.Configuration;
import datawave.ingest.data.Type;
import datawave.ingest.data.config.ingest.BaseIngestHelper;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
public interface MarkingsHelper {
@@ -28,7 +29,7 @@ public interface MarkingsHelper {
*
* @return markings
*/
Map<String,String> getDefaultMarkings();
Markings<?> getDefaultMarkings();
/**
* Returns the markings override for the field
@@ -37,7 +38,7 @@ public interface MarkingsHelper {
* the field name
* @return markings
*/
Map<String,String> getFieldMarking(String fieldName);
Markings<?> getFieldMarking(String fieldName);
/**
* Method to set the markings on a field
@@ -48,12 +49,12 @@ public interface MarkingsHelper {
void markField(NormalizedContentInterface field);
/**
* No-op helper for default ColumnVisibility implementation. Should only be used for testing purposes.
* No-op helper for default AccessExpression implementation. Should only be used for testing purposes.
*/
class NoOp implements MarkingsHelper {
private Map<String,Map<String,String>> fieldMarkingMap = new HashMap<>();
private Map<String,String> defaultMarkings = null;
private Map<String,Markings<?>> fieldMarkingMap = new HashMap<>();
private Markings<?> defaultMarkings = null;
Configuration conf;
Type dataType;
@@ -67,15 +68,13 @@ public interface MarkingsHelper {
private void initDefaultMarkings() {
String marking = conf.get(dataType.typeName() + DEFAULT_MARKING);
if (null != marking) {
defaultMarkings = new HashMap<>();
defaultMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, marking);
defaultMarkings = AccessExpressionMarkings.builder().columnVisibility(marking).build();
}
for (Entry<String,String> property : conf) {
if (property.getKey().startsWith(dataType.typeName()) && property.getKey().endsWith(FIELD_MARKING)) {
String fieldName = null;
if (null != (fieldName = BaseIngestHelper.getFieldName(dataType, property.getKey(), FIELD_MARKING))) {
Map<String,String> fieldMarking = new HashMap<>();
fieldMarking.put(MarkingFunctions.Default.COLUMN_VISIBILITY, property.getValue());
Markings<?> fieldMarking = AccessExpressionMarkings.builder().columnVisibility(property.getValue()).build();
fieldMarkingMap.put(fieldName, fieldMarking);
}
}
@@ -83,12 +82,12 @@ public interface MarkingsHelper {
}
@Override
public Map<String,String> getDefaultMarkings() {
public Markings<?> getDefaultMarkings() {
return defaultMarkings;
}
@Override
public Map<String,String> getFieldMarking(String fieldName) {
public Markings<?> getFieldMarking(String fieldName) {
return fieldMarkingMap.get(fieldName);
}
@@ -1,8 +1,7 @@
package datawave.ingest.data.config;
import java.util.Map;
import datawave.data.type.Type;
import datawave.marking.Markings;
/**
* Interface utilized to reference the original and transformed content and labels for a value pair ingested into accumulo.
@@ -66,7 +65,7 @@ public interface NormalizedContentInterface extends Cloneable {
* @param markings
* the markings to set
*/
void setMarkings(Map<String,String> markings);
void setMarkings(Markings<?> markings);
/**
* When we fail to process a field (e.g. normalize), then an error can be set which in the EventMapper results in the event being dropped from normal
@@ -82,7 +81,7 @@ public interface NormalizedContentInterface extends Cloneable {
*
* @return The field specific markings, or null if the overall event markings are to be used.
*/
Map<String,String> getMarkings();
Markings<?> getMarkings();
/**
* Get the processing error for this field if any.
@@ -6,7 +6,6 @@ package datawave.ingest.data.config;
* will be used.
*/
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
@@ -15,6 +14,7 @@ import org.apache.hadoop.io.Text;
import datawave.ingest.config.IngestConfiguration;
import datawave.ingest.config.IngestConfigurationFactory;
import datawave.ingest.config.MimeDecoder;
import datawave.marking.Markings;
public class NormalizedFieldAndValue extends BaseNormalizedContent implements GroupedNormalizedContentInterface {
private boolean grouped = false;
@@ -42,7 +42,7 @@ public class NormalizedFieldAndValue extends BaseNormalizedContent implements Gr
super(field, value);
}
public NormalizedFieldAndValue(String field, String value, Map<String,String> markings) {
public NormalizedFieldAndValue(String field, String value, Markings<?> markings) {
super(field, value, markings);
}
@@ -30,6 +30,7 @@ import datawave.ingest.data.config.GroupedNormalizedContentInterface;
import datawave.ingest.data.config.NormalizedContentInterface;
import datawave.ingest.data.config.NormalizedFieldAndValue;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
/**
* Similar to VirtualIngest virtual fields, but composite fields are not written in the event section of the shard table (only in the field index section)
@@ -131,7 +132,7 @@ public interface CompositeIngest {
protected Map<String,Boolean> allowMissing = new HashMap<>();
private Set<String> ignoreNormalizationForFields = new HashSet<>();
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
public void setup(Type type, Configuration config) {
@@ -285,30 +286,6 @@ public interface CompositeIngest {
return new String[] {str2, str1};
}
/**
* A helper routine to merge markings maps when merging fields of a NormalizedContentInterface
*
* @param markings1
* a map of markings
* @param markings2
* a different map of markings
* @return the merged markings
*/
protected Map<String,String> mergeMarkings(Map<String,String> markings1, Map<String,String> markings2) {
if (markings2 != null) {
if (markings1 == null) {
markings1 = markings2;
} else {
try {
markings1 = markingFunctions.combine(markings1, markings2);
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Unable to combine markings.", e);
}
}
}
return markings1;
}
public Multimap<String,NormalizedContentInterface> normalize(Multimap<String,String> fields) {
Multimap<String,NormalizedContentInterface> eventFields = HashMultimap.create();
for (Entry<String,String> field : fields.entries()) {
@@ -356,7 +333,7 @@ public interface CompositeIngest {
// Create the composite field from the event Fields members
public void addCompositeFields(List<NormalizedContentInterface> compositeFields, Multimap<String,NormalizedContentInterface> eventFields,
String compositeFieldName, String replacement, String[] grouping, GroupingPolicy groupingPolicy, boolean allowMissing, String[] fields,
int pos, StringBuilder originalValue, StringBuilder normalizedValue, Map<String,String> markings, boolean isOverloadedField) {
int pos, StringBuilder originalValue, StringBuilder normalizedValue, Markings<?> markings, boolean isOverloadedField) {
String separator = (pos > 0) ? compositeSeparator.get(compositeFieldName) : "";
// append any constants that have been specified
while (pos < fields.length && isConstant(fields[pos])) {
@@ -405,9 +382,14 @@ public interface CompositeIngest {
normalizedValue.append(separator);
normalizedValue.append(value.getIndexedFieldValue());
if (pos + 1 < fields.length) {
addCompositeFields(compositeFields, eventFields, compositeFieldName.replace("*", replacement), replacement,
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1, originalValue,
normalizedValue, mergeMarkings(markings, value.getMarkings()), isOverloadedField);
try {
addCompositeFields(compositeFields, eventFields, compositeFieldName.replace("*", replacement), replacement,
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1,
originalValue, normalizedValue, markingFunctions.combine(markings, value.getMarkings()),
isOverloadedField);
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Could not combine markings", e);
}
}
originalValue.setLength(oLen);
normalizedValue.setLength(nLen);
@@ -427,7 +409,7 @@ public interface CompositeIngest {
continue;
}
}
if (!isOverloadedField || (isOverloadedField && pos == 0)) {
if (!isOverloadedField || pos == 0) {
originalValue.append(separator);
originalValue.append(value.getEventFieldValue());
}
@@ -437,9 +419,13 @@ public interface CompositeIngest {
} else {
normalizedValue.append(value.getIndexedFieldValue());
}
addCompositeFields(compositeFields, eventFields, compositeFieldName, replacement, (grouping == null ? newGrouping : grouping),
groupingPolicy, allowMissing, fields, pos + 1, originalValue, normalizedValue,
mergeMarkings(markings, value.getMarkings()), isOverloadedField);
try {
addCompositeFields(compositeFields, eventFields, compositeFieldName, replacement, (grouping == null ? newGrouping : grouping),
groupingPolicy, allowMissing, fields, pos + 1, originalValue, normalizedValue,
markingFunctions.combine(markings, value.getMarkings()), isOverloadedField);
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Could not combine markings", e);
}
originalValue.setLength(oLen);
normalizedValue.setLength(nLen);
}
@@ -28,6 +28,7 @@ import datawave.ingest.data.config.GroupedNormalizedContentInterface;
import datawave.ingest.data.config.NormalizedContentInterface;
import datawave.ingest.data.config.NormalizedFieldAndValue;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
public interface VirtualIngest {
@@ -126,7 +127,7 @@ public interface VirtualIngest {
protected transient Map<String,Boolean> allowMissing = new HashMap<>();
private Set<String> ignoreNormalizationForFields = new HashSet<>();
private transient MarkingFunctions markingFunctions;
private transient MarkingFunctions<?> markingFunctions;
public void setup(Type type, String instance, Configuration config) {
@@ -338,30 +339,6 @@ public interface VirtualIngest {
}
}
/**
* A helper routine to merge markings maps when merging fields of a NormalizedContentInterface
*
* @param markings1
* a map of markings
* @param markings2
* a different map of markings
* @return the merged markings
*/
protected Map<String,String> mergeMarkings(Map<String,String> markings1, Map<String,String> markings2) {
if (markings2 != null) {
if (markings1 == null) {
markings1 = markings2;
} else {
try {
markings1 = markingFunctions.combine(markings1, markings2);
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Unable to combine markings.", e);
}
}
}
return markings1;
}
/**
* Create the normalized form of a map of fields, and add the virtual fields as configured above.
*
@@ -544,7 +521,7 @@ public interface VirtualIngest {
public void addVirtualFields(List<NormalizedContentInterface> virtualFields, Multimap<String,NormalizedContentInterface> eventFields,
Map<String,Multimap<VirtualFieldGrouping,NormalizedContentInterface>> groupings, String virtualFieldName, String replacement,
VirtualFieldGrouping grouping, GroupingPolicy groupingPolicy, boolean allowMissing, String[] fields, int pos, String startSeparator,
String endSeparator, StringBuilder originalValue, StringBuilder normalizedValue, Map<String,String> markings) {
String endSeparator, StringBuilder originalValue, StringBuilder normalizedValue, Markings<?> markings) {
String separator = "";
// append any constants that have been specified
while (pos < fields.length && isConstant(fields[pos])) {
@@ -599,10 +576,14 @@ public interface VirtualIngest {
normalizedValue.append(endSeparator);
// recurse for the next virtual field definition segment
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName.replace("*", replacement), replacement,
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1,
this.defaultStartSeparator, this.defaultEndSeparator, originalValue, normalizedValue,
mergeMarkings(markings, value.getMarkings()));
try {
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName.replace("*", replacement), replacement,
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1,
this.defaultStartSeparator, this.defaultEndSeparator, originalValue, normalizedValue,
markingFunctions.combine(markings, value.getMarkings()));
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Could not combine markings", e);
}
// reset the values to the original length
originalValue.setLength(oLen);
@@ -638,9 +619,13 @@ public interface VirtualIngest {
normalizedValue.append(endSeparator);
// recurse on the next virtual field segment
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName, replacement, (grouping == null ? newGrouping : grouping),
groupingPolicy, allowMissing, fields, pos + 1, this.defaultStartSeparator, this.defaultEndSeparator, originalValue,
normalizedValue, mergeMarkings(markings, value.getMarkings()));
try {
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName, replacement, (grouping == null ? newGrouping : grouping),
groupingPolicy, allowMissing, fields, pos + 1, this.defaultStartSeparator, this.defaultEndSeparator, originalValue,
normalizedValue, markingFunctions.combine(markings, value.getMarkings()));
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Could not combine markings", e);
}
// reset the values to the original length
originalValue.setLength(oLen);
@@ -161,7 +161,7 @@ public class EventMapper<K1,V1 extends RawRecordContainer,K2,V2> extends StatsDE
protected Set<String> sequenceFileNames = new HashSet<>();
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
private boolean metricsEnabled = false;
private MetricsService<K2,V2> metricsService;
@@ -30,6 +30,7 @@ import datawave.ingest.mapreduce.job.BulkIngestKey;
import datawave.ingest.mapreduce.job.writer.ContextWriter;
import datawave.ingest.metadata.RawRecordMetadata;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.util.StringUtils;
import datawave.util.TextUtil;
@@ -63,7 +64,7 @@ public class AtomDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedDataT
protected String[] fieldOverrides = null;
protected HashMap<String,Set<String>> subCategories;
protected String[] sCategories = null;
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
protected Configuration conf;
@@ -254,16 +255,11 @@ public class AtomDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedDataT
* the value
* @return the visibility
*/
protected String getColumnQualifier(RawRecordContainer event, NormalizedContentInterface value) {
ColumnVisibility visibility = event.getVisibility();
if (value.getMarkings() != null && !value.getMarkings().isEmpty()) {
try {
visibility = markingFunctions.translateToColumnVisibility(value.getMarkings());
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Cannot convert record-level markings into a column visibility", e);
}
Markings<?> markings = value.getMarkings();
if (markings != null && !markings.isEmpty()) {
visibility = markings.toColumnVisibility();
}
return flatten(visibility);
}
@@ -5,6 +5,7 @@ import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.hadoop.conf.Configuration;
@@ -29,6 +30,7 @@ import datawave.ingest.mapreduce.handler.error.ErrorShardedDataTypeHandler;
import datawave.ingest.mapreduce.job.BulkIngestKey;
import datawave.ingest.mapreduce.job.writer.ContextWriter;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
/**
* This class differs from the parent in that when it sees a field name of ERROR it creates a category name using the field name and value.
@@ -48,13 +50,10 @@ public class AtomErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends AtomDataTyp
public static final String ERROR_FIELD = "ERROR";
public static final String STACK_TRACE_FIELD = "STACKTRACE";
public static final String EVENT_CONTENT_FIELD = "EVENT";
public static final String COLUMN_VISIBILITY = "columnVisibility";
private MarkingsHelper mHelper = null;
private ColumnVisibility defaultVisibility = null;
private AccessExpression defaultVisibility = null;
private Configuration conf = null;
private ErrorShardedIngestHelper errorHelper = null;
private MarkingFunctions markingFunctions;
@Override
public void setup(TaskAttemptContext context) {
@@ -77,11 +76,7 @@ public class AtomErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends AtomDataTyp
}
mHelper = IngestConfigurationFactory.getIngestConfiguration().getMarkingsHelper(conf, record.getDataType());
try {
defaultVisibility = markingFunctions.translateToColumnVisibility(mHelper.getDefaultMarkings());
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse security marking configuration", e);
}
defaultVisibility = mHelper.getDefaultMarkings().toAccessExpression();
// write out the event into a value before we muck with it
DataOutputBuffer buffer = new DataOutputBuffer();
@@ -180,22 +175,17 @@ public class AtomErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends AtomDataTyp
}
protected String getVisibilityColumnString(RawRecordContainer event, NormalizedContentInterface value) {
ColumnVisibility visibility = getVisibilityColumnVisibility(event, value);
return visibility.toString();
}
protected ColumnVisibility getVisibilityColumnVisibility(RawRecordContainer event, NormalizedContentInterface value) {
ColumnVisibility visibility = event.getVisibility();
if (value.getMarkings() != null && !value.getMarkings().isEmpty()) {
try {
visibility = markingFunctions.translateToColumnVisibility(value.getMarkings());
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Cannot convert record-level markings into a column visibility", e);
}
Markings<?> markings = value.getMarkings();
// value marking is 1st choice
if (markings != null && !markings.isEmpty()) {
return markings.toAccessExpression().getExpression();
}
return visibility == null ? defaultVisibility : visibility;
ColumnVisibility visibility = event.getVisibility();
if (visibility != null) {
// event marking is 2nd choice
return new String(visibility.getExpression());
}
// default marking is the last resort
return defaultVisibility != null ? defaultVisibility.getExpression() : "";
}
}
@@ -94,6 +94,7 @@ public class DateIndexDataTypeHandler<KEYIN> implements DataTypeHandler<KEYIN>,
protected DateNormalizer dateNormalizer = new DateNormalizer();
protected ShardIdFactory shardIdFactory = null;
protected TaskAttemptContext taskAttemptContext = null;
protected MarkingFunctions<?> markingFunctions;
public Set<Type> getDataTypes() {
Set<Type> types = new HashSet<>();
@@ -148,6 +149,7 @@ public class DateIndexDataTypeHandler<KEYIN> implements DataTypeHandler<KEYIN>,
this.taskAttemptContext = context;
this.conf = context.getConfiguration();
this.shardIdFactory = new ShardIdFactory(conf);
markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
String tableName = conf.get(DATEINDEX_TNAME, null);
if (null == tableName) {
@@ -364,7 +366,7 @@ public class DateIndexDataTypeHandler<KEYIN> implements DataTypeHandler<KEYIN>,
* @return the flattened visibility
*/
protected byte[] flatten(ColumnVisibility vis) {
return MarkingFunctions.Factory.createMarkingFunctions().flatten(vis);
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
}
public Text getDateIndexTableName() {
@@ -1,5 +1,7 @@
package datawave.ingest.mapreduce.handler.edge;
import static java.nio.charset.StandardCharsets.UTF_8;
import static datawave.ingest.mapreduce.handler.shard.ShardedDataTypeHandler.METADATA_TABLE_LOADER_PRIORITY;
import static datawave.ingest.mapreduce.handler.shard.ShardedDataTypeHandler.METADATA_TABLE_NAME;
@@ -20,6 +22,7 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.ColumnVisibility;
@@ -73,7 +76,9 @@ import datawave.ingest.mapreduce.job.writer.ContextWriter;
import datawave.ingest.metadata.RawRecordMetadata;
import datawave.ingest.table.config.LoadDateTableConfigHelper;
import datawave.ingest.time.Now;
import datawave.marking.AccessExpressionUtil;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.metadata.protobuf.EdgeMetadata;
import datawave.metadata.protobuf.EdgeMetadata.MetadataValue;
import datawave.metadata.protobuf.EdgeMetadata.MetadataValue.Metadata;
@@ -141,7 +146,7 @@ public class ProtobufEdgeDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements Exten
protected String edgeTableName = null;
protected String metadataTableName = null;
protected boolean enableMetadata = false;
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
protected Map<String,EdgeDefinitionConfigurationHelper> edges = null;
@@ -1327,15 +1332,13 @@ public class ProtobufEdgeDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements Exten
* the event container
* @return the visibility as Text object
*/
protected Text getVisibility(Map<String,String> markings, RawRecordContainer event) {
try {
if (null == markings || markings.isEmpty()) {
return new Text(flatten(event.getVisibility()));
} else {
return new Text(flatten(markingFunctions.translateToColumnVisibility(markings)));
}
} catch (datawave.marking.MarkingFunctions.Exception e) {
throw new RuntimeException("Cannot convert markings into column visibility", e);
@SuppressWarnings("unchecked")
protected Text getVisibility(Markings<?> markings, RawRecordContainer event) {
if (null == markings || markings.isEmpty()) {
return new Text(flatten(event.getVisibility()));
} else {
AccessExpression ae = AccessExpressionUtil.normalize(markings.toAccessExpression());
return new Text(ae.getExpression().getBytes(UTF_8));
}
}
@@ -1363,7 +1366,7 @@ public class ProtobufEdgeDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements Exten
* @return the flattened visibility
*/
protected byte[] flatten(ColumnVisibility vis) {
return markingFunctions.flatten(vis);
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
}
@Override
@@ -1,8 +1,7 @@
package datawave.ingest.mapreduce.handler.edge.define;
import java.util.Map;
import datawave.ingest.data.config.NormalizedContentInterface;
import datawave.marking.Markings;
/**
* Extracts the duration field specified by a Normalized Content Interface
@@ -13,7 +12,7 @@ import datawave.ingest.data.config.NormalizedContentInterface;
public class DurationValue {
private int duration = -1;
private Map<String,String> markings = null;
private Markings<?> markings = null;
public DurationValue(NormalizedContentInterface elapsedTimeNCI) {
String durString = elapsedTimeNCI.getIndexedFieldValue();
@@ -36,7 +35,7 @@ public class DurationValue {
}
}
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return this.markings;
}
}
@@ -3,7 +3,6 @@ package datawave.ingest.mapreduce.handler.edge.define;
import java.io.IOException;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.ColumnVisibility;
@@ -20,7 +19,7 @@ import datawave.ingest.data.config.NormalizedContentInterface;
import datawave.ingest.data.config.ingest.IngestHelperInterface;
import datawave.ingest.mapreduce.handler.edge.define.VertexValue.ValueType;
import datawave.marking.MarkingFunctions;
import datawave.marking.MarkingFunctions.Exception;
import datawave.marking.Markings;
import datawave.util.time.DateHelper;
/**
@@ -34,43 +33,43 @@ public class EdgeDataBundle {
// Input/Setup variables
// final so you're not tempted to change them
private final RawRecordContainer event;
private final MarkingFunctions<?> markingFunctions;
private VertexValue source;
private VertexValue sink;
private EdgeDefinition edgeDefinition = null;
private EdgeDefinition edgeDefinition;
private EdgeDirection edgeDirection = EdgeDirection.UNIDIRECTIONAL;
private String sourceMaskedValue = null;
private boolean hasMaskedSource = false;
private String sinkMaskedValue = null;
private boolean hasMaskedSink = false;
private String sourceMaskedValue;
private boolean hasMaskedSource;
private String sinkMaskedValue;
private boolean hasMaskedSink;
// Variables for output
private boolean requiresMasking = false;
private boolean isDeleting = false;
private boolean requiresMasking;
private boolean isDeleting;
private String edgeType;
private String enrichedIndex;
private String enrichedValue;
private String edgeAttribute3;
private String edgeAttribute2;
private long eventDate = 0;
private long eventDate;
private IngestHelperInterface helper;
private Map<String,String> markings = null;
private ColumnVisibility maskedVisibility = null;
private boolean forceMaskedVisibility = false; // if this is a masked event, but the
private Markings<?> markings;
private ColumnVisibility maskedVisibility;
private boolean forceMaskedVisibility; // if this is a masked event, but the
// the fields defined aren't masked, use the unmasked visibility
// Duration value if defined
private DurationValue durationValue = null;
private DurationValue durationValue;
private String loadDate;
private MarkingFunctions mf = null;
private String uuid;
private long activityDate;
private boolean validActivityDate;
public EdgeDataBundle(RawRecordContainer event, String typeName, String id, IngestHelperInterface helper) {
this.mf = MarkingFunctions.Factory.createMarkingFunctions();
this.markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
this.event = event;
this.eventDate = event.getDate();
this.edgeType = typeName;
@@ -80,7 +79,7 @@ public class EdgeDataBundle {
public EdgeDataBundle(EdgeDefinition edgeDef, NormalizedContentInterface ifaceSource, NormalizedContentInterface ifaceSink, RawRecordContainer event,
IngestHelperInterface helper) {
this(event, edgeDef.getEdgeType().toString(), null, helper);
this(event, edgeDef.getEdgeType(), null, helper);
this.setSource(new VertexValue(edgeDef.isUseRealm(), edgeDef.getSourceIndexedFieldRealm(), edgeDef.getSourceEventFieldRealm(),
edgeDef.getSourceRelationship(), edgeDef.getSourceCollection(), ifaceSource));
@@ -95,7 +94,11 @@ public class EdgeDataBundle {
// even though event, etc. references are saved above, passing in the event
// prevents future bug
this.initFieldMasking(helper, event);
this.initMarkings(getSource().getMarkings(), getSink().getMarkings());
try {
this.markings = markingFunctions.combine(getSource().getMarkings(), getSink().getMarkings());
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Could not combine markings", e);
}
}
private int getHour(long time) {
@@ -140,23 +143,6 @@ public class EdgeDataBundle {
this.maskedVisibility = maskedVisibility;
}
@SuppressWarnings("unchecked")
private void initMarkings(Map<String,String> m1, Map<String,String> m2) {
if (m1 != null) {
if (m2 != null) {
try {
this.markings = mf.combine(m1, m2);
} catch (Exception e) {
throw new RuntimeException("Unable to combine markings", e);
}
} else {
this.markings = m1;
}
} else if (m2 != null) {
this.markings = m2;
}
}
public int getDuration() {
return null == this.getDurationValue() ? -1 : this.getDurationValue().getDuration();
}
@@ -192,24 +178,19 @@ public class EdgeDataBundle {
}
if (date_type == EdgeKey.DATE_TYPE.EVENT_ONLY) {
if (validActivityDate) {
builder.setBadActivityDate(false);
} else {
builder.setBadActivityDate(true);
}
builder.setBadActivityDate(!validActivityDate);
}
// Set counts
if (!this.isDeleting()) {
builder.setCount(1l);
builder.setCount(1L);
} else {
builder.setCount(-1l);
builder.setCount(-1L);
}
// Set Hour Bitmask
if (hour != -1) {
builder.setHour(hour);
}
if (forwardEdge == true) {
if (forwardEdge) {
builder.setSourceValue(source.getValue(ValueType.EVENT));
builder.setSinkValue(sink.getValue(ValueType.EVENT));
} else {
@@ -236,16 +217,11 @@ public class EdgeDataBundle {
}
if (date_type == EdgeKey.DATE_TYPE.EVENT_ONLY) {
if (validActivityDate) {
builder.setBadActivityDate(false);
} else {
builder.setBadActivityDate(true);
}
builder.setBadActivityDate(!validActivityDate);
}
List<Long> hours = EdgeValueHelper.getLongListForHour(hour, this.isDeleting());
builder.setHours(hours);
if (forwardEdge == true) {
if (forwardEdge) {
builder.setSourceValue(source.getValue(ValueType.EVENT));
} else {
builder.setSourceValue(sink.getValue(ValueType.EVENT));
@@ -276,7 +252,7 @@ public class EdgeDataBundle {
EdgeValueBuilder builder = datawave.edge.util.EdgeValue.newBuilder();
List<Long> duration = EdgeValueHelper.getLongListForDuration(this.getDuration(), this.isDeleting());
builder.setDuration(duration);
if (forwardEdge == true) {
if (forwardEdge) {
builder.setSourceValue(source.getValue(ValueType.EVENT));
} else {
builder.setSourceValue(sink.getValue(ValueType.EVENT));
@@ -385,11 +361,11 @@ public class EdgeDataBundle {
this.sink = sink;
}
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return this.markings;
}
public void setMarkings(Map<String,String> markings) {
public void setMarkings(Markings<?> markings) {
this.markings = markings;
}
@@ -1,8 +1,7 @@
package datawave.ingest.mapreduce.handler.edge.define;
import java.util.Map;
import datawave.ingest.data.config.NormalizedContentInterface;
import datawave.marking.Markings;
/**
* Combines a VertexDefinition with value obtained from a {@link datawave.ingest.data.config.NormalizedContentInterface}.
@@ -23,7 +22,7 @@ public class VertexValue {
private String indexedRealmLabel = null;
private String eventRealmLabel = null;
private String sourceIndex = null;
private Map<String,String> markings = null;
private Markings<?> markings = null;
private String maskedValue = null;
private boolean hasMaskedValue = false;
private String relationshipType = null;
@@ -50,7 +49,7 @@ public class VertexValue {
}
}
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return this.markings;
}
@@ -1,10 +1,12 @@
package datawave.ingest.mapreduce.handler.error;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Date;
import java.util.Map;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.ColumnVisibility;
@@ -109,7 +111,7 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
private byte[] defaultVisibility = null;
protected MarkingsHelper markingsHelper;
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
private String tableName = null;
@@ -133,11 +135,11 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
this.conf = context.getConfiguration();
try {
Map<String,String> defaultMarkings = markingsHelper.getDefaultMarkings();
defaultVisibility = flatten(markingFunctions.translateToColumnVisibility(defaultMarkings));
} catch (MarkingFunctions.Exception e) {
throw new IllegalArgumentException("Failed to convert default markings to a ColumnVisibility.", e);
if (markingsHelper != null && markingsHelper.getDefaultMarkings() != null) {
AccessExpression ae = markingsHelper.getDefaultMarkings().toAccessExpression();
if (ae != null) {
defaultVisibility = ae.getExpression().getBytes(UTF_8);
}
}
// Initialize a UID builder based on the configuration
@@ -320,12 +322,7 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
protected byte[] getVisibility(RawRecordContainer event, NormalizedContentInterface value) {
byte[] visibility;
if (value != null && value.getMarkings() != null && !value.getMarkings().isEmpty()) {
try {
visibility = flatten(markingFunctions.translateToColumnVisibility(value.getMarkings()));
} catch (MarkingFunctions.Exception e) {
log.error("Failed to create visibility from markings, using default", e);
visibility = defaultVisibility;
}
visibility = flatten(value.getMarkings().toColumnVisibility());
} else if (event.getVisibility() != null) {
visibility = flatten(event.getVisibility());
} else {
@@ -335,14 +332,14 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
}
/**
* Create a flattened visibility, using the cache if possible
* Normalize a ColumnVisibility expression via AccessExpression and return the expression bytes.
*
* @param vis
* the visibility
* @return the flattened visibility
* @return the normalized visibility bytes
*/
protected byte[] flatten(ColumnVisibility vis) {
return markingFunctions.flatten(vis);
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
}
@Override
@@ -1,5 +1,7 @@
package datawave.ingest.mapreduce.handler.error;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
@@ -7,6 +9,7 @@ import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.hadoop.conf.Configurable;
@@ -41,7 +44,6 @@ import datawave.ingest.mapreduce.handler.shard.AbstractColumnBasedHandler;
import datawave.ingest.mapreduce.handler.shard.ShardedDataTypeHandler;
import datawave.ingest.mapreduce.job.BulkIngestKey;
import datawave.ingest.mapreduce.job.writer.ContextWriter;
import datawave.marking.MarkingFunctions;
import datawave.table.constants.ColumnFamilyConstants;
/**
@@ -156,10 +158,11 @@ public class ErrorShardedDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends Abstract
tableName = conf.get(ERROR_PROP_PREFIX + SHARD_DINDX_NAME);
setShardDictionaryIndexTableName(tableName == null ? null : new Text(tableName));
try {
defaultVisibility = flatten(markingFunctions.translateToColumnVisibility(markingsHelper.getDefaultMarkings()));
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse security marking configuration", e);
if (markingsHelper != null && markingsHelper.getDefaultMarkings() != null) {
AccessExpression ae = markingsHelper.getDefaultMarkings().toAccessExpression();
if (ae != null) {
defaultVisibility = ae.getExpression().getBytes(UTF_8);
}
}
log.info("ShardedErrorDataTypeHandler configured.");
@@ -347,12 +350,7 @@ public class ErrorShardedDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends Abstract
public byte[] getVisibility(RawRecordContainer event, NormalizedContentInterface value) {
byte[] visibility;
if (value != null && value.getMarkings() != null && !value.getMarkings().isEmpty()) {
try {
visibility = flatten(markingFunctions.translateToColumnVisibility(value.getMarkings()));
} catch (MarkingFunctions.Exception e) {
log.error("Failed to create visibility from markings, using default", e);
visibility = defaultVisibility;
}
visibility = flatten(value.getMarkings().toColumnVisibility());
} else if (event.getVisibility() != null) {
visibility = flatten(event.getVisibility());
} else {
@@ -91,7 +91,7 @@ public class FacetHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedDataTypeHand
/* Instance variables */
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
protected ShardIdFactory shardIdFactory;
protected TaskAttemptContext taskAttemptContext;
@@ -50,6 +50,7 @@ import datawave.ingest.util.BloomFilterUtil;
import datawave.ingest.util.BloomFilterWrapper;
import datawave.ingest.util.DiskSpaceStarvationStrategy;
import datawave.marking.MarkingFunctions;
import datawave.marking.Markings;
import datawave.query.model.Direction;
import datawave.util.CompositeTimestamp;
import datawave.util.TableName;
@@ -219,7 +220,7 @@ public abstract class ShardedDataTypeHandler<KEYIN> extends StatsDEnabledDataTyp
private RawRecordMetadata metadata = null;
private ShardIdFactory shardIdFactory = null;
private LoadingCache<String,String> dCache = null;
protected MarkingFunctions markingFunctions;
protected MarkingFunctions<?> markingFunctions;
protected IngestConfiguration ingestConfig = IngestConfigurationFactory.getIngestConfiguration();
// default setting is a standard index with uid and event keys
@@ -1129,22 +1130,19 @@ public abstract class ShardedDataTypeHandler<KEYIN> extends StatsDEnabledDataTyp
*/
public byte[] getVisibility(RawRecordContainer event, NormalizedContentInterface value) {
ColumnVisibility visibility = event.getVisibility();
if (value.getMarkings() != null && !value.getMarkings().isEmpty()) {
try {
visibility = markingFunctions.translateToColumnVisibility(value.getMarkings());
} catch (MarkingFunctions.Exception e) {
throw new RuntimeException("Cannot convert record-level markings into a column visibility", e);
}
Markings<?> markings = value.getMarkings();
if (markings != null && !markings.isEmpty()) {
visibility = markings.toColumnVisibility();
}
return flatten(visibility);
}
/**
* Create a flattened visibility, using the cache if possible
* Normalize a ColumnVisibility expression via AccessExpression and return the expression bytes.
*
* @param vis
* the visibility
* @return the flattened visibility
* @return the normalized visibility bytes
*/
protected byte[] flatten(ColumnVisibility vis) {
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
@@ -5,7 +5,6 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.log4j.Logger;
@@ -170,89 +169,6 @@ public class ExtendedContentIngestHelper extends BaseIngestHelper implements Ter
}
}
public void inheritFromRootPayload(RawRecordContainer event, Map<String,Collection<Object>> metadata) {
// TODO: No-op here, but need to refactor the following in upstream
// if (metadata == null)
// return;
//
// IBaseDataObject payload = (IBaseDataObject) event.getAuxData();
// if (payload != null) {
// for (String field : helper.getInheritedPayloadFields()) {
// if (metadata.containsKey(field) && (!payload.hasParameter(field))) {
// payload.putParameter(field, metadata.get(field));
// }
// }
// }
}
public void addMetadataFromParms(RawRecordContainer event, Map<String,Collection<Object>> metadata, String id) {
for (Map.Entry<String,Collection<Object>> entry : metadata.entrySet()) {
CharSequence key = entry.getKey();
for (Object value : entry.getValue()) {
if (value == null)
continue;
if (helper.getUuids().contains(key)) {
event.getAltIds().add(String.valueOf(value));
}
if (this.helper.getSecurityMarkingFieldDomainMap().containsKey(key)) {
addSecurityMetadataFromParms(key, value, event);
}
}
}
Multimap<String,String> newMetadata = HashMultimap.create();
Multimap<String,MetadataIdParser> fieldParsers = helper.getMetadataFieldParsers();
for (String field : fieldParsers.keySet()) {
if (metadata.containsKey(field) && metadata.get(field) != null) {
for (MetadataIdParser parser : fieldParsers.get(field)) {
for (Object v : metadata.get(field)) {
if (v == null)
continue;
try {
parser.addMetadata(event, newMetadata, v.toString());
} catch (Exception e) {
log.error("Unable to apply " + parser + " to " + field, e);
event.addError(RawDataErrorNames.FIELD_EXTRACTION_ERROR);
}
}
}
}
}
// If the ID is a UUID (i.e., contains no date), try to get
// event metadata from the parameters
if ((id != null) && (id.length() >= UUID_LENGTH) && id.matches(UUID_PATTERN)) {
fieldParsers = helper.getMetadataFieldUuidParsers();
for (String field : fieldParsers.keySet()) {
if (metadata.containsKey(field) && metadata.get(field) != null) {
for (MetadataIdParser parser : fieldParsers.get(field)) {
for (Object v : metadata.get(field)) {
if (v == null)
continue;
try {
parser.addMetadata(event, newMetadata, v.toString());
} catch (Exception e) {
log.error("Unable to apply " + parser + " to " + field, e);
event.addError(RawDataErrorNames.FIELD_EXTRACTION_ERROR);
}
}
}
}
}
}
}
protected void addSecurityMetadataFromParms(CharSequence key, Object value, RawRecordContainer event) {
// If fieldName is a security marking field (as configured by EVENT_SECURITY_MARKING_FIELD_NAMES),
// then put the marking value into this.securityMarkings, where 'key' maps to the domain for the marking
// (as configured by EVENT_SECURITY_MARKING_FIELD_DOMAINS)
if (!StringUtils.isEmpty(key.toString()) && !StringUtils.isEmpty(value.toString())) {
event.addSecurityMarking(this.helper.getSecurityMarkingFieldDomainMap().get(key.toString()), value.toString());
}
}
/**
* Override the normalize call to enable event field value normalization
*
@@ -398,7 +398,7 @@ public class RawRecordContainerImplTest {
if (getVisibility() == null && getSecurityMarkings() == null) {
if (markingsHelper != null) {
setSecurityMarkings(markingsHelper.getDefaultMarkings());
} else {}
}
}
if (getSecurityMarkings() == null) {
@@ -1,13 +1,12 @@
package datawave.ingest.data.config;
import java.util.Map;
import org.apache.hadoop.conf.Configuration;
import org.junit.Assert;
import org.junit.Test;
import datawave.ingest.data.Type;
import datawave.marking.MarkingFunctions;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
public class MarkingsHelperTest {
public static final String FIELD_NAME = "FIELDNAME1";
@@ -36,10 +35,10 @@ public class MarkingsHelperTest {
// use the same type name to retrieve a markings helper and retrieve the field marking
MarkingsHelper markingsHelper = new MarkingsHelper.NoOp(conf, createType(typeName));
Map<String,String> fieldMarkingMap = markingsHelper.getFieldMarking(FIELD_NAME);
Markings<?> fieldMarkings = markingsHelper.getFieldMarking(FIELD_NAME);
Assert.assertNotNull(fieldMarkingMap);
Assert.assertEquals(FIELD_MARKING_VALUE, fieldMarkingMap.get(MarkingFunctions.Default.COLUMN_VISIBILITY));
Assert.assertNotNull(fieldMarkings);
Assert.assertEquals(FIELD_MARKING_VALUE, ((AccessExpressionMarkings) fieldMarkings).getAccessExpression().getExpression());
}
private Configuration createConfWithFieldMarking(String typeName) {
@@ -1,11 +1,10 @@
package datawave.ingest.data.config;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import datawave.data.type.Type;
import datawave.marking.Markings;
public class NormalizedFieldAndValueTest {
@@ -19,7 +18,7 @@ public class NormalizedFieldAndValueTest {
private String _eventFieldName;
private String _eventFieldValue;
private Map<String,String> _markings;
private Markings<?> _markings;
private Throwable _error;
protected NonGroupedInstance() {
@@ -84,7 +83,7 @@ public class NormalizedFieldAndValueTest {
}
@Override
public void setMarkings(Map<String,String> markings) {
public void setMarkings(Markings<?> markings) {
_markings = markings;
}
@@ -95,7 +94,7 @@ public class NormalizedFieldAndValueTest {
}
@Override
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return _markings;
}
@@ -135,7 +134,7 @@ public class NormalizedFieldAndValueTest {
private String _eventFieldName;
private String _eventFieldValue;
private Map<String,String> _markings;
private Markings<?> _markings;
private Throwable _error;
private boolean _grouped;
@@ -208,7 +207,7 @@ public class NormalizedFieldAndValueTest {
}
@Override
public void setMarkings(Map<String,String> markings) {
public void setMarkings(Markings<?> markings) {
_markings = markings;
}
@@ -219,7 +218,7 @@ public class NormalizedFieldAndValueTest {
}
@Override
public Map<String,String> getMarkings() {
public Markings<?> getMarkings() {
return _markings;
}
@@ -1,7 +1,6 @@
package datawave.ingest.data.config.ingest;
import java.util.HashMap;
import java.util.Map;
import org.apache.accumulo.access.Access;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
@@ -9,6 +8,7 @@ import com.google.common.collect.Multimap;
import datawave.ingest.data.RawRecordContainer;
import datawave.ingest.data.config.NormalizedContentInterface;
import datawave.ingest.data.config.NormalizedFieldAndValue;
import datawave.marking.AccessExpressionMarkings;
/**
*
@@ -19,8 +19,7 @@ public class FakeIngestHelper extends BaseIngestHelper {
@Override
public Multimap<String,NormalizedContentInterface> getEventFields(RawRecordContainer event) {
Multimap<String,NormalizedContentInterface> eventFields = HashMultimap.create();
Map<String,String> markings = new HashMap<>();
markings.put("P", "PERSONAL");
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(Access.builder().build().newExpression("PERSONAL")).build();
eventFields.put("FAKE_FIELD", new NormalizedFieldAndValue("FAKE_FIELD", "fake value", markings));
return eventFields;
@@ -9,8 +9,8 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.hadoop.io.Writable;
@@ -20,6 +20,8 @@ import datawave.data.hash.UIDBuilder;
import datawave.ingest.data.RawRecordContainer;
import datawave.ingest.data.Type;
import datawave.ingest.data.TypeRegistry;
import datawave.marking.AccessExpressionMarkings;
import datawave.marking.Markings;
import datawave.util.CompositeTimestamp;
/**
@@ -29,7 +31,7 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
private UIDBuilder<UID> uidBuilder = HashUID.builder();
private Map<String,String> securityMarkings = new TreeMap<>();
private Markings<?> securityMarkings = null;
private UID id = uidBuilder.newId();
private Type dataType;
private long timestamp = CompositeTimestamp.INVALID_TIMESTAMP;
@@ -45,25 +47,15 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
private boolean fatalError = false;
@Override
public Map<String,String> getSecurityMarkings() {
public Markings<?> getSecurityMarkings() {
return securityMarkings;
}
@Override
public void setSecurityMarkings(Map<String,String> securityMarkings) {
public void setSecurityMarkings(Markings<?> securityMarkings) {
this.securityMarkings = securityMarkings;
}
@Override
public void addSecurityMarking(String domain, String marking) {
securityMarkings.put(domain, marking);
}
@Override
public boolean hasSecurityMarking(String domain, String marking) {
return marking.equals(securityMarkings.get(domain));
}
@Override
public UID getId() {
return id;
@@ -244,7 +236,14 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
@Override
public void write(DataOutput dataOutput) throws IOException {
TestWritableUtil.writeMap(securityMarkings, dataOutput);
String expr = "";
if (securityMarkings != null) {
AccessExpression ae = securityMarkings.toAccessExpression();
if (ae != null) {
expr = ae.getExpression();
}
}
dataOutput.writeUTF(expr);
id.write(dataOutput);
dataOutput.writeUTF(dataType.typeName());
@@ -269,7 +268,12 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
@Override
public void readFields(DataInput dataInput) throws IOException {
securityMarkings = TestWritableUtil.readMap(dataInput);
String expr = dataInput.readUTF();
if (!expr.isEmpty()) {
securityMarkings = AccessExpressionMarkings.builder().columnVisibility(expr).build();
} else {
securityMarkings = null;
}
id = uidBuilder.newId();
id.readFields(dataInput);
@@ -131,7 +131,7 @@ public class ProtobufEdgeDeleteModeTest {
private RawRecordContainer getEvent(Configuration conf) {
RawRecordContainerImpl myEvent = new RawRecordContainerImpl();
myEvent.addSecurityMarking("columnVisibility", "PRIVATE");
myEvent.setVisibility("PRIVATE");
myEvent.setDataType(type);
myEvent.setId(UID.builder().newId());
myEvent.setConf(conf);
Loaded 100 of 210 files, more files were not shown because too many files have changed in this diff. Show more