Repository: nifi-minifi-cpp Updated Branches: refs/heads/master 19881b63b -> c05d46775
MINIFICPP-366 Added docs for expression language This closes #249. Signed-off-by: Aldrin Piri <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/commit/c05d4677 Tree: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/tree/c05d4677 Diff: http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/diff/c05d4677 Branch: refs/heads/master Commit: c05d467758c861f38a00c6ac5f64f75d6ca0ce05 Parents: 19881b6 Author: Andrew I. Christianson <[email protected]> Authored: Mon Jan 22 11:44:53 2018 -0500 Committer: Aldrin Piri <[email protected]> Committed: Tue Jan 23 20:43:31 2018 -0500 ---------------------------------------------------------------------- EXPRESSIONS.md | 754 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 6 +- 2 files changed, 759 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c05d4677/EXPRESSIONS.md ---------------------------------------------------------------------- diff --git a/EXPRESSIONS.md b/EXPRESSIONS.md new file mode 100644 index 0000000..a0a7df4 --- /dev/null +++ b/EXPRESSIONS.md @@ -0,0 +1,754 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +# MiNiFi - C++ Expression Language + +Apache NiFi - MiNiFi - C++ supports a subset of the [Apache NiFi Expression +Language](https://nifi.apache.org/docs/nifi-docs/html/expression-language-guide.html) +(EL). EL is a tiny DSL enabling processor property values to be computed +dynamically according to contextual information such as FlowFile attributes. +Dynamic values may be manipulated by a number of functions supported by EL, +including boolean logic, string manipulation, encoding/decoding, searching, +mathematical operators, date manipulation, type coercion, and more. +Processors/properties supporting EL are marked in the [processors +documentation](PROCESSORS.md). + +## Overview + +All data in Apache NiFi is represented by an abstraction called a FlowFile. A +FlowFile comprises two major pieces: content and attributes. The content +portion of the FlowFile represents the data on which to operate. For instance, +if a file is picked up from a local file system using the GetFile Processor, +the contents of the file will become the contents of the FlowFile. + +The attributes portion of the FlowFile represents information about the data +itself, or metadata. Attributes are key-value pairs that represent what is +known about the data as well as information that is useful for routing and +processing the data appropriately. Keeping with the example of a file that is +picked up from a local file system, the FlowFile would have an attribute called +`filename` that reflected the name of the file on the file system. +Additionally, the FlowFile will have a `path` attribute that reflects the +directory on the file system that this file lived in. The FlowFile will also +have an attribute named `uuid`, which is a unique identifier for this FlowFile. +For complete listing of the core attributes check out the FlowFile section of +the Apache NiFi Developerâs Guide. + +However, placing these attributes on a FlowFile do not provide much benefit if +the user is unable to make use of them. The NiFi Expression Language provides +the ability to reference these attributes, compare them to other values, and +manipulate their values. + +## Structure of a NiFi Expression + +The NiFi Expression Language always begins with the start delimiter `${` and +ends with the end delimiter `}`. Between the start and end delimiters is the +text of the Expression itself. In its most basic form, the Expression can +consist of just an attribute name. For example, `${filename}` will return the +value of the `filename` attribute. + +In a slightly more complex example, we can instead return a manipulation of +this value. We can, for example, return an all upper-case version of the +filename by calling the `toUpper` function: `${filename:toUpper()}`. In this +case, we reference the `filename` attribute and then manipulate this value by +using the `toUpper` function. A function call consists of 5 elements. First, +there is a function call delimiter `:`. Second is the name of the function --in +this case, `toUpper`. Next is an open parenthesis (`(`), followed by the +function arguments. The arguments necessary are dependent upon which function +is being called. In this example, we are using the `toUpper` function, which +does not have any arguments, so this element is omitted. Finally, the closing +parenthesis (`)`) indicates the end of the function call. There are many +different functions that are supported by the Expression Language to achieve +many different goals. Some functions provide String (text) manipulation, such +as the `toUpper` function. Others, such as the equals and matches functions, +provide comparison functionality. Functions also exist for manipulating dates +and times and for performing mathematical operations. Each of these functions +is described below, in the Functions section, with an explanation of what the +function does, the arguments that it requires, and the type of information that +it returns. + +When we perform a function call on an attribute, as above, we refer to the +attribute as the subject of the function, as the attribute is the entity on +which the function is operating. We can then chain together multiple function +calls, where the return value of the first function becomes the subject of the +second function and its return value becomes the subject of the third function +and so on. Continuing with our example, we can chain together multiple +functions by using an expression similar to +`${filename:toUpper():equals('HELLO.TXT')}`. There is no limit to the number +of functions that can be chained together. + +Any FlowFile attribute can be referenced using the Expression Language. +However, if the attribute name contains a special character, the attribute +name must be escaped by quoting it. The following characters are each +considered special characters: + +- `$` (dollar sign) +- `|` (pipe) +- `{` (open brace) +- `}` (close brace) +- `(` (open parenthesis) +- `)` (close parenthesis) +- `[` (open bracket) +- `]` (close bracket) +- `,` (comma) +- `:` (colon) +- `;` (semicolon) +- `/` (forward slash) +- `*` (asterisk) +- `'` (single quote) +- ` ` (space) +- `\t` (tab) +- `\r` (carriage return) +- `\n` (new-line) + +Additionally, a number is considered a special character if it is the first +character of the attribute name. If any of these special characters is present +in an attribute is quoted by using either single or double quotes. The +Expression Language allows single quotes and double quotes to be used +interchangeably. For example, the following can be used to escape an attribute +named my attribute: `${"my attribute"}` or `${'my attribute'}`. + +In this example, the value to be returned is the value of the "my attribute" +value, if it exists. If that attribute does not exist, the Expression Language +will then look for a System Environment Variable named "my attribute." Finally, +if none of these exists, the Expression Language will return a null value. + +There also exist some functions that expect to have no subject. These functions +are invoked simply by calling the function at the beginning of the Expression, +such as `${hostname()}`. These functions can then be changed together, as well. +For example, `${hostname():toUpper()}`. Attempting to evaluate the function with +subject will result in an error. In the Functions section below, these +functions will clearly indicate in their descriptions that they do not require +a subject. + +Often times, we will need to compare the values of two different attributes to +each other. We are able to accomplish this by using embedded Expressions. We +can, for example, check if the filename attribute is the same as the uuid +attribute: `${filename:equals( ${uuid} )}`. Notice here, also, that we have a +space between the opening parenthesis for the equals method and the embedded +Expression. This is not necessary and does not affect how the Expression is +evaluated in any way. Rather, it is intended to make the Expression easier to +read. White space is ignored by the Expression Language between delimiters. +Therefore, we can use the Expression `${ filename : equals(${ uuid}) }` or +`${filename:equals(${uuid})}` and both Expressions mean the same thing. We +cannot, however, use `${file name:equals(${uuid})}`, because this results in +file and name being interpreted as different tokens, rather than a single +token, filename. + +## Supported Features + +### String Manipulation + +- [`toUpper`](#toupper) +- [`toLower`](#tolower) +- [`substring`](#substring) +- [`substringBefore`](#substringbefore) +- [`substringBeforeLast`](#substringbeforelast) +- [`substringAfter`](#substringafter) +- [`substringAfterLast`](#substringafterlast) +- [`replace`](#replace) +- [`replaceFirst`](#replacefirst) +- [`replaceAll`](#replaceall) +- [`replaceNull`](#replacenull) +- [`replaceEmpty`](#replaceempty) + +### Mathematical Operations and Numeric Manipulation + +- [`plus`](#plus) +- [`minus`](#minus) +- [`multiply`](#multiply) +- [`divide`](#divide) +- [`mod`](#mod) +- [`toRadix`](#toradix) +- [`fromRadix`](#fromradix) +- [`random`](#random) + +## Planned Features + +### String Manipulation + +- `trim` +- `getDelimitedField` +- `append` +- `prepend` +- `length` + +### Boolean Logic + +- `isNull` +- `notNull` +- `isEmpty` +- `equals` +- `equalsIgnoreCase` +- `gt` +- `ge` +- `lt` +- `le` +- `and` +- `or` +- `not` +- `ifElse` + +### Encode/Decode Functions + +- `escapeJson` +- `escapeXml` +- `escapeCsv` +- `escapeHtml3` +- `escapeHtml4` +- `unescapeJson` +- `unescapeXml` +- `unescapeCsv` +- `unescapeHtml3` +- `unescapeHtml4` +- `urlEncode` +- `urlDecode` +- `base64Encode` +- `base64Decode` + +### Encode/Decode Functions + +- `escapeJson` +- `escapeXml` +- `escapeCsv` +- `escapeHtml3` +- `escapeHtml4` +- `unescapeJson` +- `unescapeXml` +- `unescapeCsv` +- `unescapeHtml3` +- `unescapeHtml4` +- `urlEncode` +- `urlDecode` +- `base64Encode` +- `base64Decode` + +### Date Manipulation + +- `format` +- `toDate` +- `now` + +### Subjectless Functions + +- `ip` +- `hostname` +- `UUID` +- `nextInt` +- `literal` +- `getStateValue` + +### Evaluating Multiple Attributes + +- `anyAttribute` +- `allAttributes` +- `anyMatchingAttribute` +- `allMatchingAttributes` +- `anyDelineatedValue` +- `allDelineatedValues` +- `join` +- `count` + +## Unsupported Features + +The following EL features are currently not supported, and no support is +planned due to language/environment (Java vs. C++) differences: + +### Mathematical Operations and Numeric Manipulation + +- `math ` + +## String Manipulation + +Each of the following functions manipulates a String in some way. + +### toUpper + +**Description**: This function converts the Subject into an all upper-case +String. Said another way, it replaces any lowercase letter with the uppercase +equivalent. + +**Subject Type**: String + +**Arguments**: No arguments + +**Return Type**: String + +**Examples**: If the `filename` attribute is `abc123.txt`, then the Expression +`${filename:toUpper()}` will return `ABC123.TXT` + +### toLower + +**Description**: This function converts the Subject into an all lower-case +String. Said another way, it replaces any uppercase letter with the lowercase +equivalent. + +**Subject Type**: String + +**Arguments**: No arguments + +**Return Type**: String + +**Examples**: If the `filename` attribute is `ABC123.TXT`, then the Expression +`${filename:toLower()}` will return `abc123.txt` + +### substring + +**Description**: Returns a portion of the Subject, given a starting index and +an optional ending index. If the ending index is not supplied, it will return +the portion of the Subject starting at the given 'start index' and ending at +the end of the Subject value. + +The starting index and ending index are zero-based. That is, the first +character is referenced by using the value 0, not 1. + +If either the starting index is or the ending index is not a number, this +function call will result in an error. + +If the starting index is larger than the ending index, this function call will +result in an error. + +If the starting index or the ending index is greater than the length of the +Subject or has a value less than 0, this function call will result in an error. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| starting index | The 0-based index of the first character to capture (inclusive) | +| ending index | The 0-based index of the last character to capture (exclusive) | + +**Return Type**: String + +**Examples**: + +If we have an attribute named `filename` with the value `a brand new +filename.txt`, then the following Expressions will result in the following +values: + +| Expression | Value | +| - | - | +| `${filename:substring(0,1)}` | a | +| `${filename:substring(2)}` | brand new filename.txt | +| `${filename:substring(12)}` | filename.txt | +| `${filename:substring( ${filename:length():minus(2)} )}` | xt | + +### substringBefore + +**Description**: Returns a portion of the Subject, starting with the first +character of the Subject and ending with the character immediately before the +first occurrence of the argument. If the argument is not present in the +Subject, the entire Subject will be returned. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| value | The String to search for in the Subject | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will result in the following +values: + +| Expression | Value | +| - | - | +| `${filename:substringBefore('.')}` | a brand new filename | +| `${filename:substringBefore(' ')}` | a | +| `${filename:substringBefore(' n')}` | a brand | +| `${filename:substringBefore('missing')}` | a brand new filename.txt | + +### substringBeforeLast + +**Description**: Returns a portion of the Subject, starting with the first +character of the Subject and ending with the character immediately before the +last occurrence of the argument. If the argument is not present in the Subject, +the entire Subject will be returned. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| value | The String to search for in the Subject | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will result in the following +values: + +| Expression | Value | +| - | - | +| `${filename:substringBeforeLast('.')}` | a brand new filename | +| `${filename:substringBeforeLast(' ')}` | a brand new | +| `${filename:substringBeforeLast(' n')}` | a brand | +| `${filename:substringBeforeLast('missing')}` | a brand new filename.txt | + +### substringAfter + +**Description**: Returns a portion of the Subject, starting with the character +immediately after the first occurrence of the argument and extending to the end +of the Subject. If the argument is not present in the Subject, the entire +Subject will be returned. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| value | The String to search for in the Subject | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will result in the following +values: + +| Expression | Value | +| - | - | +| `${filename:substringAfter('.')}` | txt | +| `${filename:substringAfter(' ')}` | brand new filename.txt | +| `${filename:substringAfter(' n')}` | ew filename.txt | +| `${filename:substringAfter('missing')}` | a brand new filename.txt | + +### substringAfterLast + +**Description**: Returns a portion of the Subject, starting with the character +immediately after the last occurrence of the argument and extending to the end +of the Subject. If the argument is not present in the Subject, the entire +Subject will be returned. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| value | The String to search for in the Subject | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will result in the following +values: + +| Expression | Value | +| - | - | +| `${filename:substringAfterLast('.')}` | txt | +| `${filename:substringAfterLast(' ')}` | filename.txt | +| `${filename:substringAfterLast(' n')}` | ew filename.txt | +| `${filename:substringAfterLast('missing')}` | a brand new filename.txt | + +### replace + +**Description**: Replaces all occurrences of one literal String within the Subject +with another String. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| Search String | The String to find within the Subject | +| Replacement | The value to replace Search String with | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will provide the following +results: + +| Expression | Value | +| - | - | +| `${filename:replace('.', '_')}` | a brand new filename_txt | +| `${filename:replace(' ', '.')}` | a.brand.new.filename.txt | +| `${filename:replace('XYZ', 'ZZZ')}` | a brand new filename.txt | +| `${filename:replace('filename', 'book')}` | a brand new book.txt | + +### replaceFirst + +**Description**: Replaces the first occurrence of one literal String or regular +expression within the Subject with another String. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| Search String | The String (literal or regular expression pattern) to find within the Subject | +| Replacement | The value to replace Search String with | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will provide the following +results: + +| Expression | Value | +| - | - | +| `${filename:replaceFirst('a', 'the')}` | the brand new filename.txt | +| `${filename:replaceFirst('[br]', 'g')}` | a grand new filename.txt | +| `${filename:replaceFirst('XYZ', 'ZZZ')}` | a brand new filename.txt | +| `${filename:replaceFirst('\w{8}', 'book')}` | a brand new book.txt | + +### replaceAll + +**Description**: The replaceAll function takes two String arguments: a literal +String or Regular Expression (NiFi uses the Java Pattern syntax), and a +replacement string. The return value is the result of substituting the +replacement string for all patterns within the Subject that match the Regular +Expression. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| Regex | he Regular Expression (in Java syntax) to match in the Subject | +| Replacement | The value to use for replacing matches in the Subject. If the regular expression argument uses Capturing Groups, back references are allowed in the replacement. | + +**Return Type**: String + +**Examples**: If the `filename` attribute has the value `a brand new +filename.txt`, then the following Expressions will provide the following +results: + +| Expression | Value | +| - | - | +| `${filename:replaceAll('\..*', '')}` | a brand new filename | +| `${filename:replaceAll('a brand (new)', '$1')}` | new filename.txt | +| `${filename:replaceAll('XYZ', 'ZZZ')}` | a brand new filename.txt | +| `${filename:replaceAll('brand (new)', 'somewhat $1')}` | a somewhat new filename.txt | + +### replaceNull + +**Description**: The replaceNull function returns the argument if the Subject is +null. Otherwise, returns the Subject. + +**Subject Type**: Any + +**Arguments**: + +| Argument | Description | +| - | - | +| Replacement | The value to return if the Subject is null. | + +**Return Type**: Type of Subject if Subject is not null; else, type of Argument + +**Examples**: If the attribute `filename` has the value `a brand new filename.txt` and the attribute `hello` does not exist, then the Expression `${filename:replaceNull('abc')}` will return `a brand new filename.txt`, while `${hello:replaceNull('abc')}` will return `abc`. + +### replaceEmpty + +**Description**: The replaceEmpty function returns the argument if the Subject is +null or if the Subject consists only of white space (new line, carriage return, +tab, space). Otherwise, returns the Subject. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| Replacement | The value to return if the Subject is null or empty. | + +**Return Type**: String + +**Examples**: If the attribute `filename` has the value `a brand new +filename.txt` and the attribute `hello` has the value ` `, then the Expression +`${filename:replaceEmpty('abc')}` will return `a brand new filename.txt`, while +`${hello:replaceEmpty('abc')}` will return `abc`. + +## Mathematical Operations and Numeric Manipulation + +For those functions that support Decimal and Number (whole number) types, the +return value type depends on the input types. If either the subject or argument +are a Decimal then the result will be a Decimal. If both values are Numbers +then the result will be a Number. This includes Divide. This is to preserve +backwards compatibility and to not force rounding errors. + +### plus + +**Description**: Adds a numeric value to the Subject. If either the argument or the +Subject cannot be coerced into a Number, returns null. + +**Subject Type**: Number or Decimal + +**Arguments**: + +| Argument | Description | +| - | - | +| Operand | The value to add to the Subject | + +**Return Type**: Number or Decimal (depending on input types) + +**Examples**: If the `fileSize` attribute has a value of 100, then the +Expression `${fileSize:plus(1000)}` will return the value 1100. + +### minus + +**Description**: Subtracts a numeric value from the Subject. + +**Subject Type**: Number or Decimal + +**Arguments**: + +| Argument | Description | +| - | - | +| Operand | The value to subtract from the Subject | + +**Return Type**: Number or Decimal (depending on input types) + +**Examples**: If the `fileSize` attribute has a value of 100, then the +Expression `${fileSize:minus(100)}` will return the value 0. + +### multiply + +**Description**: Multiplies a numeric value by the Subject and returns the product. + +**Subject Type**: Number or Decimal + +**Arguments**: + +| Argument | Description | +| - | - | +| Operand | The value to multiple the Subject by | + +**Return Type**: Number or Decimal (depending on input types) + +**Examples**: If the `fileSize` attribute has a value of 100, then the +Expression `${fileSize:multiply(1024)}` will return the value 102400. + +### divide + +**Description**: Divides the Subject by a numeric value and returns the result. + +**Subject Type**: Number or Decimal + +**Arguments**: + +| Argument | Description | +| - | - | +| Operand | The value to divide the Subject by | + +**Return Type**: Number or Decimal (depending on input types) + +**Examples**: If the `fileSize` attribute has a value of 100, then the +Expression `${fileSize:divide(12)}` will return the value 8. + +### mod + +**Description**: Performs a modular division of the Subject by the argument. That +is, this function will divide the Subject by the value of the argument and +return not the quotient but rather the remainder. + +**Subject Type**: Number or Decimal + +**Arguments**: + +| Argument | Description | +| - | - | +| Operand | The value to divide the Subject by | + +**Return Type**: Number or Decimal (depending on input types) + +**Examples**: If the `fileSize` attribute has a value of 100, then the +Expression `${fileSize:mod(12)}` will return the value 4. + +### toRadix + +**Description**: Converts the Subject from a Base 10 number to a +different Radix (or number base). An optional second argument can be used to +indicate the minimum number of characters to be used. If the converted value +has fewer than this number of characters, the number will be padded with +leading zeroes. + +If a decimal is passed as the subject, it will first be converted to a whole +number and then processed. + +**Subject Type**: Number + +**Arguments**: + +| Argument | Description | +| - | - | +| Desired Base | A Number between 2 and 36 (inclusive) | +| Padding | Optional argument that specifies the minimum number of characters in the converted output | + +**Return Type**: String + +**Examples**: If the `fileSize` attributes has a value of 1024, then the +following Expressions will yield the following results: + +| Expression | Value | +| - | - | +| `${fileSize:toRadix(10)}` | 1024 | +| `${fileSize:toRadix(10, 1)}` | 1024 | +| `${fileSize:toRadix(10, 8)}` | 00001024 | +| `${fileSize:toRadix(16)}` | 400 | +| `${fileSize:toRadix(16, 8)}` | 00000400 | +| `${fileSize:toRadix(2)}` | 10000000000 | +| `${fileSize:toRadix(2, 16)}` | 0000010000000000 | + +### fromRadix + +**Description**: Converts the Subject from a specified Radix (or +number base) to a base ten whole number. The subject will converted as is, +without interpretation, and all characters must be valid for the base being +converted from. For example converting "0xFF" from hex will not work due to "x" +being a invalid hex character. + +If a decimal is passed as the subject, it will first be converted to a whole +number and then processed. + +**Subject Type**: String + +**Arguments**: + +| Argument | Description | +| - | - | +| Subject Base | A Number between 2 and 36 (inclusive) | + +**Return Type**: Number + +**Examples**: If the `fileSize` attributes has a value of 1234A, then the +following Expressions will yield the following results: + +| Expression | Value | +| - | - | +| `${fileSize:fromRadix(11)}` | 17720 | +| `${fileSize:fromRadix(16)}` | 74570 | +| `${fileSize:fromRadix(20)}` | 177290 | + +### random + +**Description**: Returns a random whole number (0 to 2^63 - 1) using an insecure +random number generator. + +**Subject Type**: No subject + +**Arguments**: No arguments + +**Return Type**: Number + +**Examples**: `${random():mod(10):plus(1)}` returns random number between 1 and 10 inclusive. http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/c05d4677/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md index 2c6fd41..6a7e584 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ MiNiFi is a child project effort of Apache NiFi. This repository is for a nativ Apache NiFi - MiNiFi C++ is a complementary data collection approach that supplements the core tenets of [NiFi](http://nifi.apache.org/) in dataflow management, focusing on the collection of data at the source of its creation. The C++ implementation is an additional implementation to the one in Java with the aim of an even smaller resource footprint. -Specific goals for MiNiFi are comprised of: +Specific goals for MiNiFi comprise: - small and lightweight footprint - central management of agents - generation of data provenance @@ -42,6 +42,10 @@ Specific goals for MiNiFi are comprised of: Perspectives of the role of MiNiFi should be from the perspective of the agent acting immediately at, or directly adjacent to, source sensors, systems, or servers. +### Expression Language + +A subset of the Apache NiFi [Expression Language](EXPRESSIONS.md) is supported. + ### Processors MiNiFi - C++ supports the following processors:
