Markings#3469
Conversation
e86e7ba to
0e0b4d2
Compare
07765cd to
65db1ad
Compare
8bc250c to
98f8567
Compare
98f8567 to
b07ead2
Compare
cceab28 to
e72fd54
Compare
691ba20 to
4bf29f6
Compare
4bf29f6 to
6076aad
Compare
6076aad to
1158ca1
Compare
1c454a1 to
7956b99
Compare
This reverts commit 1158ca1.
| 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(" ", "_"); |
There was a problem hiding this comment.
I know this isn't part of your change set, but consider the fact that for single character strings, the following is generally more performant because the character to replace isn't treated as a regular expression. Also, generally I prefer to assign it to a new immutable variable instead of reusing a variable name, the impact to the stack is minimal.
| columnName = columnName.replaceAll(" ", "_"); | |
| final String cleanColumnName = columnName.replace(' ', '_'); |
There's a second replaceAll on single characters later in this method as well
| if (null == this.markings) { | ||
| this.markings = markings; | ||
| } else { | ||
| // 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)) { | ||
| // incoming markings are null so skip remaining logic | ||
| if (null != markings) { | ||
| // we have existing markings, but they aren't valid so we update if the new ones are valid | ||
| if (this.markings.isEmpty() && !markings.isEmpty()) { | ||
| this.markings = markings; | ||
| } else { | ||
| // otherwise combine | ||
| try { | ||
| Set<ColumnVisibility> columnVisibilities = Sets.newHashSet(); | ||
| columnVisibilities.add(this.markings.toColumnVisibility()); | ||
| columnVisibilities.add(markings.toColumnVisibility()); | ||
| ColumnVisibility combinedVisibility = markingFunctions.combineVisibilities(columnVisibilities); | ||
|
|
||
| // use combined marking as new markings | ||
| this.markings = markingFunctions.translateFromColumnVisibility(combinedVisibility); | ||
| } catch (MarkingFunctions.Exception e) { | ||
| LOGGER.error("Invalid markings {} skipping column {} = {}", markings, columnName, columnTypedValue, e); | ||
| return; | ||
| } | ||
| } |
There was a problem hiding this comment.
Perhaps something like the following instead?
try {
this.markings = markingFunctions.combine(this.markings, markings);
}
catch (MarkingFunctions.Exception e) {
LOGGER.error("Invalid markings {} skipping column {} = {}", markings, cleanColumnName, columnTypedValue, e);
return;
}| request.setFieldValue(fieldValue); | ||
| Map<String,String> markings = new HashMap<>(); | ||
| markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, columnVisibility); | ||
| markings.put("columnVisibility", columnVisibility); |
There was a problem hiding this comment.
| markings.put("columnVisibility", columnVisibility); | |
| markings.put(AccessExpressionMarkings.COLUMN_VISIBILITY_KEY, columnVisibility); |
| public AccessExpressionMarkings combine(Markings<?> markings1, Markings<?> markings2) { | ||
| if (markings2 != null) { | ||
| if (markings1 == null) { | ||
| markings1 = markings2; | ||
| } else { | ||
| if (markings1 instanceof AccessExpressionMarkings && markings2 instanceof AccessExpressionMarkings) { | ||
| AccessExpressionMarkings aem1 = (AccessExpressionMarkings) markings1; | ||
| AccessExpressionMarkings aem2 = (AccessExpressionMarkings) markings2; | ||
| return combine(List.of(aem1, aem2)); | ||
| } else { | ||
| throw new RuntimeException( | ||
| String.format("Unknown markings class %s or %s", markings1.getClass().getName(), markings2.getClass().getName())); | ||
| } | ||
| } | ||
| } | ||
| return markings1 == null ? null : (AccessExpressionMarkings) markings1; |
There was a problem hiding this comment.
Consider something a little less complex? Still, not a fan of the potential ClassCastExceptions here, so this suggestion might need more thought if we want to avoid or handle those more cleanly.
| public AccessExpressionMarkings combine(Markings<?> markings1, Markings<?> markings2) { | |
| if (markings2 != null) { | |
| if (markings1 == null) { | |
| markings1 = markings2; | |
| } else { | |
| if (markings1 instanceof AccessExpressionMarkings && markings2 instanceof AccessExpressionMarkings) { | |
| AccessExpressionMarkings aem1 = (AccessExpressionMarkings) markings1; | |
| AccessExpressionMarkings aem2 = (AccessExpressionMarkings) markings2; | |
| return combine(List.of(aem1, aem2)); | |
| } else { | |
| throw new RuntimeException( | |
| String.format("Unknown markings class %s or %s", markings1.getClass().getName(), markings2.getClass().getName())); | |
| } | |
| } | |
| } | |
| return markings1 == null ? null : (AccessExpressionMarkings) markings1; | |
| public AccessExpressionMarkings combine(Markings<?> markings1, Markings<?> markings2) { | |
| 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())); |
There was a problem hiding this comment.
Nice coverage, but it would be cool to see a few more unhappy-path tests here (e.g., mismatched parenthesis, illegal operators like && and || or + or ,)
There was a problem hiding this comment.
Likewise, maybe a couple more bizarre tests here like A&A|B&B|(A&A&A) or (A|B|C)&(B|C|D) can normalize clean things like this up?
| 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; |
There was a problem hiding this comment.
I'm wondering if the prevalence of MarkingFunctions<?> and other wildcard generic types throughout this PR is suggesting that we should consider just using plain sub-classing instead of generics the code. Replacing the <?> everywhere it's used it going to be very difficult, but maybe that's not the end goal.
There was a problem hiding this comment.
Consider adding a direct dependency to accumulo-utils in the dictionary api pom?
| Markings<?> currMarkings = columnMarkingsMap.get(columnName); | ||
|
|
||
| if (currMarkings.equals(markings) == false) { | ||
| if (!currMarkings.equals(markings)) { |
There was a problem hiding this comment.
Consider a null check here?
| for (Map.Entry<String,String> entry : combinedColumnMarkings.entrySet()) { | ||
| String columnName = entry.getKey(); | ||
| String combinedString = entry.getValue(); | ||
| int x = combinedString.lastIndexOf(':'); |
There was a problem hiding this comment.
Consider whether the combined string might have colons in it from the values created in CacheableQueryRowImpl where we encode `accessExpression + ':' + columnVisibility' and this get this split incorrect.
| @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) | ||
| public interface Markings<T> { | ||
|
|
||
| T getMarkings(); |
There was a problem hiding this comment.
Consider whether we can just drop this method entirely from the interface definition and just remove the generic type on Markings.
|
|
||
| @Test | ||
| public void testJaxbMarshal() throws Exception { | ||
| JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class); |
There was a problem hiding this comment.
You could move all the JAXB boilerplate into a method:
AccessExpressionMarkings original = // ... test setup
AccessExpressionMarkings copy = makeJaxbRoundtrip(original);
// assertions
| public void testProtostuffRoundTripEmpty() { | ||
| AccessExpressionMarkings original = AccessExpressionMarkings.builder().accessExpression(null).build(); | ||
|
|
||
| LinkedBuffer buffer = LinkedBuffer.allocate(); |
There was a problem hiding this comment.
Same comment as JAXB roundtrip boilerplate.
| <dependency> | ||
| <groupId>org.projectlombok</groupId> | ||
| <artifactId>lombok</artifactId> | ||
| <version>1.18.36</version> |
There was a problem hiding this comment.
Can we bubble these versions up to the top level parent and just inherit here?
| <datawave.webservice.namespace>http://webservice.datawave.nsa/v1</datawave.webservice.namespace> | ||
| <version.commons-codec>1.17.1</version.commons-codec> | ||
| <version.datawave>7.33.1</version.datawave> | ||
| <version.datawave>7.39.0-SNAPSHOT</version.datawave> |
There was a problem hiding this comment.
Do you have changes in other repos that we'll need before we can merge this?
| import io.protostuff.Message; | ||
| import io.protostuff.Output; | ||
| import io.protostuff.Schema; | ||
| import lombok.Setter; |
There was a problem hiding this comment.
Is this the only Lombok addition? If the plan is to use it across the board, I'm cool but if this is the only usage, I'd suggest we drop the dependency and leave the original setter.
| DESC desc = this.responseObjectFactory.getDescription(); | ||
| Map<String,String> markings = Maps.newHashMap(); | ||
| markings.put("columnVisibility", columnVisibility); | ||
| Markings<?> markings = AccessExpressionMarkings.builder().accessExpression(ACCESS.newExpression(columnVisibility)).build(); |
There was a problem hiding this comment.
It looks like a large portion of AccessExpressionMarkings are being built from columnVisibilities. Thoughts on adding that to the builder?
AccessExpressionMarkings.builder().colvis(columnVisibility).build();
| 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(new AbstractMap.SimpleEntry<>("fooField", "fooType"), new DefaultDescription("my foo field", AccessExpressionMarkings.create("USER"))); |
There was a problem hiding this comment.
Not your code but a nice improvement over the entry creation is Map.entry(key, value) instead of the inner SimpleEntry thing here.
| String oldColViz = AccessExpressionUtil.normalize(AccessExpressionUtil.toAccessExpression(oldColumnVisibility)).getExpression(); | ||
| String thisVis = AccessExpressionUtil.normalize(AccessExpressionUtil.toAccessExpression(thisViz)).getExpression(); | ||
| if (!oldColViz.equals(thisVis)) { | ||
| log.trace("Skipping key that does not match with column visibility: {}", e.getKey()); |
There was a problem hiding this comment.
small touch, but could check if trace is enabled before the log statement. also on line 880
No description provided.