Package com.orchestranetworks.addon.dpra.function

Provides classes and interfaces to create custom functions.

Sample code to create a custom function that queries data using SQL:

  1. 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()
                            {
                    
                            }
                    }
                    
  2. Register function:

                    FunctionDefinitionRegistry.register(CustomLowestValueFunction.DEFINITION, CustomLowestValueFunction.CHART_CONFIG);
                    

Sample code to create a custom function with linked records:

  1. 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()
                            {
                    
                            }
                    }
                    
  2. Register function:

                    FunctionDefinitionRegistry.register(CustomRecordCountFunction.DEFINITION, CustomRecordCountFunction.CHART_CONFIG);