Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.deephaven.server.hierarchicaltable.HierarchicalTableServiceGrpcImpl Maven / Gradle / Ivy
//
// Copyright (c) 2016-2024 Deephaven Data Labs and Patent Pending
//
package io.deephaven.server.hierarchicaltable;
import com.google.rpc.Code;
import io.deephaven.api.ColumnName;
import io.deephaven.api.SortColumn;
import io.deephaven.api.agg.Aggregation;
import io.deephaven.api.filter.Filter;
import io.deephaven.auth.codegen.impl.HierarchicalTableServiceContextualAuthWiring;
import io.deephaven.base.verify.Assert;
import io.deephaven.engine.table.Table;
import io.deephaven.engine.table.TableDefinition;
import io.deephaven.engine.table.hierarchical.HierarchicalTable;
import io.deephaven.engine.table.hierarchical.RollupTable;
import io.deephaven.engine.table.hierarchical.TreeTable;
import io.deephaven.engine.table.impl.AbsoluteSortColumnConventions;
import io.deephaven.engine.table.impl.BaseGridAttributes;
import io.deephaven.engine.table.impl.hierarchical.RollupTableImpl;
import io.deephaven.engine.table.impl.perf.QueryPerformanceNugget;
import io.deephaven.engine.table.impl.perf.QueryPerformanceRecorder;
import io.deephaven.engine.table.impl.select.WhereFilter;
import io.deephaven.extensions.barrage.util.ExportUtil;
import io.deephaven.internal.log.LoggerFactory;
import io.deephaven.io.logger.Logger;
import io.deephaven.proto.backplane.grpc.*;
import io.deephaven.proto.util.Exceptions;
import io.deephaven.server.auth.AuthorizationProvider;
import io.deephaven.server.grpc.Common;
import io.deephaven.server.grpc.GrpcErrorHelper;
import io.deephaven.server.session.*;
import io.deephaven.server.table.ops.AggregationAdapter;
import io.deephaven.server.table.ops.FilterTableGrpcImpl;
import io.deephaven.server.table.ops.filter.FilterFactory;
import io.deephaven.util.SafeCloseable;
import io.grpc.stub.StreamObserver;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.inject.Inject;
import java.lang.Object;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static io.deephaven.engine.table.impl.AbsoluteSortColumnConventions.baseColumnNameToAbsoluteName;
import static io.deephaven.extensions.barrage.util.GrpcUtil.safelyComplete;
public class HierarchicalTableServiceGrpcImpl extends HierarchicalTableServiceGrpc.HierarchicalTableServiceImplBase {
private static final Logger log = LoggerFactory.getLogger(HierarchicalTableServiceGrpcImpl.class);
private final TicketRouter ticketRouter;
private final SessionService sessionService;
private final HierarchicalTableServiceContextualAuthWiring authWiring;
private final TicketResolver.Authorization authTransformation;
@Inject
public HierarchicalTableServiceGrpcImpl(
@NotNull final TicketRouter ticketRouter,
@NotNull final SessionService sessionService,
@NotNull final AuthorizationProvider authorizationProvider) {
this.ticketRouter = ticketRouter;
this.sessionService = sessionService;
this.authWiring = authorizationProvider.getHierarchicalTableServiceContextualAuthWiring();
this.authTransformation = authorizationProvider.getTicketResolverAuthorization();
}
@Override
public void rollup(
@NotNull final RollupRequest request,
@NotNull final StreamObserver responseObserver) {
validate(request);
final SessionState session = sessionService.getCurrentSession();
final String description = "HierarchicalTableService#rollup(table="
+ ticketRouter.getLogNameFor(request.getSourceTableId(), "sourceTableId") + ")";
final QueryPerformanceRecorder queryPerformanceRecorder = QueryPerformanceRecorder.newQuery(
description, session.getSessionId(), QueryPerformanceNugget.DEFAULT_FACTORY);
try (final SafeCloseable ignored = queryPerformanceRecorder.startQuery()) {
final SessionState.ExportObject sourceTableExport =
ticketRouter.resolve(session, request.getSourceTableId(), "sourceTableId");
session.newExport(request.getResultRollupTableId(), "resultRollupTableId")
.queryPerformanceRecorder(queryPerformanceRecorder)
.require(sourceTableExport)
.onError(responseObserver)
.submit(() -> {
final Table sourceTable = sourceTableExport.get();
authWiring.checkPermissionRollup(session.getAuthContext(), request, List.of(sourceTable));
final Collection extends Aggregation> aggregations = request.getAggregationsList().stream()
.map(AggregationAdapter::adapt)
.collect(Collectors.toList());
final boolean includeConstituents = request.getIncludeConstituents();
final Collection groupByColumns = request.getGroupByColumnsList().stream()
.map(ColumnName::of)
.collect(Collectors.toList());
final RollupTable result = sourceTable.rollup(
aggregations, includeConstituents, groupByColumns);
final RollupTable transformedResult = authTransformation.transform(result);
if (transformedResult == null) {
throw Exceptions.statusRuntimeException(
Code.FAILED_PRECONDITION, "Not authorized to rollup hierarchical table");
}
safelyComplete(responseObserver, RollupResponse.getDefaultInstance());
return transformedResult;
});
}
}
private static void validate(@NotNull final RollupRequest request) {
GrpcErrorHelper.checkHasField(request, RollupRequest.RESULT_ROLLUP_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasField(request, RollupRequest.SOURCE_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasNoUnknownFields(request);
Common.validate(request.getResultRollupTableId());
Common.validate(request.getSourceTableId());
request.getAggregationsList().forEach(AggregationAdapter::validate);
}
@Override
public void tree(
@NotNull final TreeRequest request,
@NotNull final StreamObserver responseObserver) {
validate(request);
final SessionState session = sessionService.getCurrentSession();
final String description = "HierarchicalTableService#tree(table="
+ ticketRouter.getLogNameFor(request.getSourceTableId(), "sourceTableId") + ")";
final QueryPerformanceRecorder queryPerformanceRecorder = QueryPerformanceRecorder.newQuery(
description, session.getSessionId(), QueryPerformanceNugget.DEFAULT_FACTORY);
try (final SafeCloseable ignored = queryPerformanceRecorder.startQuery()) {
final SessionState.ExportObject sourceTableExport =
ticketRouter.resolve(session, request.getSourceTableId(), "sourceTableId");
session.newExport(request.getResultTreeTableId(), "resultTreeTableId")
.queryPerformanceRecorder(queryPerformanceRecorder)
.require(sourceTableExport)
.onError(responseObserver)
.submit(() -> {
final Table sourceTable = sourceTableExport.get();
authWiring.checkPermissionTree(session.getAuthContext(), request, List.of(sourceTable));
final ColumnName identifierColumn = ColumnName.of(request.getIdentifierColumn());
final ColumnName parentIdentifierColumn = ColumnName.of(request.getParentIdentifierColumn());
final Table sourceTableToUse;
if (request.getPromoteOrphans()) {
sourceTableToUse = TreeTable.promoteOrphans(
sourceTable, identifierColumn.name(), parentIdentifierColumn.name());
} else {
sourceTableToUse = sourceTable;
}
final TreeTable result = sourceTableToUse.tree(
identifierColumn.name(), parentIdentifierColumn.name());
final TreeTable transformedResult = authTransformation.transform(result);
if (transformedResult == null) {
throw Exceptions.statusRuntimeException(
Code.FAILED_PRECONDITION, "Not authorized to tree hierarchical table");
}
safelyComplete(responseObserver, TreeResponse.getDefaultInstance());
return transformedResult;
});
}
}
private static void validate(@NotNull final TreeRequest request) {
GrpcErrorHelper.checkHasField(request, TreeRequest.RESULT_TREE_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasField(request, TreeRequest.SOURCE_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasField(request, TreeRequest.IDENTIFIER_COLUMN_FIELD_NUMBER);
GrpcErrorHelper.checkHasField(request, TreeRequest.PARENT_IDENTIFIER_COLUMN_FIELD_NUMBER);
GrpcErrorHelper.checkHasNoUnknownFields(request);
Common.validate(request.getResultTreeTableId());
Common.validate(request.getSourceTableId());
}
@Override
public void apply(
@NotNull final HierarchicalTableApplyRequest request,
@NotNull final StreamObserver responseObserver) {
validate(request);
final SessionState session = sessionService.getCurrentSession();
final String description = "HierarchicalTableService#apply(table="
+ ticketRouter.getLogNameFor(request.getInputHierarchicalTableId(), "inputHierarchicalTableId") + ")";
final QueryPerformanceRecorder queryPerformanceRecorder = QueryPerformanceRecorder.newQuery(
description, session.getSessionId(), QueryPerformanceNugget.DEFAULT_FACTORY);
try (final SafeCloseable ignored = queryPerformanceRecorder.startQuery()) {
final SessionState.ExportObject> inputHierarchicalTableExport =
ticketRouter.resolve(session, request.getInputHierarchicalTableId(), "inputHierarchicalTableId");
session.newExport(request.getResultHierarchicalTableId(), "resultHierarchicalTableId")
.queryPerformanceRecorder(queryPerformanceRecorder)
.require(inputHierarchicalTableExport)
.onError(responseObserver)
.submit(() -> {
final HierarchicalTable> inputHierarchicalTable = inputHierarchicalTableExport.get();
authWiring.checkPermissionApply(session.getAuthContext(), request,
List.of(inputHierarchicalTable.getSource()));
if (request.getFiltersCount() == 0 && request.getSortsCount() == 0) {
throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT, "No operations specified");
}
final Collection finishedConditions = request.getFiltersCount() == 0
? null
: FilterTableGrpcImpl.finishConditions(request.getFiltersList());
final Collection translatedSorts =
translateAndValidateSorts(request, (BaseGridAttributes, ?>) inputHierarchicalTable);
final HierarchicalTable> result;
if (inputHierarchicalTable instanceof RollupTable) {
RollupTable rollupTable = (RollupTable) inputHierarchicalTable;
// Rollups only support filtering on the group-by columns, so we can safely use the
// aggregated node definition here.
final TableDefinition nodeDefinition =
rollupTable.getNodeDefinition(RollupTable.NodeType.Aggregated);
if (finishedConditions != null) {
final Collection extends WhereFilter> filters =
makeWhereFilters(finishedConditions, nodeDefinition);
RollupTableImpl.initializeAndValidateFilters(
rollupTable.getSource(),
rollupTable.getGroupByColumns(),
filters,
message -> Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT, message));
rollupTable = rollupTable.withFilter(Filter.and(filters));
}
if (translatedSorts != null) {
RollupTable.NodeOperationsRecorder aggregatedSorts =
rollupTable.makeNodeOperationsRecorder(RollupTable.NodeType.Aggregated);
aggregatedSorts = aggregatedSorts.sort(translatedSorts);
if (rollupTable.includesConstituents()) {
final RollupTable.NodeOperationsRecorder constituentSorts = rollupTable
.translateAggregatedNodeOperationsForConstituentNodes(aggregatedSorts);
rollupTable = rollupTable.withNodeOperations(aggregatedSorts, constituentSorts);
} else {
rollupTable = rollupTable.withNodeOperations(aggregatedSorts);
}
}
result = rollupTable;
} else if (inputHierarchicalTable instanceof TreeTable) {
TreeTable treeTable = (TreeTable) inputHierarchicalTable;
final TableDefinition nodeDefinition = treeTable.getNodeDefinition();
if (finishedConditions != null) {
treeTable = treeTable
.withFilter(Filter.and(makeWhereFilters(finishedConditions, nodeDefinition)));
}
if (translatedSorts != null) {
TreeTable.NodeOperationsRecorder treeSorts = treeTable.makeNodeOperationsRecorder();
treeSorts = treeSorts.sort(translatedSorts);
treeTable = treeTable.withNodeOperations(treeSorts);
}
result = treeTable;
} else {
throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
"Input is not a supported HierarchicalTable type");
}
final HierarchicalTable> transformedResult = authTransformation.transform(result);
if (transformedResult == null) {
throw Exceptions.statusRuntimeException(
Code.FAILED_PRECONDITION, "Not authorized to apply to hierarchical table");
}
safelyComplete(responseObserver, HierarchicalTableApplyResponse.getDefaultInstance());
return transformedResult;
});
}
}
private static void validate(@NotNull final HierarchicalTableApplyRequest request) {
GrpcErrorHelper.checkHasField(request, HierarchicalTableApplyRequest.RESULT_HIERARCHICAL_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasField(request, HierarchicalTableApplyRequest.INPUT_HIERARCHICAL_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasNoUnknownFields(request);
Common.validate(request.getResultHierarchicalTableId());
Common.validate(request.getInputHierarchicalTableId());
}
@NotNull
private static List makeWhereFilters(
@NotNull final Collection finishedConditions,
@NotNull final TableDefinition nodeDefinition) {
return finishedConditions.stream()
.map(condition -> FilterFactory.makeFilter(nodeDefinition, condition))
.collect(Collectors.toList());
}
@Nullable
private static Collection translateAndValidateSorts(
@NotNull final HierarchicalTableApplyRequest request,
@NotNull final BaseGridAttributes, ?> inputHierarchicalTable) {
if (request.getSortsCount() == 0) {
return null;
}
final Collection translatedSorts = request.getSortsList().stream()
.map(HierarchicalTableServiceGrpcImpl::translateSort)
.collect(Collectors.toList());
final Set sortableColumnNames = inputHierarchicalTable.getSortableColumns();
if (sortableColumnNames != null) {
if (sortableColumnNames.isEmpty()) {
throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
"Sorting is not supported on this hierarchical table");
}
final Collection unavailableSortColumnNames = translatedSorts.stream()
.map(sc -> AbsoluteSortColumnConventions.stripAbsoluteColumnName(sc.column().name()))
.filter(scn -> !sortableColumnNames.contains(scn))
.collect(Collectors.toList());
if (!unavailableSortColumnNames.isEmpty()) {
throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
"Sorting attempted on restricted column(s): "
+ unavailableSortColumnNames.stream().collect(Collectors.joining(", ", "[", "]"))
+ ", available column(s) for sorting are: "
+ sortableColumnNames.stream().collect(Collectors.joining(", ", "[", "]")));
}
}
return translatedSorts;
}
private static SortColumn translateSort(@NotNull final SortDescriptor sortDescriptor) {
switch (sortDescriptor.getDirection()) {
case DESCENDING:
return SortColumn.desc(ColumnName.of(sortDescriptor.getIsAbsolute()
? baseColumnNameToAbsoluteName(sortDescriptor.getColumnName())
: sortDescriptor.getColumnName()));
case ASCENDING:
return SortColumn.asc(ColumnName.of(sortDescriptor.getIsAbsolute()
? baseColumnNameToAbsoluteName(sortDescriptor.getColumnName())
: sortDescriptor.getColumnName()));
case UNKNOWN:
case REVERSE:
default:
throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT,
"Unsupported or unknown sort direction: " + sortDescriptor.getDirection());
}
}
@Override
public void view(
@NotNull final HierarchicalTableViewRequest request,
@NotNull final StreamObserver responseObserver) {
validate(request);
final SessionState session = sessionService.getCurrentSession();
final boolean usedExisting;
final Ticket targetTicket;
switch (request.getTargetCase()) {
case HIERARCHICAL_TABLE_ID:
usedExisting = false;
targetTicket = request.getHierarchicalTableId();
break;
case EXISTING_VIEW_ID:
usedExisting = true;
targetTicket = request.getExistingViewId();
break;
case TARGET_NOT_SET:
default:
throw Exceptions.statusRuntimeException(Code.INVALID_ARGUMENT, "No target specified");
}
final String description = "HierarchicalTableService#view(table="
+ ticketRouter.getLogNameFor(targetTicket, "targetTableId") + ")";
final QueryPerformanceRecorder queryPerformanceRecorder = QueryPerformanceRecorder.newQuery(
description, session.getSessionId(), QueryPerformanceNugget.DEFAULT_FACTORY);
try (final SafeCloseable ignored = queryPerformanceRecorder.startQuery()) {
final SessionState.ExportBuilder resultExportBuilder =
session.newExport(request.getResultViewId(), "resultViewId");
final SessionState.ExportObject> targetExport =
ticketRouter.resolve(session, targetTicket, "targetTableId");
final SessionState.ExportObject keyTableExport;
if (request.hasExpansions()) {
keyTableExport = ticketRouter.resolve(
session, request.getExpansions().getKeyTableId(), "expansions.keyTableId");
resultExportBuilder.require(targetExport, keyTableExport);
} else {
keyTableExport = null;
resultExportBuilder.require(targetExport);
}
resultExportBuilder
.queryPerformanceRecorder(queryPerformanceRecorder)
.onError(responseObserver)
.submit(() -> {
final Table keyTable = keyTableExport == null ? null : keyTableExport.get();
final Object target = targetExport.get();
final HierarchicalTableView targetExistingView = usedExisting
? (HierarchicalTableView) target
: null;
final HierarchicalTable> targetHierarchicalTable = usedExisting
? targetExistingView.getHierarchicalTable()
: (HierarchicalTable>) target;
authWiring.checkPermissionView(session.getAuthContext(), request, keyTable == null
? List.of(targetHierarchicalTable.getSource())
: List.of(keyTable, targetHierarchicalTable.getSource()));
final HierarchicalTableView result;
if (usedExisting) {
if (keyTable != null) {
result = HierarchicalTableView.makeFromExistingView(
targetExistingView,
keyTable,
request.getExpansions().hasKeyTableActionColumn()
? ColumnName.of(request.getExpansions().getKeyTableActionColumn())
: null);
} else {
result = HierarchicalTableView.makeFromExistingView(targetExistingView);
}
} else {
if (keyTable != null) {
result = HierarchicalTableView.makeFromHierarchicalTable(
targetHierarchicalTable,
keyTable,
request.getExpansions().hasKeyTableActionColumn()
? ColumnName.of(request.getExpansions().getKeyTableActionColumn())
: null);
} else {
result = HierarchicalTableView.makeFromHierarchicalTable(targetHierarchicalTable);
}
}
final HierarchicalTableView transformedResult = authTransformation.transform(result);
if (transformedResult == null) {
throw Exceptions.statusRuntimeException(
Code.FAILED_PRECONDITION, "Not authorized to view hierarchical table");
}
safelyComplete(responseObserver, HierarchicalTableViewResponse.getDefaultInstance());
return transformedResult;
});
}
}
private static void validate(@NotNull final HierarchicalTableViewRequest request) {
GrpcErrorHelper.checkHasField(request, HierarchicalTableViewRequest.RESULT_VIEW_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasOneOf(request, "target");
GrpcErrorHelper.checkHasNoUnknownFields(request);
switch (request.getTargetCase()) {
case HIERARCHICAL_TABLE_ID:
Common.validate(request.getHierarchicalTableId());
break;
case EXISTING_VIEW_ID:
Common.validate(request.getExistingViewId());
break;
case TARGET_NOT_SET:
// noinspection ThrowableNotThrown
Assert.statementNeverExecuted("No target specified, despite prior validation");
break;
default:
throw Exceptions.statusRuntimeException(Code.INTERNAL, String.format("%s has unexpected target case %s",
request.getDescriptorForType().getFullName(), request.getTargetCase()));
}
}
@Override
public void exportSource(
@NotNull final HierarchicalTableSourceExportRequest request,
@NotNull final StreamObserver responseObserver) {
validate(request);
final SessionState session = sessionService.getCurrentSession();
final String description = "HierarchicalTableService#exportSource(table="
+ ticketRouter.getLogNameFor(request.getHierarchicalTableId(), "hierarchicalTableId") + ")";
final QueryPerformanceRecorder queryPerformanceRecorder = QueryPerformanceRecorder.newQuery(
description, session.getSessionId(), QueryPerformanceNugget.DEFAULT_FACTORY);
try (final SafeCloseable ignored = queryPerformanceRecorder.startQuery()) {
final SessionState.ExportObject> hierarchicalTableExport =
ticketRouter.resolve(session, request.getHierarchicalTableId(), "hierarchicalTableId");
session.newExport(request.getResultTableId(), "resultTableId")
.queryPerformanceRecorder(queryPerformanceRecorder)
.require(hierarchicalTableExport)
.onError(responseObserver)
.submit(() -> {
final HierarchicalTable> hierarchicalTable = hierarchicalTableExport.get();
final Table result = hierarchicalTable.getSource();
authWiring.checkPermissionExportSource(session.getAuthContext(), request, List.of(result));
final Table transformedResult = authTransformation.transform(result);
if (transformedResult == null) {
throw Exceptions.statusRuntimeException(
Code.FAILED_PRECONDITION,
"Not authorized to export source from hierarchical table");
}
final ExportedTableCreationResponse response =
ExportUtil.buildTableCreationResponse(request.getResultTableId(), transformedResult);
safelyComplete(responseObserver, response);
return transformedResult;
});
}
}
private static void validate(@NotNull final HierarchicalTableSourceExportRequest request) {
GrpcErrorHelper.checkHasField(request, HierarchicalTableSourceExportRequest.RESULT_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasField(request, HierarchicalTableSourceExportRequest.HIERARCHICAL_TABLE_ID_FIELD_NUMBER);
GrpcErrorHelper.checkHasNoUnknownFields(request);
Common.validate(request.getResultTableId());
Common.validate(request.getHierarchicalTableId());
}
}