Package com.orchestranetworks.addon.dpra.function
package com.orchestranetworks.addon.dpra.function
Provides classes and interfaces to create custom functions and execute registered functions (both built-in functions and custom functions).
Sample code to create a custom function that queries data using SQL:
-
Define function:
public final class CustomLowestValueFunction { private static final String OUTPUT_LOWEST_VALUE = "lowestValue"; private static final OutputDefinition LOWEST_VALUE_OUTPUT_DEF = OutputDefinition .forDecimal(OUTPUT_LOWEST_VALUE, UserMessage.createInfo("Lowest value"), null); public static final FunctionDefinition DEFINITION = FunctionDefinition .onField("CustomLowestValueFunction") .withLabel("Lowest value function") .withDescription("This function finds the lowest value for a numeric field.") .withOutputs(LOWEST_VALUE_OUTPUT_DEF) .onValidation(CustomLowestValueFunction::validate) .onExecution(CustomLowestValueFunction::execute) .build(); public static final ChartConfigForFunction CHART_CONFIG = ChartConfigForFunction .newBuilder(AxisConfig.outputLabelAsCategory(OUTPUT_LOWEST_VALUE)) .setDefaultChartType(ChartType.CARD) .addOtherChartTypes(ChartType.COLUMN) .build(); private static void validate(ValidationContextOnField context) throws InvalidFunctionException { final SchemaTypeName dataType = context.getCurrentField().getXsTypeName(); if (SchemaTypeName.XS_DECIMAL.equals(dataType) || SchemaTypeName.XS_INT.equals(dataType) || SchemaTypeName.XS_INTEGER.equals(dataType)) { return; } throw new InvalidFunctionException( UserMessage.createError("This function only applies for numeric fields.")); } private static FunctionResult execute(ExecutionContextOnField context) throws DPRAException { final SchemaNode field = context.getCurrentField(); final AdaptationTable table = context.getCurrentTable(); final String fieldName = getFieldNameForSql(field); final String tableName = getTableNameForSql(table); final String sql = "SELECT " + fieldName + " FROM " + tableName + " ORDER BY " + fieldName + " LIMIT 1"; final Query<Number> query = context.getCurrentDataset() .createQueryBuilder() .build(sql, Number.class); try (QueryResult<Number> result = query.getResult()) { final Iterator<Number> iterator = result.iterator(); // table has no records or all field values are null if (!iterator.hasNext()) { return FunctionResult.newInstance(); } final Number value = iterator.next(); if (value == null) { return FunctionResult.newInstance(); } final ValueSequence sequence = context.newValueSequence() .set(OUTPUT_LOWEST_VALUE, BigDecimal.valueOf(value.doubleValue())); return FunctionResult.of(sequence); } } private static String getFieldNameForSql(SchemaNode field) { return "\"" + field.getPathInAdaptation().getLastStep().format() + "\""; } private static String getTableNameForSql(AdaptationTable table) { return "\"" + table.getTablePath().format() + "\""; } private CustomLowestValueFunction() { } } -
Register function:
FunctionDefinitionRegistry.register(CustomLowestValueFunction.DEFINITION, CustomLowestValueFunction.CHART_CONFIG);
Sample code to create a custom function with linked records:
-
Define function:
public final class CustomRecordCountFunction { private static final String OUTPUT_COUNT = "recordCount"; private static final OutputDefinition COUNT_OUTPUT_DEF = OutputDefinition .forInteger(OUTPUT_COUNT, UserMessage.createInfo("Record count"), null); public static final FunctionDefinition DEFINITION = FunctionDefinition.onTable("CustomRecordCountFunction") .withLabel("Record count") .withDescription("This function counts the number of records in a table.") .withOutputs(COUNT_OUTPUT_DEF) .withLinkedRecord() .onExecution(CustomRecordCountFunction::execute) .build(); public static final ChartConfigForFunction CHART_CONFIG = ChartConfigForFunction .newBuilder(AxisConfig.outputLabelAsCategory(OUTPUT_COUNT)) .setDefaultChartType(ChartType.CARD) .addOtherChartTypes(ChartType.COLUMN) .build(); private static FunctionResult execute(ExecutionContextOnTable context) throws DPRAException { final AdaptationTable table = context.getCurrentTable(); final String xpathPredicate = context.getXpathFilterPredicate(); final boolean hasFilter = xpathPredicate != null && xpathPredicate.trim().length() > 0; try (RequestResult requestResult = hasFilter ? table.createRequestResult(xpathPredicate) : table.createRequest().execute()) { final int tableCount = requestResult.getSize(); final ValueSequence sequence = context.newValueSequence() .set(OUTPUT_COUNT, Integer.valueOf(tableCount)); if (context.isLinkedRecordEnabled()) { if (hasFilter) { sequence.linkWithRecords(xpathPredicate); } else { sequence.linkWithRecords(buildLinkedRecordXPathFilter(requestResult)); } } return FunctionResult.of(sequence); } } private static XPathFilter buildLinkedRecordXPathFilter(RequestResult requestResult) { final StringBuilder builder = new StringBuilder(); for (Adaptation record; (record = requestResult.nextAdaptation()) != null;) { if (builder.length() > 0) { builder.append(" or "); } builder.append(record.toXPathPredicateString()); } return XPathFilter.newFilter(builder.toString()); } private CustomRecordCountFunction() { } } -
Register function:
FunctionDefinitionRegistry.register(CustomRecordCountFunction.DEFINITION, CustomRecordCountFunction.CHART_CONFIG);
Sample code to execute a registered function:
The following example shows how to execute a previously registered function and read both scalar outputs and sequence outputs.
-
Acquire session:
Session session = ...; // implementation-specific -
Obtain function operations:
FunctionOperations ops = OperationsFactory.getInstance().getFunctionOperations(session); -
Build an asset context (table level example):
Adaptation dataset = ...; // retrieved dataset AdaptationTable table = dataset.getTable(Path.parse("/root/Brand")); AssetContextAdapter context = AssetContextAdapter.onTable(table); -
Execute the function by its code:
String functionCode = "CustomRecordCountFunction"; // or any registered code FunctionResult result = ops.execute(functionCode, context); -
Process outputs:
// Scalar (single-value) outputs for (FunctionValue value : result.getValues()) { System.out.println(value.getOutputName() + " = " + value.format()); } // Sequence (multi-row) outputs for (ValueSequence sequence : result.getSequences()) { for (FunctionValue value : sequence.getValues()) { System.out.println("[seq] " + value.getOutputName() + " = " + value.format()); } }
-
ClassDescriptionAdapter for representing asset contexts in the add-on.BaseFunctionDefinitionBuilder<T extends BaseFunctionDefinitionBuilder<T>>Base builder of
FunctionDefinitioninstances.A function declaration.Builder ofFunctionDefinitioninstances.Builder ofFunctionDefinitioninstances at the dataset level.Builder ofFunctionDefinitioninstances at the dataspace level.Builder ofFunctionDefinitioninstances at the field level.Builder ofFunctionDefinitioninstances at the table level.Builder ofFunctionDefinitioninstances at both the table and the field levels.Builder ofFunctionDefinitioninstances at the workflow level.Registers instances ofFunctionDefinition.Provides operations for executing functions in the add-on.Specifies the input definition of a function.Specifies the output definition of a function.