Skip to content

Commit

Permalink
Add decodeView http parameter support to ContentQueryLogic (#2675)
Browse files Browse the repository at this point in the history
  • Loading branch information
FineAndDandy authored Dec 19, 2024
1 parent b5b816f commit 1440f31
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ public class QueryParameters {
*/
public static final String CONTENT_VIEW_ALL = "content.view.all";

/**
* Used by the ContentQueryLogic to determine if views should be decoded from base64
*/
public static final String DECODE_VIEW = "content.view.decode";

/**
* Used to specify the class used to perform visibility interpretations into markings.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class ContentQueryLogic extends BaseQueryLogic<Entry<Key,Value>> implemen
private int queryThreads = 100;
ScannerFactory scannerFactory;
String viewName = null;
private boolean decodeView = false;

private ContentQueryConfiguration config;

Expand Down Expand Up @@ -123,6 +124,11 @@ public GenericQueryConfiguration initialize(final AccumuloClient client, final Q
end = PARENT_ONLY;
}

p = settings.findParameter(QueryParameters.DECODE_VIEW);
if ((null != p) && (null != p.getParameterValue())) {
this.decodeView = Boolean.parseBoolean(p.getParameterValue());
}

// Configure ranges
final Collection<Range> ranges = this.createRanges(settings, end);
config.setRanges(ranges);
Expand Down Expand Up @@ -249,7 +255,7 @@ public AccumuloConnectionFactory.Priority getConnectionPriority() {

@Override
public QueryLogicTransformer getTransformer(Query settings) {
return new ContentQueryTransformer(settings, this.markingFunctions, this.responseObjectFactory);
return new ContentQueryTransformer(settings, this.markingFunctions, this.responseObjectFactory, this.decodeView);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@ public class ContentQueryTransformer extends BaseQueryLogicTransformer<Entry<Key
protected final Authorizations auths;
protected final ResponseObjectFactory responseObjectFactory;
protected final Map<Metadata,String> metadataIdMap;
protected final boolean decodeView;

public ContentQueryTransformer(Query query, MarkingFunctions markingFunctions, ResponseObjectFactory responseObjectFactory) {
this(query, markingFunctions, responseObjectFactory, false);
}

public ContentQueryTransformer(Query query, MarkingFunctions markingFunctions, ResponseObjectFactory responseObjectFactory, boolean decodeView) {
super(markingFunctions);
this.auths = new Authorizations(query.getQueryAuthorizations().split(","));
this.responseObjectFactory = responseObjectFactory;
this.metadataIdMap = extractMetadadaIdMap(query);
this.decodeView = decodeView;
}

/**
Expand Down Expand Up @@ -138,7 +144,13 @@ public EventBase transform(Entry<Key,Value> entry) {
field.setMarkings(ckv.getMarkings());
field.setName(ckv.getViewName());
field.setTimestamp(entry.getKey().getTimestamp());
field.setValue(ckv.getContents());
if (this.decodeView) {
// settings a String value causes the value not to be base64 encoded, see TypedValue
field.setValue(new String(ckv.getContents()));
} else {
// settings a byte value causes the value to be base64 encoded, see TypedValue
field.setValue(ckv.getContents());
}

List<FieldBase> fields = new ArrayList<>();
fields.add(field);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,37 +10,55 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.powermock.api.easymock.PowerMock.expectLastCall;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;

import java.util.AbstractMap;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

import org.apache.accumulo.core.client.AccumuloClient;
import org.apache.accumulo.core.client.BatchScanner;
import org.apache.accumulo.core.client.Scanner;
import org.apache.accumulo.core.client.TableNotFoundException;
import org.apache.accumulo.core.data.Key;
import org.apache.accumulo.core.data.Value;
import org.apache.accumulo.core.security.Authorizations;
import org.apache.accumulo.core.security.ColumnVisibility;
import org.apache.commons.collections4.iterators.TransformIterator;
import org.geotools.util.Base64;
import org.junit.Before;
import org.junit.Test;
import org.powermock.api.easymock.PowerMock;
import org.powermock.api.easymock.annotation.Mock;

import com.google.common.collect.Sets;

import datawave.core.common.connection.AccumuloConnectionFactory;
import datawave.core.query.configuration.GenericQueryConfiguration;
import datawave.core.query.logic.BaseQueryLogic;
import datawave.core.query.logic.QueryLogicTransformer;
import datawave.core.query.result.event.DefaultResponseObjectFactory;
import datawave.marking.MarkingFunctions;
import datawave.microservice.query.Query;
import datawave.microservice.query.QueryImpl;
import datawave.query.QueryParameters;
import datawave.query.config.ContentQueryConfiguration;
import datawave.query.tables.ScannerFactory;
import datawave.webservice.query.exception.QueryException;
import datawave.webservice.query.result.event.DefaultField;
import datawave.webservice.query.result.event.EventBase;
import datawave.webservice.query.result.event.FieldBase;

public class ContentQueryLogicTest {
private ContentQueryLogic contentQueryLogic;
private ScannerFactory mockScannerFactory;
private BatchScanner mockScanner;
private GenericQueryConfiguration mockGenericConfig;
private ContentQueryConfiguration mockContentConfig;
@org.powermock.api.easymock.annotation.Mock
@Mock
Query query;

@Before
Expand Down Expand Up @@ -100,7 +118,7 @@ public void testConstructorCopy() throws Exception {
int result1 = subject.getMaxPageSize();
long result2 = subject.getPageByteTrigger();
TransformIterator result3 = subject.getTransformIterator(this.query);
PowerMock.verifyAll();
verifyAll();

// Verify results
assertEquals("Incorrect max page size", 0, result1);
Expand Down Expand Up @@ -138,6 +156,54 @@ public void testContainsDnWithAccess() {
assertFalse(logic.containsDNWithAccess(Collections.emptySet()));
}

@Test
public void testDecodeViewParam() throws Exception {
AccumuloClient mockClient = PowerMock.createMock(AccumuloClient.class);
MarkingFunctions mockMarkingFunctions = PowerMock.createMock(MarkingFunctions.class);

ContentQueryLogic logic = new ContentQueryLogic();
logic.setMarkingFunctions(mockMarkingFunctions);
logic.setResponseObjectFactory(new DefaultResponseObjectFactory());

Authorizations auths = new Authorizations("A");

Query settings = new QueryImpl();
settings.setQuery("event:20241218_0/samplecsv/1.2.3");
settings.addParameter(QueryParameters.DECODE_VIEW, "true");
settings.setQueryAuthorizations("A");

Key dataKey = new Key("20241218_0", "d", "samplecsv" + '\u0000' + "1.2.3" + '\u0000' + "someView", "A");
Value viewValue = new Value(Base64.encodeBytes("my happy message".getBytes()));
Map.Entry<Key,Value> entry = new AbstractMap.SimpleImmutableEntry<>(dataKey, viewValue);

mockMarkingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility("A"), auths);
expectLastCall().andReturn(Map.of("A", "A")).anyTimes();

replayAll();

// test with decode view
logic.initialize(mockClient, settings, Set.of(auths));
QueryLogicTransformer<Map.Entry<Key,Value>,EventBase> transformer = logic.getTransformer(settings);
EventBase base = transformer.transform(entry);

assertEquals(1, base.getFields().size());
DefaultField field = (DefaultField) base.getFields().get(0);
assertEquals("my happy message", field.getTypedValue().getValue());
assertEquals("xs:string", field.getTypedValue().getType());

// test without decode view
settings.removeParameter(QueryParameters.DECODE_VIEW);
logic.initialize(mockClient, settings, Set.of(auths));
transformer = logic.getTransformer(settings);
base = transformer.transform(entry);

assertEquals(1, base.getFields().size());
field = (DefaultField) base.getFields().get(0);
assertEquals("xs:base64Binary", field.getTypedValue().getType());

verifyAll();
}

private class TestContentQuery extends ContentQueryLogic {
// borrowed from TestBaseQueryLogic.java
public TestContentQuery() {
Expand Down

0 comments on commit 1440f31

Please sign in to comment.