diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index 1c3b97fef0f11..9aacfdf0a8efa 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -170,6 +170,7 @@ jobs: ${{ env.MAVEN_VERIFY_COMMAND }} ${{ env.MAVEN_BUILD_PROFILES }} -P report-code-coverage + -P python-unit-tests ${{ env.MAVEN_PROJECTS }} - name: Codecov uses: codecov/codecov-action@v3 @@ -238,6 +239,7 @@ jobs: ${{ env.MAVEN_COMMAND }} ${{ env.MAVEN_VERIFY_COMMAND }} ${{ env.MAVEN_BUILD_PROFILES }} + -P python-unit-tests ${{ env.MAVEN_PROJECTS }} - name: Upload Test Reports uses: actions/upload-artifact@v3 diff --git a/.gitignore b/.gitignore index 2e9685e07b608..f45e08f9fcff5 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ nb-configuration.xml .vscode/ .java-version /nifi-nar-bundles/nifi-py4j-bundle/nifi-python-extension-api/src/main/python/dist/ +__pycache__ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index eacdc9ed17a17..346d645fd06fd 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentInfo.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentInfo.java index 5660b8c2eb77c..24c02a7c6430d 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentInfo.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentInfo.java @@ -17,13 +17,11 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.c2.protocol.component.api.RuntimeManifest; import java.io.Serializable; -@ApiModel public class AgentInfo implements Serializable { private static final long serialVersionUID = 1L; @@ -33,10 +31,7 @@ public class AgentInfo implements Serializable { private RuntimeManifest agentManifest; private AgentStatus status; - @ApiModelProperty( - value = "A unique identifier for the Agent", - notes = "Usually set when the agent is provisioned and deployed", - required = true) + @Schema(description = "A unique identifier for the Agent. Usually set when the agent is provisioned and deployed") public String getIdentifier() { return identifier; } @@ -45,9 +40,7 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } - @ApiModelProperty( - value = "The class or category label of the agent, e.g., 'sensor-collector'", - notes = "Usually set when the agent is provisioned and deployed") + @Schema(description = "The class or category label of the agent, e.g., 'sensor-collector'. Usually set when the agent is provisioned and deployed") public String getAgentClass() { return agentClass; } @@ -56,7 +49,7 @@ public void setAgentClass(String agentClass) { this.agentClass = agentClass; } - @ApiModelProperty("The hash code of the manifest definition generated by the agent.") + @Schema(description = "The hash code of the manifest definition generated by the agent.") public String getAgentManifestHash() { return this.agentManifestHash; } @@ -65,7 +58,7 @@ public void setAgentManifestHash(String agentManifestHash) { this.agentManifestHash = agentManifestHash; } - @ApiModelProperty("The specification of the agent's capabilities") + @Schema(description = "The specification of the agent's capabilities") public RuntimeManifest getAgentManifest() { return agentManifest; } @@ -74,7 +67,7 @@ public void setAgentManifest(RuntimeManifest runtimeManifest) { this.agentManifest = runtimeManifest; } - @ApiModelProperty("A summary of the runtime status of the agent") + @Schema(description = "A summary of the runtime status of the agent") public AgentStatus getStatus() { return status; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentManifest.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentManifest.java index 3263fd38896b9..e8d527394b313 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentManifest.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentManifest.java @@ -17,17 +17,16 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.util.Objects; import java.util.Set; + +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.c2.protocol.component.api.RuntimeManifest; -@ApiModel public class AgentManifest extends RuntimeManifest { private static final long serialVersionUID = 1L; - @ApiModelProperty("All supported operations by agent") + @Schema(description = "All supported operations by agent") private Set supportedOperations; public AgentManifest() { diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositories.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositories.java index aa6eb5e37e9d0..cdabb182272fc 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositories.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositories.java @@ -17,18 +17,14 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; -@ApiModel public class AgentRepositories implements Serializable { private static final long serialVersionUID = 1L; private AgentRepositoryStatus flowFile; private AgentRepositoryStatus provenance; - @ApiModelProperty public AgentRepositoryStatus getFlowFile() { return flowFile; } @@ -37,7 +33,6 @@ public void setFlowFile(AgentRepositoryStatus flowFile) { this.flowFile = flowFile; } - @ApiModelProperty public AgentRepositoryStatus getProvenance() { return provenance; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositoryStatus.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositoryStatus.java index 2b91b0ae475aa..b4e8fa2460a12 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositoryStatus.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentRepositoryStatus.java @@ -17,12 +17,10 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; -@ApiModel public class AgentRepositoryStatus implements Serializable { private static final long serialVersionUID = 1L; @@ -31,7 +29,7 @@ public class AgentRepositoryStatus implements Serializable { private Long dataSize; private Long dataSizeMax; - @ApiModelProperty(value = "The number of items in the repository", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The number of items in the repository", allowableValues = "range[0, 9223372036854775807]") public Long getSize() { return size; } @@ -40,7 +38,7 @@ public void setSize(Long size) { this.size = size; } - @ApiModelProperty(value = "The maximum number of items the repository is capable of storing", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The maximum number of items the repository is capable of storing", allowableValues = "range[0, 9223372036854775807]") public Long getSizeMax() { return sizeMax; } @@ -49,7 +47,7 @@ public void setSizeMax(Long sizeMax) { this.sizeMax = sizeMax; } - @ApiModelProperty(value = "The data size (in Bytes) of all items in the repository", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The data size (in Bytes) of all items in the repository", allowableValues = "range[0, 9223372036854775807]") public Long getDataSize() { return dataSize; } @@ -58,7 +56,7 @@ public void setDataSize(Long dataSize) { this.dataSize = dataSize; } - @ApiModelProperty(value = "The maximum data size (in Bytes) that the repository is capable of storing", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The maximum data size (in Bytes) that the repository is capable of storing", allowableValues = "range[0, 9223372036854775807]") public Long getDataSizeMax() { return dataSizeMax; } @@ -75,7 +73,7 @@ public void setDataSizeMax(Long dataSizeMax) { * * @return a decimal between [0, 1] representing the sizeMax utilization percentage */ - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public Double getSizeUtilization() { return size != null && sizeMax != null && sizeMax > 0 ? (double) size / (double) sizeMax : null; } @@ -86,7 +84,7 @@ public Double getSizeUtilization() { * * @return a decimal between [0, 1] representing the dataSizeMax utilization percentage */ - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public Double getDataSizeUtilization() { return dataSize != null && dataSizeMax != null && dataSizeMax > 0 ? (double) dataSize / (double) dataSizeMax : null; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentResourceConsumption.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentResourceConsumption.java index 2ceb170564808..47e72bd7e373e 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentResourceConsumption.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentResourceConsumption.java @@ -17,21 +17,20 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; /** * Resource consumption of the given agent */ -@ApiModel public class AgentResourceConsumption implements Serializable { private static final long serialVersionUID = 1L; private Long memoryUsage; private Double cpuUtilization; - @ApiModelProperty("The memory footprint of the agent in bytes.") + @Schema(description = "The memory footprint of the agent in bytes.") public Long getMemoryUsage() { return memoryUsage; } @@ -40,7 +39,7 @@ public void setMemoryUsage(Long memoryUsage) { this.memoryUsage = memoryUsage; } - @ApiModelProperty("The CPU utilisation of the agent [0.0 - 1.0] and -1.0 in case of errors.") + @Schema(description = "The CPU utilisation of the agent [0.0 - 1.0] and -1.0 in case of errors.") public Double getCpuUtilization() { return cpuUtilization; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentStatus.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentStatus.java index bb249617140c0..1d40294d5d5aa 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentStatus.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/AgentStatus.java @@ -17,8 +17,8 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Map; @@ -26,7 +26,6 @@ * Status of the aspects of the agent, including any agent components that are controllable by the C2 server, ie: * - Repositories that can be cleared and their current state */ -@ApiModel public class AgentStatus implements Serializable { private static final long serialVersionUID = 1L; @@ -35,7 +34,7 @@ public class AgentStatus implements Serializable { private Map components; private AgentResourceConsumption resourceConsumption; - @ApiModelProperty("The number of milliseconds since the agent started.") + @Schema(description = "The number of milliseconds since the agent started.") public Long getUptime() { return uptime; } @@ -44,7 +43,7 @@ public void setUptime(Long uptime) { this.uptime = uptime; } - @ApiModelProperty("Status and metrics for the agent repositories") + @Schema(description = "Status and metrics for the agent repositories") public AgentRepositories getRepositories() { return repositories; } @@ -53,7 +52,7 @@ public void setRepositories(AgentRepositories repositories) { this.repositories = repositories; } - @ApiModelProperty("Status for shared agent components (that is, components that exist outside the context of a specific flow).") + @Schema(description = "Status for shared agent components (that is, components that exist outside the context of a specific flow).") public Map getComponents() { return components; } @@ -62,7 +61,7 @@ public void setComponents(Map components) { this.components = components; } - @ApiModelProperty("Resource consumption details of the agent.") + @Schema(description = "Resource consumption details of the agent.") public AgentResourceConsumption getResourceConsumption() { return resourceConsumption; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Heartbeat.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Heartbeat.java index 4c69c51f7e467..e09760fe640b7 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Heartbeat.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Heartbeat.java @@ -17,8 +17,7 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Objects; @@ -26,7 +25,6 @@ /** * An object representation of a Heartbeat in the C2 protocol */ -@ApiModel public class C2Heartbeat implements Serializable { private static final long serialVersionUID = 1L; @@ -37,7 +35,7 @@ public class C2Heartbeat implements Serializable { private AgentInfo agentInfo; private FlowInfo flowInfo; - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getIdentifier() { return identifier; } @@ -46,7 +44,7 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public Long getCreated() { return created; } @@ -55,7 +53,7 @@ public void setCreated(Long created) { this.created = created; } - @ApiModelProperty("Metadata for the device") + @Schema(description = "Metadata for the device") public DeviceInfo getDeviceInfo() { return deviceInfo; } @@ -64,7 +62,7 @@ public void setDeviceInfo(DeviceInfo deviceInfo) { this.deviceInfo = deviceInfo; } - @ApiModelProperty("Metadata for the agent installed on the device") + @Schema(description = "Metadata for the agent installed on the device") public AgentInfo getAgentInfo() { return agentInfo; } @@ -73,7 +71,7 @@ public void setAgentInfo(AgentInfo agentInfo) { this.agentInfo = agentInfo; } - @ApiModelProperty("Metadata for the flow currently deployed to the agent") + @Schema(description = "Metadata for the flow currently deployed to the agent") public FlowInfo getFlowInfo() { return flowInfo; } @@ -83,22 +81,22 @@ public void setFlowInfo(FlowInfo flowInfo) { } // Convenience getters - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getDeviceId() { return deviceInfo != null ? deviceInfo.getIdentifier() : null; } - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getAgentId() { return agentInfo != null ? agentInfo.getIdentifier() : null; } - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getAgentClass() { return agentInfo != null ? agentInfo.getAgentClass() : null; } - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getAgentManifestId() { if (agentInfo != null && agentInfo.getAgentManifest() != null) { return agentInfo.getAgentManifest().getIdentifier(); @@ -106,7 +104,7 @@ public String getAgentManifestId() { return null; } - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getFlowId() { return flowInfo != null ? flowInfo.getFlowId() : null; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2HeartbeatResponse.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2HeartbeatResponse.java index 210504756e68b..4803b714fc548 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2HeartbeatResponse.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2HeartbeatResponse.java @@ -17,18 +17,14 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.util.List; -@ApiModel public class C2HeartbeatResponse implements Serializable { private static final long serialVersionUID = 1L; private List requestedOperations; - @ApiModelProperty public List getRequestedOperations() { return requestedOperations; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Operation.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Operation.java index a8c5edd7421d9..6dca210258909 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Operation.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2Operation.java @@ -17,8 +17,8 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Map; import java.util.Objects; @@ -26,7 +26,6 @@ import static java.lang.String.format; -@ApiModel public class C2Operation implements Serializable { private static final long serialVersionUID = 1L; @@ -36,7 +35,7 @@ public class C2Operation implements Serializable { private Map args; private Set dependencies; - @ApiModelProperty(value = "A unique identifier for the operation", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "A unique identifier for the operation", accessMode = Schema.AccessMode.READ_ONLY) public String getIdentifier() { return identifier; } @@ -45,7 +44,7 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } - @ApiModelProperty(value = "The type of operation", required = true) + @Schema(description = "The type of operation") public OperationType getOperation() { return operation; } @@ -58,13 +57,7 @@ public void setOperation(OperationType operation) { this.operation = operation; } - @ApiModelProperty( - value = "The primary operand of the operation", - notes = "This is an optional field which contains the name of the entity that is target of the operation. " + - "Most operations can be fully specified with zero or one operands." + - "If no operand is needed, this field will be absent." + - "If one operand is insufficient, the operation will contain an args map" + - "with additional keyword parameters and values (see 'args').") + @Schema(description = "The primary operand of the operation") public OperandType getOperand() { return operand; } @@ -77,8 +70,7 @@ public void setOperand(OperandType operand) { this.operand = operand; } - @ApiModelProperty(value = "If the operation requires arguments ", - notes = "This is an optional field and only provided when an operation has arguments " + + @Schema(description = "This is an optional field and only provided when an operation has arguments " + "in additional to the primary operand or optional parameters. Arguments are " + "arbitrary key-value pairs whose interpretation is subject to the context" + "of the operation and operand. For example, given:" + @@ -95,7 +87,7 @@ public void setArgs(Map args) { this.args = args; } - @ApiModelProperty("Optional set of operation ids that this operation depends on. " + + @Schema(description = "Optional set of operation ids that this operation depends on. " + "Executing this operation is conditional on the success of all dependency operations.") public Set getDependencies() { return dependencies; diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationAck.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationAck.java index d74967e34fe7f..08729e1b1f460 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationAck.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationAck.java @@ -17,29 +17,28 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Objects; -@ApiModel public class C2OperationAck implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty("The id of the requested operation that is being acknowledged") + @Schema(description = "The id of the requested operation that is being acknowledged") private String operationId; - @ApiModelProperty("The agent's status response for this operation ID") + @Schema(description = "The agent's status response for this operation ID") private C2OperationState operationState; // Optional, additional details that can be included in an ACK - @ApiModelProperty("Optionally, an ack can include device info that is relevant to the operation being acknowledged") + @Schema(description = "Optionally, an ack can include device info that is relevant to the operation being acknowledged") private DeviceInfo deviceInfo; - @ApiModelProperty("Optionally, an ack can include agent info that is relevant to the operation being acknowledged") + @Schema(description = "Optionally, an ack can include agent info that is relevant to the operation being acknowledged") private AgentInfo agentInfo; - @ApiModelProperty("Optionally, an ack can include flow info that is relevant to the operation being acknowledged") + @Schema(description = "Optionally, an ack can include flow info that is relevant to the operation being acknowledged") private FlowInfo flowInfo; diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationState.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationState.java index dc4e303e431dc..1e9c1e5bf24a5 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationState.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/C2OperationState.java @@ -17,8 +17,8 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Objects; @@ -33,16 +33,13 @@ * some insight, but a pre-condition and post-condition failure may better indicate how to arrive at operational * success. */ -@ApiModel public class C2OperationState implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "State of the operation performed", required = true, example = "FULLY_APPLIED") + @Schema(description = "State of the operation performed", example = "FULLY_APPLIED") private OperationState state; - @ApiModelProperty( - value = "Additional details about the state", - example = "Operation failed due to missing processor(s)") + @Schema(description = "Additional details about the state") private String details; public String getDetails() { diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/ComponentStatus.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/ComponentStatus.java index 172ea7f9f732c..e9303a718a505 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/ComponentStatus.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/ComponentStatus.java @@ -17,17 +17,13 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; -@ApiModel public class ComponentStatus implements Serializable { private static final long serialVersionUID = 1L; private Boolean running; - @ApiModelProperty public Boolean getRunning() { return running; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/DeviceInfo.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/DeviceInfo.java index 88d8be30f1097..85aa3fa471e14 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/DeviceInfo.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/DeviceInfo.java @@ -17,24 +17,21 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Objects; -@ApiModel public class DeviceInfo implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty( - value = "A unique, long-lived identifier for the device", - required = true) + @Schema(description = "A unique, long-lived identifier for the device") private String identifier; - @ApiModelProperty("Metadata for the device hardware and operating system") + @Schema(description = "Metadata for the device hardware and operating system") private SystemInfo systemInfo; - @ApiModelProperty("Metadata for the network interface of this device") + @Schema(description = "Metadata for the network interface of this device") private NetworkInfo networkInfo; public String getIdentifier() { diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowInfo.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowInfo.java index caf2626afc509..b6c9cc93ec1d6 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowInfo.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowInfo.java @@ -17,12 +17,11 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Map; -@ApiModel public class FlowInfo implements Serializable { private static final long serialVersionUID = 1L; @@ -31,7 +30,7 @@ public class FlowInfo implements Serializable { private Map components; private Map queues; - @ApiModelProperty(value = "A unique identifier of the flow currently deployed on the agent", required = true) + @Schema(description = "A unique identifier of the flow currently deployed on the agent") public String getFlowId() { return flowId; } @@ -40,7 +39,7 @@ public void setFlowId(String flowId) { this.flowId = flowId; } - @ApiModelProperty("The Uniform Resource Identifier (URI) for the flow") + @Schema(description = "The Uniform Resource Identifier (URI) for the flow") public FlowUri getFlowUri() { return flowUri; } @@ -49,7 +48,7 @@ public void setFlowUri(FlowUri flowUri) { this.flowUri = flowUri; } - @ApiModelProperty("Status and for each component that is part of the flow (e.g., processors)") + @Schema(description = "Status and for each component that is part of the flow (e.g., processors)") public Map getComponents() { return components; } @@ -58,7 +57,7 @@ public void setComponents(Map components) { this.components = components; } - @ApiModelProperty("Status and metrics for each flow connection queue") + @Schema(description = "Status and metrics for each flow connection queue") public Map getQueues() { return queues; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowQueueStatus.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowQueueStatus.java index 0d59267f510d1..5173185c076c0 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowQueueStatus.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowQueueStatus.java @@ -17,12 +17,10 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; -@ApiModel public class FlowQueueStatus implements Serializable { private static final long serialVersionUID = 1L; @@ -31,7 +29,7 @@ public class FlowQueueStatus implements Serializable { private Long dataSize; private Long dataSizeMax; - @ApiModelProperty(value = "The number of flow files in the queue", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The number of flow files in the queue", allowableValues = "range[0, 9223372036854775807]") public Long getSize() { return size; } @@ -40,7 +38,7 @@ public void setSize(Long size) { this.size = size; } - @ApiModelProperty(value = "The maximum number of flow files that the queue is configured to hold", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The maximum number of flow files that the queue is configured to hold", allowableValues = "range[0, 9223372036854775807]") public Long getSizeMax() { return sizeMax; } @@ -49,7 +47,7 @@ public void setSizeMax(Long sizeMax) { this.sizeMax = sizeMax; } - @ApiModelProperty(value = "The size (in Bytes) of all flow files in the queue", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The size (in Bytes) of all flow files in the queue", allowableValues = "range[0, 9223372036854775807]") public Long getDataSize() { return dataSize; } @@ -58,7 +56,7 @@ public void setDataSize(Long dataSize) { this.dataSize = dataSize; } - @ApiModelProperty(value = "The maximum size (in Bytes) that the queue is configured to hold", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "The maximum size (in Bytes) that the queue is configured to hold", allowableValues = "range[0, 9223372036854775807]") public Long getDataSizeMax() { return dataSizeMax; } @@ -75,7 +73,7 @@ public void setDataSizeMax(Long dataSizeMax) { * * @return a decimal between [0, 1] representing the sizeMax utilization percentage */ - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public Double getSizeUtilization() { return size != null && sizeMax != null && sizeMax > 0 ? (double) size / (double) sizeMax : null; } @@ -86,7 +84,7 @@ public Double getSizeUtilization() { * * @return a decimal between [0, 1] representing the dataSizeMax utilization percentage */ - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public Double getDataSizeUtilization() { return dataSize != null && dataSizeMax != null && dataSizeMax > 0 ? (double) dataSize / (double) dataSizeMax : null; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowUri.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowUri.java index 9c3d7cd584daf..e668161db7881 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowUri.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/FlowUri.java @@ -17,14 +17,12 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Objects; -@ApiModel( - value = "FlowUri", - description = "Uniform Resource Identifier for flows, used to uniquely identify a flow version ") +@Schema(description = "Uniform Resource Identifier for flows, used to uniquely identify a flow version") public class FlowUri implements Serializable { private static final long serialVersionUID = 1L; diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Location.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Location.java index da02e2fe5d144..b1f8f412b642c 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Location.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Location.java @@ -17,20 +17,14 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; - import java.io.Serializable; import java.util.Objects; -@ApiModel public class Location implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty private Double latitude; - @ApiModelProperty private Double longitude; public Double getLatitude() { diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/NetworkInfo.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/NetworkInfo.java index 17ea0b21652ef..f9a64d7bf1400 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/NetworkInfo.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/NetworkInfo.java @@ -17,21 +17,20 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; -@ApiModel public class NetworkInfo implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty("The device network interface ID") + @Schema(description = "The device network interface ID") private String deviceId; - @ApiModelProperty("The device network hostname") + @Schema(description = "The device network hostname") private String hostname; - @ApiModelProperty("The device network interface IP Address (v4 or v6)") + @Schema(description = "The device network interface IP Address (v4 or v6)") private String ipAddress; public String getDeviceId() { diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Operation.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Operation.java index 89f2c0e6028bf..3a1edd2909f6a 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Operation.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/Operation.java @@ -17,10 +17,8 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; -@ApiModel public class Operation extends C2Operation { private static final long serialVersionUID = 1L; @@ -32,7 +30,7 @@ public class Operation extends C2Operation { private Long created; private Long updated; - @ApiModelProperty("The identifier of the agent to which the operation applies") + @Schema(description = "The identifier of the agent to which the operation applies") public String getTargetAgentId() { return targetAgentId; } @@ -41,9 +39,7 @@ public void setTargetAgentId(String targetAgentId) { this.targetAgentId = targetAgentId; } - @ApiModelProperty( - value = "The current state of the operation", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The current state of the operation", accessMode = Schema.AccessMode.READ_ONLY) public OperationState getState() { return state; } @@ -52,7 +48,7 @@ public void setState(OperationState state) { this.state = state; } - @ApiModelProperty(hidden = true) + @Schema(hidden = true) public String getBulkOperationId() { return bulkOperationId; } @@ -61,11 +57,8 @@ public void setBulkOperationId(String bulkOperationId) { this.bulkOperationId = bulkOperationId; } - @ApiModelProperty(value = "The verified identity of the C2 client that created the operation", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, - notes = "This field is set by the server when an operation request is submitted to identify the origin. " + - "When the C2 instance is secured, this is the client principal identity (e.g., certificate DN). " + - "When the C2 instances is unsecured, this will be 'anonymous' as client identity can not be authenticated.") + @Schema(description = "The verified identity of the C2 client that created the operation", + accessMode = Schema.AccessMode.READ_ONLY) public String getCreatedBy() { return createdBy; } @@ -74,7 +67,7 @@ public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } - @ApiModelProperty("The time (in milliseconds since Epoch) that this operation was created") + @Schema(description = "The time (in milliseconds since Epoch) that this operation was created") public Long getCreated() { return created; } @@ -83,7 +76,7 @@ public void setCreated(Long created) { this.created = created; } - @ApiModelProperty("The time (in milliseconds since Epoch) that this operation was last updated") + @Schema(description = "The time (in milliseconds since Epoch) that this operation was last updated") public Long getUpdated() { return updated; } @@ -92,7 +85,7 @@ public void setUpdated(Long updated) { this.updated = updated; } - @ApiModelProperty(value = "Additional details about the state of this operation (such as an error message).") + @Schema(description = "Additional details about the state of this operation (such as an error message).") public String getDetails() { return details; } diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SupportedOperation.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SupportedOperation.java index ede22079a6cf4..b90e981b00a01 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SupportedOperation.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SupportedOperation.java @@ -17,20 +17,19 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Map; import java.util.Objects; -@ApiModel public class SupportedOperation implements Serializable { private static final long serialVersionUID = 1; - @ApiModelProperty("The type of the operation supported by the agent") + @Schema(description = "The type of the operation supported by the agent") private OperationType type; - @ApiModelProperty("Operand specific properties defined by the agent") + @Schema(description = "Operand specific properties defined by the agent") private Map> properties; public OperationType getType() { diff --git a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SystemInfo.java b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SystemInfo.java index cd07ef19b76e6..8371c6fcb20ca 100644 --- a/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SystemInfo.java +++ b/c2/c2-protocol/c2-protocol-api/src/main/java/org/apache/nifi/c2/protocol/api/SystemInfo.java @@ -17,34 +17,32 @@ package org.apache.nifi.c2.protocol.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; -@ApiModel public class SystemInfo implements Serializable { private static final long serialVersionUID = 1L; - @ApiModelProperty("Machine architecture of the device, e.g., ARM, x86") + @Schema(description = "Machine architecture of the device, e.g., ARM, x86") private String machineArch; private String operatingSystem; - @ApiModelProperty(value = "Size of physical memory of the device in bytes", allowableValues = "range[0, 9223372036854775807]") + @Schema(description = "Size of physical memory of the device in bytes", allowableValues = "range[0, 9223372036854775807]") private Long physicalMem; - @ApiModelProperty( - value = "Number of virtual cores on the device", + @Schema(description = "Number of virtual cores on the device", name = "vCores", allowableValues = "range[0, 2147483647]") private Integer vCores; - @ApiModelProperty + @Schema(description = "Memory usage") private Long memoryUsage; - @ApiModelProperty + @Schema(description = "CPU utilization") private Double cpuUtilization; + private Double cpuLoadAverage; public String getMachineArch() { diff --git a/c2/c2-protocol/c2-protocol-component-api/pom.xml b/c2/c2-protocol/c2-protocol-component-api/pom.xml index 36b982462828b..c281fd78d3683 100644 --- a/c2/c2-protocol/c2-protocol-component-api/pom.xml +++ b/c2/c2-protocol/c2-protocol-component-api/pom.xml @@ -31,7 +31,7 @@ limitations under the License. nifi-api - io.swagger + io.swagger.core.v3 swagger-annotations compile diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Attribute.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Attribute.java index d6155fdea4c1f..457162dfa8d6e 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Attribute.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Attribute.java @@ -16,16 +16,14 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; -@ApiModel public class Attribute { private String name; private String description; - @ApiModelProperty(value = "The name of the attribute") + @Schema(description = "The name of the attribute") public String getName() { return name; } @@ -34,7 +32,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the attribute") + @Schema(description = "The description of the attribute") public String getDescription() { return description; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/BuildInfo.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/BuildInfo.java index fe1e75f8316eb..4e25a46e62488 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/BuildInfo.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/BuildInfo.java @@ -17,11 +17,10 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; -@ApiModel public class BuildInfo implements Serializable { private static final long serialVersionUID = 1L; @@ -32,7 +31,7 @@ public class BuildInfo implements Serializable { private String compiler; private String compilerFlags; - @ApiModelProperty("The version number of the built component.") + @Schema(description = "The version number of the built component.") public String getVersion() { return version; } @@ -41,7 +40,7 @@ public void setVersion(String version) { this.version = version; } - @ApiModelProperty("The SCM revision id of the source code used for this build.") + @Schema(description = "The SCM revision id of the source code used for this build.") public String getRevision() { return revision; } @@ -50,7 +49,7 @@ public void setRevision(String revision) { this.revision = revision; } - @ApiModelProperty("The timestamp (milliseconds since Epoch) of the build.") + @Schema(description = "The timestamp (milliseconds since Epoch) of the build.") public Long getTimestamp() { return timestamp; } @@ -59,7 +58,7 @@ public void setTimestamp(Long timestamp) { this.timestamp = timestamp; } - @ApiModelProperty("The target architecture of the built component.") + @Schema(description = "The target architecture of the built component.") public String getTargetArch() { return targetArch; } @@ -68,7 +67,7 @@ public void setTargetArch(String targetArch) { this.targetArch = targetArch; } - @ApiModelProperty("The compiler used for the build") + @Schema(description = "The compiler used for the build") public String getCompiler() { return compiler; } @@ -77,7 +76,7 @@ public void setCompiler(String compiler) { this.compiler = compiler; } - @ApiModelProperty("The compiler flags used for the build.") + @Schema(description = "The compiler flags used for the build.") public String getCompilerFlags() { return compilerFlags; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Bundle.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Bundle.java index 6c009e7c9b47e..559e10fb506ad 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Bundle.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Bundle.java @@ -17,13 +17,11 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Objects; -@ApiModel public class Bundle implements Serializable { private static final long serialVersionUID = 1L; @@ -49,10 +47,7 @@ public static Bundle defaultBundle() { return new Bundle(DEFAULT_GROUP, DEFAULT_ARTIFACT, DEFAULT_VERSION); } - @ApiModelProperty( - value = "The group id of the bundle", - notes = "A globally unique group namespace, e.g., org.apache.nifi", - required = true) + @Schema(description = "The group id of the bundle") public String getGroup() { return group; } @@ -61,10 +56,7 @@ public void setGroup(String group) { this.group = group; } - @ApiModelProperty( - value = "The artifact id of the bundle", - notes = "Unique within the group", - required = true) + @Schema(description = "The artifact id of the bundle") public String getArtifact() { return artifact; } @@ -73,7 +65,7 @@ public void setArtifact(String artifact) { this.artifact = artifact; } - @ApiModelProperty("The version of the bundle artifact") + @Schema(description = "The version of the bundle artifact") public String getVersion() { return version; } @@ -82,10 +74,7 @@ public void setVersion(String version) { this.version = version; } - @ApiModelProperty(value = "The full specification of the bundle contents", - notes = "This is optional, as the group, artifact, and version are " + - "also enough to reference a bundle in the case the bundle " + - "specification has been published to a registry.") + @Schema(description = "The full specification of the bundle contents") public ComponentManifest getComponentManifest() { return componentManifest; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ComponentManifest.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ComponentManifest.java index 0be677931867e..d7199d5467939 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ComponentManifest.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ComponentManifest.java @@ -17,13 +17,12 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; import java.util.Collections; import java.util.List; -@ApiModel public class ComponentManifest implements Serializable { private static final long serialVersionUID = 1L; @@ -32,7 +31,7 @@ public class ComponentManifest implements Serializable { private List processors; private List reportingTasks; - @ApiModelProperty("Public interfaces defined in this bundle") + @Schema(description = "Public interfaces defined in this bundle") public List getApis() { return (apis != null ? Collections.unmodifiableList(apis) : null); } @@ -41,7 +40,7 @@ public void setApis(List apis) { this.apis = apis; } - @ApiModelProperty("Controller Services provided in this bundle") + @Schema(description = "Controller Services provided in this bundle") public List getControllerServices() { return (controllerServices != null ? Collections.unmodifiableList(controllerServices) : null); } @@ -50,7 +49,7 @@ public void setControllerServices(List controllerSe this.controllerServices = controllerServices; } - @ApiModelProperty("Processors provided in this bundle") + @Schema(description = "Processors provided in this bundle") public List getProcessors() { return (processors != null ? Collections.unmodifiableList(processors) : null); } @@ -59,7 +58,7 @@ public void setProcessors(List processors) { this.processors = processors; } - @ApiModelProperty("Reporting Tasks provided in this bundle") + @Schema(description = "Reporting Tasks provided in this bundle") public List getReportingTasks() { return (reportingTasks != null ? Collections.unmodifiableList(reportingTasks) : null); } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ConfigurableExtensionDefinition.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ConfigurableExtensionDefinition.java index 99216c7cf9cd7..b7321ac9dfa15 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ConfigurableExtensionDefinition.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ConfigurableExtensionDefinition.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Collections; import java.util.LinkedHashMap; @@ -33,7 +33,7 @@ public abstract class ConfigurableExtensionDefinition extends ExtensionComponent private List dynamicProperties; @Override - @ApiModelProperty("Descriptions of configuration properties applicable to this component.") + @Schema(description = "Descriptions of configuration properties applicable to this component.") public Map getPropertyDescriptors() { return (propertyDescriptors != null ? Collections.unmodifiableMap(propertyDescriptors) : null); } @@ -44,7 +44,7 @@ public void setPropertyDescriptors(LinkedHashMap pro } @Override - @ApiModelProperty("Whether or not this component makes use of dynamic (user-set) properties.") + @Schema(description = "Whether or not this component makes use of dynamic (user-set) properties.") public boolean getSupportsDynamicProperties() { return supportsDynamicProperties; } @@ -55,7 +55,7 @@ public void setSupportsDynamicProperties(boolean supportsDynamicProperties) { } @Override - @ApiModelProperty("Whether or not this component makes use of sensitive dynamic (user-set) properties.") + @Schema(description = "Whether or not this component makes use of sensitive dynamic (user-set) properties.") public boolean getSupportsSensitiveDynamicProperties() { return supportsSensitiveDynamicProperties; } @@ -66,7 +66,7 @@ public void setSupportsSensitiveDynamicProperties(boolean supportsSensitiveDynam } @Override - @ApiModelProperty("Describes the dynamic properties supported by this component") + @Schema(description = "Describes the dynamic properties supported by this component") public List getDynamicProperties() { return dynamicProperties; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ControllerServiceDefinition.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ControllerServiceDefinition.java index 89279e04d7213..0457b11c34001 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ControllerServiceDefinition.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ControllerServiceDefinition.java @@ -17,9 +17,6 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; - -@ApiModel public class ControllerServiceDefinition extends ConfigurableExtensionDefinition { private static final long serialVersionUID = 1L; diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DefinedType.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DefinedType.java index b59f00cb6222a..91acb08d62da8 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DefinedType.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DefinedType.java @@ -17,8 +17,7 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Objects; @@ -26,7 +25,6 @@ /** * A reference to a defined type identified by bundle and fully qualified class type identifiers */ -@ApiModel public class DefinedType implements Serializable { private static final long serialVersionUID = 1L; @@ -36,7 +34,7 @@ public class DefinedType implements Serializable { private String type; private String typeDescription; - @ApiModelProperty("The group name of the bundle that provides the referenced type.") + @Schema(description = "The group name of the bundle that provides the referenced type.") public String getGroup() { return group; } @@ -45,7 +43,7 @@ public void setGroup(String group) { this.group = group; } - @ApiModelProperty("The artifact name of the bundle that provides the referenced type.") + @Schema(description = "The artifact name of the bundle that provides the referenced type.") public String getArtifact() { return artifact; } @@ -54,7 +52,7 @@ public void setArtifact(String artifact) { this.artifact = artifact; } - @ApiModelProperty("The version of the bundle that provides the referenced type.") + @Schema(description = "The version of the bundle that provides the referenced type.") public String getVersion() { return version; } @@ -63,10 +61,7 @@ public void setVersion(String version) { this.version = version; } - @ApiModelProperty( - value = "The fully-qualified class type", - required = true, - notes = "For example, 'org.apache.nifi.GetFile' or 'org::apache:nifi::minifi::GetFile'") + @Schema(description = "The fully-qualified class type") public String getType() { return type; } @@ -75,7 +70,7 @@ public void setType(String type) { this.type = type; } - @ApiModelProperty("The description of the type.") + @Schema(description = "The description of the type.") public String getTypeDescription() { return typeDescription; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicProperty.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicProperty.java index 25e247dbec799..a219b94282842 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicProperty.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicProperty.java @@ -16,11 +16,9 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.expression.ExpressionLanguageScope; -@ApiModel public class DynamicProperty { private String name; @@ -28,7 +26,7 @@ public class DynamicProperty { private String description; private ExpressionLanguageScope expressionLanguageScope; - @ApiModelProperty(value = "The description of the dynamic property name") + @Schema(description = "The description of the dynamic property name") public String getName() { return name; } @@ -37,7 +35,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the dynamic property value") + @Schema(description = "The description of the dynamic property value") public String getValue() { return value; } @@ -46,7 +44,7 @@ public void setValue(String value) { this.value = value; } - @ApiModelProperty(value = "The description of the dynamic property") + @Schema(description = "The description of the dynamic property") public String getDescription() { return description; } @@ -55,7 +53,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "The scope of the expression language support") + @Schema(description = "The scope of the expression language support") public ExpressionLanguageScope getExpressionLanguageScope() { return expressionLanguageScope; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicRelationship.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicRelationship.java index 0934490ee31d4..5b6efff25d858 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicRelationship.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/DynamicRelationship.java @@ -16,16 +16,14 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; -@ApiModel public class DynamicRelationship { private String name; private String description; - @ApiModelProperty(value = "The description of the dynamic relationship name") + @Schema(description = "The description of the dynamic relationship name") public String getName() { return name; } @@ -34,7 +32,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the dynamic relationship") + @Schema(description = "The description of the dynamic relationship") public String getDescription() { return description; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ExtensionComponent.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ExtensionComponent.java index 485ee1563c9ef..f3e94a246c83d 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ExtensionComponent.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ExtensionComponent.java @@ -17,8 +17,7 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Collections; import java.util.List; @@ -28,7 +27,6 @@ /** * A component provided by an extension bundle */ -@ApiModel public class ExtensionComponent extends DefinedType { private static final long serialVersionUID = 1L; @@ -52,7 +50,7 @@ public class ExtensionComponent extends DefinedType { private boolean additionalDetails; - @ApiModelProperty("The build metadata for this component") + @Schema(description = "The build metadata for this component") public BuildInfo getBuildInfo() { return buildInfo; } @@ -61,7 +59,7 @@ public void setBuildInfo(BuildInfo buildInfo) { this.buildInfo = buildInfo; } - @ApiModelProperty("If this type represents a provider for an interface, this lists the APIs it implements") + @Schema(description = "If this type represents a provider for an interface, this lists the APIs it implements") public List getProvidedApiImplementations() { return (providedApiImplementations != null ? Collections.unmodifiableList(providedApiImplementations) : null); @@ -71,7 +69,7 @@ public void setProvidedApiImplementations(List providedApiImplement this.providedApiImplementations = providedApiImplementations; } - @ApiModelProperty("The tags associated with this type") + @Schema(description = "The tags associated with this type") public Set getTags() { return (tags != null ? Collections.unmodifiableSet(tags) : null); } @@ -80,7 +78,7 @@ public void setTags(Set tags) { this.tags = tags; } - @ApiModelProperty("The names of other component types that may be related") + @Schema(description = "The names of other component types that may be related") public Set getSeeAlso() { return seeAlso; } @@ -89,7 +87,7 @@ public void setSeeAlso(Set seeAlso) { this.seeAlso = seeAlso; } - @ApiModelProperty("Whether or not the component has been deprecated") + @Schema(description = "Whether or not the component has been deprecated") public Boolean getDeprecated() { return deprecated; } @@ -98,7 +96,7 @@ public void setDeprecated(Boolean deprecated) { this.deprecated = deprecated; } - @ApiModelProperty("If this component has been deprecated, this optional field can be used to provide an explanation") + @Schema(description = "If this component has been deprecated, this optional field can be used to provide an explanation") public String getDeprecationReason() { return deprecationReason; } @@ -107,7 +105,7 @@ public void setDeprecationReason(String deprecationReason) { this.deprecationReason = deprecationReason; } - @ApiModelProperty("If this component has been deprecated, this optional field provides alternatives to use") + @Schema(description = "If this component has been deprecated, this optional field provides alternatives to use") public Set getDeprecationAlternatives() { return deprecationAlternatives; } @@ -116,7 +114,7 @@ public void setDeprecationAlternatives(Set deprecationAlternatives) { this.deprecationAlternatives = deprecationAlternatives; } - @ApiModelProperty("Whether or not the component has a general restriction") + @Schema(description = "Whether or not the component has a general restriction") public Boolean isRestricted() { return restricted; } @@ -129,7 +127,7 @@ public void setRestricted(Boolean restricted) { this.restricted = restricted; } - @ApiModelProperty("An optional description of the general restriction") + @Schema(description = "An optional description of the general restriction") public String getRestrictedExplanation() { return restrictedExplanation; } @@ -138,7 +136,7 @@ public void setRestrictedExplanation(String restrictedExplanation) { this.restrictedExplanation = restrictedExplanation; } - @ApiModelProperty("Explicit restrictions that indicate a require permission to use the component") + @Schema(description = "Explicit restrictions that indicate a require permission to use the component") public Set getExplicitRestrictions() { return explicitRestrictions; } @@ -147,7 +145,7 @@ public void setExplicitRestrictions(Set explicitRestrictions) { this.explicitRestrictions = explicitRestrictions; } - @ApiModelProperty("Indicates if the component stores state") + @Schema(description = "Indicates if the component stores state") public Stateful getStateful() { return stateful; } @@ -156,7 +154,7 @@ public void setStateful(Stateful stateful) { this.stateful = stateful; } - @ApiModelProperty("The system resource considerations for the given component") + @Schema(description = "The system resource considerations for the given component") public List getSystemResourceConsiderations() { return systemResourceConsiderations; } @@ -165,7 +163,7 @@ public void setSystemResourceConsiderations(List sy this.systemResourceConsiderations = systemResourceConsiderations; } - @ApiModelProperty("Indicates if the component has additional details documentation") + @Schema(description = "Indicates if the component has additional details documentation") public boolean isAdditionalDetails() { return additionalDetails; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/MultiProcessorUseCase.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/MultiProcessorUseCase.java new file mode 100644 index 0000000000000..ccc238bdee237 --- /dev/null +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/MultiProcessorUseCase.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.apache.nifi.c2.protocol.component.api; + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; +import java.util.List; + +public class MultiProcessorUseCase implements Serializable { + private String description; + private String notes; + private List keywords; + private List configurations; + + @Schema(description="A description of the use case") + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + @Schema(description="Any pertinent notes about the use case") + public String getNotes() { + return notes; + } + + public void setNotes(final String notes) { + this.notes = notes; + } + + @Schema(description="Keywords that pertain to the use csae") + public List getKeywords() { + return keywords; + } + + public void setKeywords(final List keywords) { + this.keywords = keywords; + } + + @Schema(description="A description of how to configure the Processor to perform the task described in the use case") + public List getConfigurations() { + return configurations; + } + + public void setConfigurations(final List configurations) { + this.configurations = configurations; + } + +} diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorConfiguration.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorConfiguration.java new file mode 100644 index 0000000000000..0416e19e47cad --- /dev/null +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorConfiguration.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package org.apache.nifi.c2.protocol.component.api; + + +import io.swagger.v3.oas.annotations.media.Schema; + +import java.io.Serializable; + +public class ProcessorConfiguration implements Serializable { + private String processorClassName; + private String configuration; + + @Schema(description="The fully qualified classname of the Processor that should be used to accomplish the use case") + public String getProcessorClassName() { + return processorClassName; + } + + public void setProcessorClassName(final String processorClassName) { + this.processorClassName = processorClassName; + } + + @Schema(description="A description of how the Processor should be configured in order to accomplish the use case") + public String getConfiguration() { + return configuration; + } + + public void setConfiguration(final String configuration) { + this.configuration = configuration; + } +} diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorDefinition.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorDefinition.java index 99ea2429b570a..f35a6add63298 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorDefinition.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ProcessorDefinition.java @@ -17,15 +17,13 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.annotation.behavior.InputRequirement; import java.util.Collections; import java.util.List; import java.util.Map; -@ApiModel public class ProcessorDefinition extends ConfigurableExtensionDefinition { private static final long serialVersionUID = 1L; @@ -53,7 +51,11 @@ public class ProcessorDefinition extends ConfigurableExtensionDefinition { private List readsAttributes; private List writesAttributes; - @ApiModelProperty("Any input requirements this processor has.") + private List useCases; + private List multiProcessorUseCases; + + + @Schema(description="Any input requirements this processor has.") public InputRequirement.Requirement getInputRequirement() { return inputRequirement; } @@ -62,7 +64,7 @@ public void setInputRequirement(InputRequirement.Requirement inputRequirement) { this.inputRequirement = inputRequirement; } - @ApiModelProperty("The supported relationships for this processor.") + @Schema(description = "The supported relationships for this processor.") public List getSupportedRelationships() { return (supportedRelationships == null ? Collections.emptyList() : Collections.unmodifiableList(supportedRelationships)); } @@ -71,7 +73,7 @@ public void setSupportedRelationships(List supportedRelationships) this.supportedRelationships = supportedRelationships; } - @ApiModelProperty("Whether or not this processor supports dynamic relationships.") + @Schema(description = "Whether or not this processor supports dynamic relationships.") public boolean getSupportsDynamicRelationships() { return supportsDynamicRelationships; } @@ -80,7 +82,7 @@ public void setSupportsDynamicRelationships(boolean supportsDynamicRelationships this.supportsDynamicRelationships = supportsDynamicRelationships; } - @ApiModelProperty("If the processor supports dynamic relationships, this describes the dynamic relationship") + @Schema(description = "If the processor supports dynamic relationships, this describes the dynamic relationship") public DynamicRelationship getDynamicRelationship() { return dynamicRelationship; } @@ -89,7 +91,7 @@ public void setDynamicRelationship(DynamicRelationship dynamicRelationship) { this.dynamicRelationship = dynamicRelationship; } - @ApiModelProperty("Whether or not this processor should be triggered serially (i.e. no concurrent execution).") + @Schema(description = "Whether or not this processor should be triggered serially (i.e. no concurrent execution).") public boolean getTriggerSerially() { return triggerSerially; } @@ -98,7 +100,7 @@ public void setTriggerSerially(boolean triggerSerially) { this.triggerSerially = triggerSerially; } - @ApiModelProperty("Whether or not this processor should be triggered when incoming queues are empty.") + @Schema(description = "Whether or not this processor should be triggered when incoming queues are empty.") public boolean getTriggerWhenEmpty() { return triggerWhenEmpty; } @@ -107,7 +109,7 @@ public void setTriggerWhenEmpty(boolean triggerWhenEmpty) { this.triggerWhenEmpty = triggerWhenEmpty; } - @ApiModelProperty("Whether or not this processor should be triggered when any destination queue has room.") + @Schema(description = "Whether or not this processor should be triggered when any destination queue has room.") public boolean getTriggerWhenAnyDestinationAvailable() { return triggerWhenAnyDestinationAvailable; } @@ -116,7 +118,7 @@ public void setTriggerWhenAnyDestinationAvailable(boolean triggerWhenAnyDestinat this.triggerWhenAnyDestinationAvailable = triggerWhenAnyDestinationAvailable; } - @ApiModelProperty("Whether or not this processor supports batching. If a Processor uses this annotation, " + + @Schema(description = "Whether or not this processor supports batching. If a Processor uses this annotation, " + "it allows the Framework to batch calls to session commits, as well as allowing the Framework to return " + "the same session multiple times.") public boolean getSupportsBatching() { @@ -127,7 +129,7 @@ public void setSupportsBatching(boolean supportsBatching) { this.supportsBatching = supportsBatching; } - @ApiModelProperty("Whether or not this processor should be scheduled only on the primary node in a cluster.") + @Schema(description = "Whether or not this processor should be scheduled only on the primary node in a cluster.") public boolean getPrimaryNodeOnly() { return primaryNodeOnly; } @@ -136,7 +138,7 @@ public void setPrimaryNodeOnly(boolean primaryNodeOnly) { this.primaryNodeOnly = primaryNodeOnly; } - @ApiModelProperty("Whether or not this processor is considered side-effect free. Side-effect free indicate that the " + + @Schema(description = "Whether or not this processor is considered side-effect free. Side-effect free indicate that the " + "processor's operations on FlowFiles can be safely repeated across process sessions.") public boolean getSideEffectFree() { return sideEffectFree; @@ -146,7 +148,7 @@ public void setSideEffectFree(boolean sideEffectFree) { this.sideEffectFree = sideEffectFree; } - @ApiModelProperty("The supported scheduling strategies, such as TIME_DRIVER, CRON, or EVENT_DRIVEN.") + @Schema(description = "The supported scheduling strategies, such as TIME_DRIVER, CRON, or EVENT_DRIVEN.") public List getSupportedSchedulingStrategies() { return supportedSchedulingStrategies; } @@ -155,7 +157,7 @@ public void setSupportedSchedulingStrategies(List supportedSchedulingStr this.supportedSchedulingStrategies = supportedSchedulingStrategies; } - @ApiModelProperty("The default scheduling strategy for the processor.") + @Schema(description = "The default scheduling strategy for the processor.") public String getDefaultSchedulingStrategy() { return defaultSchedulingStrategy; } @@ -164,7 +166,7 @@ public void setDefaultSchedulingStrategy(String defaultSchedulingStrategy) { this.defaultSchedulingStrategy = defaultSchedulingStrategy; } - @ApiModelProperty("The default concurrent tasks for each scheduling strategy.") + @Schema(description = "The default concurrent tasks for each scheduling strategy.") public Map getDefaultConcurrentTasksBySchedulingStrategy() { return defaultConcurrentTasksBySchedulingStrategy != null ? Collections.unmodifiableMap(defaultConcurrentTasksBySchedulingStrategy) : null; } @@ -173,7 +175,7 @@ public void setDefaultConcurrentTasksBySchedulingStrategy(Map d this.defaultConcurrentTasksBySchedulingStrategy = defaultConcurrentTasksBySchedulingStrategy; } - @ApiModelProperty("The default scheduling period for each scheduling strategy. " + + @Schema(description = "The default scheduling period for each scheduling strategy. " + "The scheduling period is expected to be a time period, such as \"30 sec\".") public Map getDefaultSchedulingPeriodBySchedulingStrategy() { return defaultSchedulingPeriodBySchedulingStrategy != null ? Collections.unmodifiableMap(defaultSchedulingPeriodBySchedulingStrategy) : null; @@ -183,7 +185,7 @@ public void setDefaultSchedulingPeriodBySchedulingStrategy(Map d this.defaultSchedulingPeriodBySchedulingStrategy = defaultSchedulingPeriodBySchedulingStrategy; } - @ApiModelProperty("The default penalty duration as a time period, such as \"30 sec\".") + @Schema(description = "The default penalty duration as a time period, such as \"30 sec\".") public String getDefaultPenaltyDuration() { return defaultPenaltyDuration; } @@ -192,7 +194,7 @@ public void setDefaultPenaltyDuration(String defaultPenaltyDuration) { this.defaultPenaltyDuration = defaultPenaltyDuration; } - @ApiModelProperty("The default yield duration as a time period, such as \"1 sec\".") + @Schema(description = "The default yield duration as a time period, such as \"1 sec\".") public String getDefaultYieldDuration() { return defaultYieldDuration; } @@ -201,7 +203,7 @@ public void setDefaultYieldDuration(String defaultYieldDuration) { this.defaultYieldDuration = defaultYieldDuration; } - @ApiModelProperty("The default bulletin level, such as WARN, INFO, DEBUG, etc.") + @Schema(description = "The default bulletin level, such as WARN, INFO, DEBUG, etc.") public String getDefaultBulletinLevel() { return defaultBulletinLevel; } @@ -210,7 +212,7 @@ public void setDefaultBulletinLevel(String defaultBulletinLevel) { this.defaultBulletinLevel = defaultBulletinLevel; } - @ApiModelProperty("The FlowFile attributes this processor reads") + @Schema(description = "The FlowFile attributes this processor reads") public List getReadsAttributes() { return readsAttributes; } @@ -219,7 +221,7 @@ public void setReadsAttributes(List readsAttributes) { this.readsAttributes = readsAttributes; } - @ApiModelProperty("The FlowFile attributes this processor writes/updates") + @Schema(description = "The FlowFile attributes this processor writes/updates") public List getWritesAttributes() { return writesAttributes; } @@ -227,4 +229,22 @@ public List getWritesAttributes() { public void setWritesAttributes(List writesAttributes) { this.writesAttributes = writesAttributes; } + + @Schema(description="A list of use cases that have been documented for this Processor") + public List getUseCases() { + return useCases; + } + + public void setUseCases(final List useCases) { + this.useCases = useCases; + } + + @Schema(description="A list of use cases that have been documented that involve this Processor in conjunction with other Processors") + public List getMultiProcessorUseCases() { + return multiProcessorUseCases; + } + + public void setMultiProcessorUseCases(final List multiProcessorUseCases) { + this.multiProcessorUseCases = multiProcessorUseCases; + } } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyAllowableValue.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyAllowableValue.java index e70e80a5ace9e..7e33631e7d92f 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyAllowableValue.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyAllowableValue.java @@ -17,13 +17,11 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Objects; -@ApiModel public class PropertyAllowableValue implements Serializable { private static final long serialVersionUID = 1L; @@ -31,7 +29,7 @@ public class PropertyAllowableValue implements Serializable { private String displayName; private String description; - @ApiModelProperty(value = "The internal value", required = true) + @Schema(description = "The internal value") public String getValue() { return value; } @@ -40,7 +38,7 @@ public void setValue(String value) { this.value = value; } - @ApiModelProperty("The display name of the value, if different from the internal value") + @Schema(description = "The display name of the value, if different from the internal value") public String getDisplayName() { return displayName; } @@ -49,7 +47,7 @@ public void setDisplayName(String displayName) { this.displayName = displayName; } - @ApiModelProperty("The description of the value, e.g., the behavior it produces.") + @Schema(description = "The description of the value, e.g., the behavior it produces.") public String getDescription() { return description; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDependency.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDependency.java index dbac2d16dea8f..c49193c09d385 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDependency.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDependency.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.List; -@ApiModel public class PropertyDependency implements Serializable { private static final long serialVersionUID = 1L; @@ -30,7 +28,7 @@ public class PropertyDependency implements Serializable { private String propertyDisplayName; private List dependentValues; - @ApiModelProperty("The name of the property that is depended upon") + @Schema(description = "The name of the property that is depended upon") public String getPropertyName() { return propertyName; } @@ -39,7 +37,7 @@ public void setPropertyName(String propertyName) { this.propertyName = propertyName; } - @ApiModelProperty("The name of the property that is depended upon") + @Schema(description = "The name of the property that is depended upon") public String getPropertyDisplayName() { return propertyDisplayName; } @@ -48,7 +46,7 @@ public void setPropertyDisplayName(String propertyDisplayName) { this.propertyDisplayName = propertyDisplayName; } - @ApiModelProperty("The values that satisfy the dependency") + @Schema(description = "The values that satisfy the dependency") public List getDependentValues() { return dependentValues; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDescriptor.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDescriptor.java index 2ebd040bc0026..c0fe2ce527fd3 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDescriptor.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyDescriptor.java @@ -16,15 +16,13 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.io.Serializable; import java.util.Collections; import java.util.List; -import org.apache.nifi.expression.ExpressionLanguageScope; +import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.nifi.expression.ExpressionLanguageScope; -@ApiModel public class PropertyDescriptor implements Serializable { private static final long serialVersionUID = 1L; @@ -44,7 +42,7 @@ public class PropertyDescriptor implements Serializable { private PropertyResourceDefinition resourceDefinition; private List dependencies; - @ApiModelProperty(value = "The name of the property key", required = true) + @Schema(description = "The name of the property key") public String getName() { return name; } @@ -53,7 +51,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The display name of the property key, if different from the name") + @Schema(description = "The display name of the property key, if different from the name") public String getDisplayName() { return displayName; } @@ -62,7 +60,7 @@ public void setDisplayName(String displayName) { this.displayName = displayName; } - @ApiModelProperty("The description of what the property does") + @Schema(description = "The description of what the property does") public String getDescription() { return description; } @@ -71,7 +69,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty("A list of the allowable values for the property") + @Schema(description = "A list of the allowable values for the property") public List getAllowableValues() { return (allowableValues != null ? Collections.unmodifiableList(allowableValues) : null); } @@ -80,7 +78,7 @@ public void setAllowableValues(List allowableValues) { this.allowableValues = allowableValues; } - @ApiModelProperty("The default value if a user-set value is not specified") + @Schema(description = "The default value if a user-set value is not specified") public String getDefaultValue() { return defaultValue; } @@ -89,7 +87,7 @@ public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } - @ApiModelProperty("Whether or not the property is required for the component") + @Schema(description = "Whether or not the property is required for the component") public boolean getRequired() { return required; } @@ -98,7 +96,7 @@ public void setRequired(boolean required) { this.required = required; } - @ApiModelProperty("Whether or not the value of the property is considered sensitive (e.g., passwords and keys)") + @Schema(description = "Whether or not the value of the property is considered sensitive (e.g., passwords and keys)") public boolean getSensitive() { return sensitive; } @@ -107,7 +105,7 @@ public void setSensitive(boolean sensitive) { this.sensitive = sensitive; } - @ApiModelProperty("The scope of expression language supported by this property") + @Schema(description = "The scope of expression language supported by this property") public ExpressionLanguageScope getExpressionLanguageScope() { return expressionLanguageScope; } @@ -117,12 +115,12 @@ public void setExpressionLanguageScope(ExpressionLanguageScope expressionLanguag this.expressionLanguageScopeDescription = expressionLanguageScope == null ? null : expressionLanguageScope.getDescription(); } - @ApiModelProperty(value = "The description of the expression language scope supported by this property", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The description of the expression language scope supported by this property", accessMode = Schema.AccessMode.READ_ONLY) public String getExpressionLanguageScopeDescription() { return expressionLanguageScope == null ? null : expressionLanguageScope.getDescription(); } - @ApiModelProperty("Indicates that this property is for selecting a controller service of the specified type") + @Schema(description = "Indicates that this property is for selecting a controller service of the specified type") public DefinedType getTypeProvidedByValue() { return typeProvidedByValue; } @@ -131,7 +129,7 @@ public void setTypeProvidedByValue(DefinedType typeProvidedByValue) { this.typeProvidedByValue = typeProvidedByValue; } - @ApiModelProperty("A regular expression that can be used to validate the value of this property") + @Schema(description = "A regular expression that can be used to validate the value of this property") public String getValidRegex() { return validRegex; } @@ -140,7 +138,7 @@ public void setValidRegex(String validRegex) { this.validRegex = validRegex; } - @ApiModelProperty("Name of the validator used for this property descriptor") + @Schema(description = "Name of the validator used for this property descriptor") public String getValidator() { return validator; } @@ -149,7 +147,7 @@ public void setValidator(final String validator) { this.validator = validator; } - @ApiModelProperty("Whether or not the descriptor is for a dynamically added property") + @Schema(description = "Whether or not the descriptor is for a dynamically added property") public boolean isDynamic() { return dynamic; } @@ -158,7 +156,7 @@ public void setDynamic(boolean dynamic) { this.dynamic = dynamic; } - @ApiModelProperty("Indicates that this property references external resources") + @Schema(description = "Indicates that this property references external resources") public PropertyResourceDefinition getResourceDefinition() { return resourceDefinition; } @@ -167,7 +165,7 @@ public void setResourceDefinition(PropertyResourceDefinition resourceDefinition) this.resourceDefinition = resourceDefinition; } - @ApiModelProperty("The dependencies that this property has on other properties") + @Schema(description = "The dependencies that this property has on other properties") public List getDependencies() { return dependencies; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyResourceDefinition.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyResourceDefinition.java index ebc6d2bdc96e2..0e8d26fef5d34 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyResourceDefinition.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/PropertyResourceDefinition.java @@ -16,22 +16,20 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.components.resource.ResourceCardinality; import org.apache.nifi.components.resource.ResourceType; import java.io.Serializable; import java.util.Set; -@ApiModel public class PropertyResourceDefinition implements Serializable { private static final long serialVersionUID = 1L; private ResourceCardinality cardinality; private Set resourceTypes; - @ApiModelProperty("The cardinality of the resource definition (i.e. single or multiple)") + @Schema(description = "The cardinality of the resource definition (i.e. single or multiple)") public ResourceCardinality getCardinality() { return cardinality; } @@ -40,7 +38,7 @@ public void setCardinality(ResourceCardinality cardinality) { this.cardinality = cardinality; } - @ApiModelProperty("The types of resources that can be referenced") + @Schema(description = "The types of resources that can be referenced") public Set getResourceTypes() { return resourceTypes; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Relationship.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Relationship.java index 84135a896db9f..e7066b9b01726 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Relationship.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Relationship.java @@ -17,18 +17,17 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; + import java.io.Serializable; -@ApiModel public class Relationship implements Serializable { private static final long serialVersionUID = 1L; private String name; private String description; - @ApiModelProperty("The name of the relationship") + @Schema(description = "The name of the relationship") public String getName() { return name; } @@ -37,7 +36,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The description of the relationship") + @Schema(description = "The description of the relationship") public String getDescription() { return description; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ReportingTaskDefinition.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ReportingTaskDefinition.java index aa51e36c76594..19bbf25d96dbb 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ReportingTaskDefinition.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/ReportingTaskDefinition.java @@ -17,14 +17,12 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Collections; import java.util.List; import java.util.Map; -@ApiModel public class ReportingTaskDefinition extends ConfigurableExtensionDefinition { private static final long serialVersionUID = 1L; @@ -32,7 +30,7 @@ public class ReportingTaskDefinition extends ConfigurableExtensionDefinition { private String defaultSchedulingStrategy; private Map defaultSchedulingPeriodBySchedulingStrategy; - @ApiModelProperty("The supported scheduling strategies, such as TIME_DRIVER or CRON.") + @Schema(description = "The supported scheduling strategies, such as TIME_DRIVER or CRON.") public List getSupportedSchedulingStrategies() { return (supportedSchedulingStrategies != null ? Collections.unmodifiableList(supportedSchedulingStrategies) : null); } @@ -41,7 +39,7 @@ public void setSupportedSchedulingStrategies(List supportedSchedulingStr this.supportedSchedulingStrategies = supportedSchedulingStrategies; } - @ApiModelProperty("The default scheduling strategy for the reporting task.") + @Schema(description = "The default scheduling strategy for the reporting task.") public String getDefaultSchedulingStrategy() { return defaultSchedulingStrategy; } @@ -50,7 +48,7 @@ public void setDefaultSchedulingStrategy(String defaultSchedulingStrategy) { this.defaultSchedulingStrategy = defaultSchedulingStrategy; } - @ApiModelProperty("The default scheduling period for each scheduling strategy. " + + @Schema(description = "The default scheduling period for each scheduling strategy. " + "The scheduling period is expected to be a time period, such as \"30 sec\".") public Map getDefaultSchedulingPeriodBySchedulingStrategy() { return defaultSchedulingPeriodBySchedulingStrategy != null ? Collections.unmodifiableMap(defaultSchedulingPeriodBySchedulingStrategy) : null; diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Restriction.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Restriction.java index 9b0f24dbab75e..b44eee01cdf6c 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Restriction.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Restriction.java @@ -16,18 +16,16 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; -@ApiModel public class Restriction { private String requiredPermission; private String explanation; - @ApiModelProperty(value = "The permission required for this restriction") + @Schema(description = "The permission required for this restriction") public String getRequiredPermission() { return requiredPermission; } @@ -36,7 +34,7 @@ public void setRequiredPermission(String requiredPermission) { this.requiredPermission = requiredPermission; } - @ApiModelProperty(value = "The explanation of this restriction") + @Schema(description = "The explanation of this restriction") public String getExplanation() { return explanation; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/RuntimeManifest.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/RuntimeManifest.java index 8b12fa9009d34..f6b6f28f6c647 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/RuntimeManifest.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/RuntimeManifest.java @@ -17,15 +17,13 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Objects; -@ApiModel public class RuntimeManifest implements Serializable { private static final long serialVersionUID = 1L; @@ -36,7 +34,7 @@ public class RuntimeManifest implements Serializable { private List bundles; private SchedulingDefaults schedulingDefaults; - @ApiModelProperty("A unique identifier for the manifest") + @Schema(description = "A unique identifier for the manifest") public String getIdentifier() { return identifier; } @@ -45,9 +43,7 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } - @ApiModelProperty( - value = "The type of the runtime binary, e.g., 'minifi-java' or 'minifi-cpp'", - notes = "Usually set when the runtime is built.") + @Schema(description = "The type of the runtime binary, e.g., 'minifi-java' or 'minifi-cpp'") public String getAgentType() { return agentType; } @@ -56,9 +52,7 @@ public void setAgentType(String agentType) { this.agentType = agentType; } - @ApiModelProperty( - value = "The version of the runtime binary, e.g., '1.0.1'", - notes = "Usually set when the runtime is built.") + @Schema(description = "The version of the runtime binary, e.g., '1.0.1'") public String getVersion() { return version; } @@ -67,7 +61,7 @@ public void setVersion(String version) { this.version = version; } - @ApiModelProperty("Build summary for this runtime binary") + @Schema(description = "Build summary for this runtime binary") public BuildInfo getBuildInfo() { return buildInfo; } @@ -76,7 +70,7 @@ public void setBuildInfo(BuildInfo buildInfo) { this.buildInfo = buildInfo; } - @ApiModelProperty("All extension bundles included with this runtime") + @Schema(description = "All extension bundles included with this runtime") public List getBundles() { return (bundles != null ? Collections.unmodifiableList(bundles) : null); } @@ -85,7 +79,7 @@ public void setBundles(List bundles) { this.bundles = bundles; } - @ApiModelProperty("Scheduling defaults for components defined in this manifest") + @Schema(description = "Scheduling defaults for components defined in this manifest") public SchedulingDefaults getSchedulingDefaults() { return schedulingDefaults; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SchedulingDefaults.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SchedulingDefaults.java index 9a9d6d999ee8d..c2875d6e01920 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SchedulingDefaults.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SchedulingDefaults.java @@ -17,15 +17,13 @@ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.scheduling.SchedulingStrategy; import java.io.Serializable; import java.util.Collections; import java.util.Map; -@ApiModel public class SchedulingDefaults implements Serializable { private static final long serialVersionUID = 1L; @@ -39,7 +37,7 @@ public class SchedulingDefaults implements Serializable { private Map defaultConcurrentTasksBySchedulingStrategy; private Map defaultSchedulingPeriodsBySchedulingStrategy; - @ApiModelProperty("The name of the default scheduling strategy") + @Schema(description = "The name of the default scheduling strategy") public SchedulingStrategy getDefaultSchedulingStrategy() { return defaultSchedulingStrategy; } @@ -48,7 +46,7 @@ public void setDefaultSchedulingStrategy(SchedulingStrategy defaultSchedulingStr this.defaultSchedulingStrategy = defaultSchedulingStrategy; } - @ApiModelProperty("The default scheduling period in milliseconds") + @Schema(description = "The default scheduling period in milliseconds") public long getDefaultSchedulingPeriodMillis() { return defaultSchedulingPeriodMillis; } @@ -57,7 +55,7 @@ public void setDefaultSchedulingPeriodMillis(long defaultSchedulingPeriodMillis) this.defaultSchedulingPeriodMillis = defaultSchedulingPeriodMillis; } - @ApiModelProperty("The default penalization period in milliseconds") + @Schema(description = "The default penalization period in milliseconds") public long getPenalizationPeriodMillis() { return penalizationPeriodMillis; } @@ -66,7 +64,7 @@ public void setPenalizationPeriodMillis(long penalizationPeriodMillis) { this.penalizationPeriodMillis = penalizationPeriodMillis; } - @ApiModelProperty("The default yield duration in milliseconds") + @Schema(description = "The default yield duration in milliseconds") public long getYieldDurationMillis() { return yieldDurationMillis; } @@ -75,7 +73,7 @@ public void setYieldDurationMillis(long yieldDurationMillis) { this.yieldDurationMillis = yieldDurationMillis; } - @ApiModelProperty("The default run duration in nano-seconds") + @Schema(description = "The default run duration in nano-seconds") public long getDefaultRunDurationNanos() { return defaultRunDurationNanos; } @@ -84,7 +82,7 @@ public void setDefaultRunDurationNanos(long defaultRunDurationNanos) { this.defaultRunDurationNanos = defaultRunDurationNanos; } - @ApiModelProperty("The default concurrent tasks") + @Schema(description = "The default concurrent tasks") public String getDefaultMaxConcurrentTasks() { return defaultMaxConcurrentTasks; } @@ -93,7 +91,7 @@ public void setDefaultMaxConcurrentTasks(String defaultMaxConcurrentTasks) { this.defaultMaxConcurrentTasks = defaultMaxConcurrentTasks; } - @ApiModelProperty("The default concurrent tasks for each scheduling strategy") + @Schema(description = "The default concurrent tasks for each scheduling strategy") public Map getDefaultConcurrentTasksBySchedulingStrategy() { return defaultConcurrentTasksBySchedulingStrategy != null ? Collections.unmodifiableMap(defaultConcurrentTasksBySchedulingStrategy) : null; } @@ -102,7 +100,7 @@ public void setDefaultConcurrentTasksBySchedulingStrategy(Map d this.defaultConcurrentTasksBySchedulingStrategy = defaultConcurrentTasksBySchedulingStrategy; } - @ApiModelProperty("The default scheduling period for each scheduling strategy") + @Schema(description = "The default scheduling period for each scheduling strategy") public Map getDefaultSchedulingPeriodsBySchedulingStrategy() { return defaultSchedulingPeriodsBySchedulingStrategy != null ? Collections.unmodifiableMap(defaultSchedulingPeriodsBySchedulingStrategy) : null; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Stateful.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Stateful.java index b7c6a211984d5..742307272e4b4 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Stateful.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/Stateful.java @@ -16,19 +16,17 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.components.state.Scope; import java.util.Set; -@ApiModel public class Stateful { private String description; private Set scopes; - @ApiModelProperty(value = "Description of what information is being stored in the StateManager") + @Schema(description = "Description of what information is being stored in the StateManager") public String getDescription() { return description; } @@ -37,7 +35,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "Indicates the Scope(s) associated with the State that is stored and retrieved") + @Schema(description = "Indicates the Scope(s) associated with the State that is stored and retrieved") public Set getScopes() { return scopes; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SystemResourceConsideration.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SystemResourceConsideration.java index 3c008f1f72b82..8c3f45b91161d 100644 --- a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SystemResourceConsideration.java +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/SystemResourceConsideration.java @@ -16,16 +16,14 @@ */ package org.apache.nifi.c2.protocol.component.api; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; -@ApiModel public class SystemResourceConsideration { private String resource; private String description; - @ApiModelProperty(value = "The resource to consider") + @Schema(description = "The resource to consider") public String getResource() { return resource; } @@ -34,7 +32,7 @@ public void setResource(String resource) { this.resource = resource; } - @ApiModelProperty(value = "The description of how the resource is affected") + @Schema(description = "The description of how the resource is affected") public String getDescription() { return description; } diff --git a/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/UseCase.java b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/UseCase.java new file mode 100644 index 0000000000000..6f3c7eba7453c --- /dev/null +++ b/c2/c2-protocol/c2-protocol-component-api/src/main/java/org/apache/nifi/c2/protocol/component/api/UseCase.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package org.apache.nifi.c2.protocol.component.api; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.apache.nifi.annotation.behavior.InputRequirement; + +import java.io.Serializable; +import java.util.List; + +public class UseCase implements Serializable { + private String description; + private String notes; + private List keywords; + private String configuration; + private InputRequirement.Requirement inputRequirement; + + @Schema(description="A description of the use case") + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + @Schema(description="Any pertinent notes about the use case") + public String getNotes() { + return notes; + } + + public void setNotes(final String notes) { + this.notes = notes; + } + + @Schema(description="Keywords that pertain to the use case") + public List getKeywords() { + return keywords; + } + + public void setKeywords(final List keywords) { + this.keywords = keywords; + } + + @Schema(description="A description of how to configure the Processor to perform the task described in the use case") + public String getConfiguration() { + return configuration; + } + + public void setConfiguration(final String configuration) { + this.configuration = configuration; + } + + @Schema(description="Specifies whether an incoming FlowFile is expected for this use case") + public InputRequirement.Requirement getInputRequirement() { + return inputRequirement; + } + + public void setInputRequirement(final InputRequirement.Requirement inputRequirement) { + this.inputRequirement = inputRequirement; + } +} diff --git a/minifi/minifi-bootstrap/pom.xml b/minifi/minifi-bootstrap/pom.xml index bbab3d59aa7c4..8f96c8f6be909 100644 --- a/minifi/minifi-bootstrap/pom.xml +++ b/minifi/minifi-bootstrap/pom.xml @@ -86,6 +86,13 @@ limitations under the License. minifi-commons-api 2.0.0-SNAPSHOT + + + org.apache.nifi.minifi + minifi-properties-loader + 2.0.0-SNAPSHOT + org.apache.nifi.minifi minifi-commons-framework diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/RunMiNiFi.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/RunMiNiFi.java index cbd23dcfac61b..4d00feee1a307 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/RunMiNiFi.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/RunMiNiFi.java @@ -48,7 +48,7 @@ import org.apache.nifi.minifi.commons.api.MiNiFiCommandState; import org.apache.nifi.minifi.commons.service.StandardFlowEnrichService; import org.apache.nifi.minifi.commons.service.StandardFlowSerDeService; -import org.apache.nifi.properties.ApplicationProperties; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -103,7 +103,7 @@ public RunMiNiFi(File bootstrapConfigFile) throws IOException { bootstrapFileProvider = new BootstrapFileProvider(bootstrapConfigFile); objectMapper = getObjectMapper(); Properties properties = bootstrapFileProvider.getStatusProperties(); - Properties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); miNiFiParameters = new MiNiFiParameters( Optional.ofNullable(properties.getProperty(STATUS_FILE_PORT_KEY)).map(Integer::parseInt).orElse(UNINITIALIZED), @@ -118,7 +118,7 @@ public RunMiNiFi(File bootstrapConfigFile) throws IOException { periodicStatusReporterManager = new PeriodicStatusReporterManager(bootstrapProperties, miNiFiStatusProvider, miNiFiCommandSender, miNiFiParameters); MiNiFiConfigurationChangeListener configurationChangeListener = new MiNiFiConfigurationChangeListener(this, DEFAULT_LOGGER, bootstrapFileProvider, - new StandardFlowEnrichService(new ApplicationProperties(bootstrapProperties)), StandardFlowSerDeService.defaultInstance()); + new StandardFlowEnrichService(bootstrapProperties), StandardFlowSerDeService.defaultInstance()); configurationChangeCoordinator = new ConfigurationChangeCoordinator(bootstrapFileProvider, this, singleton(configurationChangeListener)); currentPortProvider = new CurrentPortProvider(miNiFiCommandSender, miNiFiParameters, processUtils); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/command/StartRunner.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/command/StartRunner.java index 827f6ef171867..af331fcc2be90 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/command/StartRunner.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/command/StartRunner.java @@ -55,6 +55,7 @@ import org.apache.nifi.minifi.bootstrap.service.MiNiFiStdLogHandler; import org.apache.nifi.minifi.bootstrap.service.PeriodicStatusReporterManager; import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.minifi.properties.BootstrapProperties; public class StartRunner implements CommandRunner { @@ -122,10 +123,10 @@ private void start() throws IOException, InterruptedException, ConfigurationChan CMD_LOGGER.warn("Failed to delete previous lock file {}; this file should be cleaned up manually", prevLockFile); } - Properties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); String confDir = bootstrapProperties.getProperty(CONF_DIR_KEY); - generateMiNiFiProperties(bootstrapProperties, confDir); + generateMiNiFiProperties(bootstrapFileProvider.getProtectedBootstrapProperties(), confDir); regenerateFlowConfiguration(bootstrapProperties.getProperty(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey())); Process process = startMiNiFi(); @@ -259,7 +260,7 @@ private void deleteSwapFile(File file) { } } - private void generateMiNiFiProperties(Properties bootstrapProperties, String confDir) { + private void generateMiNiFiProperties(BootstrapProperties bootstrapProperties, String confDir) { DEFAULT_LOGGER.debug("Generating minifi.properties from bootstrap.conf"); try { miNiFiPropertiesGenerator.generateMinifiProperties(confDir, bootstrapProperties); @@ -317,7 +318,7 @@ private Process startMiNiFiProcess(final ProcessBuilder builder) throws IOExcept } private File getWorkingDir() throws IOException { - Properties props = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties props = bootstrapFileProvider.getBootstrapProperties(); File bootstrapConfigAbsoluteFile = bootstrapConfigFile.getAbsoluteFile(); File binDir = bootstrapConfigAbsoluteFile.getParentFile(); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ConfigurationChangeCoordinator.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ConfigurationChangeCoordinator.java index b6a11d2564351..fb187ae85744c 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ConfigurationChangeCoordinator.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ConfigurationChangeCoordinator.java @@ -17,26 +17,26 @@ package org.apache.nifi.minifi.bootstrap.configuration; +import static java.util.Optional.ofNullable; +import static java.util.function.Predicate.not; +import static java.util.stream.Collectors.toList; + import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Collections; import java.util.HashSet; -import java.util.Properties; import java.util.Set; import java.util.stream.Stream; import org.apache.nifi.minifi.bootstrap.RunMiNiFi; import org.apache.nifi.minifi.bootstrap.configuration.ingestors.interfaces.ChangeIngestor; import org.apache.nifi.minifi.bootstrap.service.BootstrapFileProvider; import org.apache.nifi.minifi.bootstrap.util.ByteBufferInputStream; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static java.util.Optional.ofNullable; -import static java.util.function.Predicate.not; -import static java.util.stream.Collectors.toList; - public class ConfigurationChangeCoordinator implements Closeable, ConfigurationChangeNotifier { public static final String NOTIFIER_INGESTORS_KEY = "nifi.minifi.notifier.ingestors"; @@ -94,7 +94,7 @@ private ListenerHandleResult notifyListener(ByteBuffer newFlowConfig, Configurat private void initialize() throws IOException { closeIngestors(); - Properties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); ofNullable(bootstrapProperties.getProperty(NOTIFIER_INGESTORS_KEY)) .filter(not(String::isBlank)) .map(ingestors -> ingestors.split(COMMA)) @@ -115,7 +115,7 @@ private void closeIngestors() { } } - private void instantiateIngestor(Properties bootstrapProperties, String ingestorClassname) { + private void instantiateIngestor(BootstrapProperties bootstrapProperties, String ingestorClassname) { try { Class ingestorClass = Class.forName(ingestorClassname); ChangeIngestor changeIngestor = (ChangeIngestor) ingestorClass.getDeclaredConstructor().newInstance(); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/AbstractPullChangeIngestor.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/AbstractPullChangeIngestor.java index 8d3b225df7e85..14c2405a59bb6 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/AbstractPullChangeIngestor.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/AbstractPullChangeIngestor.java @@ -18,7 +18,6 @@ package org.apache.nifi.minifi.bootstrap.configuration.ingestors; import java.io.IOException; -import java.util.Properties; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -26,20 +25,21 @@ import org.apache.nifi.minifi.bootstrap.ConfigurationFileHolder; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier; import org.apache.nifi.minifi.bootstrap.configuration.ingestors.interfaces.ChangeIngestor; +import org.apache.nifi.minifi.properties.BootstrapProperties; public abstract class AbstractPullChangeIngestor implements Runnable, ChangeIngestor { protected static final String DEFAULT_POLLING_PERIOD_MILLISECONDS = "300000"; protected final AtomicInteger pollingPeriodMS = new AtomicInteger(); - protected final AtomicReference properties = new AtomicReference<>(); + protected final AtomicReference properties = new AtomicReference<>(); private final ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); protected volatile ConfigurationChangeNotifier configurationChangeNotifier; @Override - public void initialize(Properties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { + public void initialize(BootstrapProperties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { this.configurationChangeNotifier = configurationChangeNotifier; this.properties.set(properties); } diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestor.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestor.java index 95a49a0d9935d..a77b41f0044fb 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestor.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestor.java @@ -39,7 +39,6 @@ import java.nio.file.WatchService; import java.util.Map; import java.util.Optional; -import java.util.Properties; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -50,6 +49,7 @@ import org.apache.nifi.minifi.bootstrap.configuration.differentiators.WholeConfigDifferentiator; import org.apache.nifi.minifi.bootstrap.configuration.ingestors.interfaces.ChangeIngestor; import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -84,7 +84,7 @@ public class FileChangeIngestor implements Runnable, ChangeIngestor { private long pollingSeconds; @Override - public void initialize(Properties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { + public void initialize(BootstrapProperties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { Path configFile = ofNullable(properties.getProperty(CONFIG_FILE_PATH_KEY)) .filter(not(String::isBlank)) .map(Path::of) @@ -190,7 +190,7 @@ private Supplier unableToFindDifferentiatorExceptionSu + " which does not correspond to any in the FileChangeIngestor Map:" + DIFFERENTIATOR_CONSTRUCTOR_MAP.keySet()); } - private void checkConfigFileLocationCorrectness(Properties properties, Path configFile) { + private void checkConfigFileLocationCorrectness(BootstrapProperties properties, Path configFile) { Path flowConfigFile = Path.of(properties.getProperty(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey())).toAbsolutePath(); Path rawFlowConfigFile = flowConfigFile.getParent().resolve(getBaseName(flowConfigFile.toString()) + RAW_EXTENSION); if (flowConfigFile.equals(configFile) || rawFlowConfigFile.equals(configFile)) { diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java index 0b1238f1f44df..21d666f02fa52 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java @@ -41,7 +41,6 @@ import java.security.KeyStore; import java.util.Arrays; import java.util.Map; -import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import java.util.stream.Stream; @@ -59,6 +58,7 @@ import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier; import org.apache.nifi.minifi.bootstrap.configuration.differentiators.Differentiator; import org.apache.nifi.minifi.bootstrap.configuration.differentiators.WholeConfigDifferentiator; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.apache.nifi.security.ssl.StandardKeyStoreBuilder; import org.apache.nifi.security.ssl.StandardSslContextBuilder; import org.apache.nifi.security.ssl.StandardTrustManagerBuilder; @@ -91,18 +91,18 @@ public class PullHttpChangeIngestor extends AbstractPullChangeIngestor { public static final String OVERRIDE_SECURITY = PULL_HTTP_BASE_KEY + ".override.security"; public static final String HTTP_HEADERS = PULL_HTTP_BASE_KEY + ".headers"; + protected static final String DEFAULT_CONNECT_TIMEOUT_MS = "5000"; + protected static final String DEFAULT_READ_TIMEOUT_MS = "15000"; + protected static final String DEFAULT_PATH = "/"; private static final Logger logger = LoggerFactory.getLogger(PullHttpChangeIngestor.class); private static final Map>> DIFFERENTIATOR_CONSTRUCTOR_MAP = Map.of( WHOLE_CONFIG_KEY, WholeConfigDifferentiator::getByteBufferDifferentiator ); private static final int NOT_MODIFIED_STATUS_CODE = 304; - private static final String DEFAULT_CONNECT_TIMEOUT_MS = "5000"; - private static final String DEFAULT_READ_TIMEOUT_MS = "15000"; private static final String DOUBLE_QUOTES = "\""; private static final String ETAG_HEADER = "ETag"; private static final String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization"; - private static final String DEFAULT_PATH = "/"; private static final int BAD_REQUEST_STATUS_CODE = 400; private static final String IF_NONE_MATCH_HEADER_KEY = "If-None-Match"; private static final String HTTP_HEADERS_SEPARATOR = ","; @@ -121,7 +121,7 @@ public class PullHttpChangeIngestor extends AbstractPullChangeIngestor { private volatile boolean useEtag = false; @Override - public void initialize(Properties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { + public void initialize(BootstrapProperties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { super.initialize(properties, configurationFileHolder, configurationChangeNotifier); pollingPeriodMS.set(Integer.parseInt(properties.getProperty(PULL_HTTP_POLLING_PERIOD_KEY, DEFAULT_POLLING_PERIOD_MILLISECONDS))); @@ -145,8 +145,7 @@ public void initialize(Properties properties, ConfigurationFileHolder configurat .collect(toMap(split -> ofNullable(split[0]).map(String::trim).orElse(EMPTY), split -> ofNullable(split[1]).map(String::trim).orElse(EMPTY))); logger.debug("Configured HTTP headers: {}", httpHeaders); - ofNullable(properties.get(PORT_KEY)) - .map(String.class::cast) + ofNullable(properties.getProperty(PORT_KEY)) .map(Integer::parseInt) .ifPresentOrElse( portReference::set, @@ -157,7 +156,7 @@ public void initialize(Properties properties, ConfigurationFileHolder configurat pathReference.set(path); queryReference.set(query); httpHeadersReference.set(httpHeaders); - useEtag = parseBoolean((String) properties.getOrDefault(USE_ETAG_KEY, FALSE.toString())); + useEtag = parseBoolean(properties.getProperty(USE_ETAG_KEY, FALSE.toString())); httpClientReference.set(null); @@ -263,7 +262,7 @@ public void run() { } } - private void setSslSocketFactory(OkHttpClient.Builder okHttpClientBuilder, Properties properties) { + private void setSslSocketFactory(OkHttpClient.Builder okHttpClientBuilder, BootstrapProperties properties) { String keystorePass = properties.getProperty(KEYSTORE_PASSWORD_KEY); KeyStore keyStore = buildKeyStore(properties, KEYSTORE_LOCATION_KEY, KEYSTORE_PASSWORD_KEY, KEYSTORE_TYPE_KEY); KeyStore truststore = buildKeyStore(properties, TRUSTSTORE_LOCATION_KEY, TRUSTSTORE_PASSWORD_KEY, TRUSTSTORE_TYPE_KEY); @@ -279,7 +278,7 @@ private void setSslSocketFactory(OkHttpClient.Builder okHttpClientBuilder, Prope okHttpClientBuilder.sslSocketFactory(sslSocketFactory, trustManager); } - private KeyStore buildKeyStore(Properties properties, String locationKey, String passKey, String typeKey) { + private KeyStore buildKeyStore(BootstrapProperties properties, String locationKey, String passKey, String typeKey) { String keystoreLocation = ofNullable(properties.getProperty(locationKey)) .filter(StringUtils::isNotBlank) .orElseThrow(() -> new IllegalArgumentException(locationKey + " is null or empty")); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestor.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestor.java index 1b9c39012555a..d8c35984cf940 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestor.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestor.java @@ -32,7 +32,6 @@ import java.nio.ByteBuffer; import java.security.KeyStore; import java.util.Map; -import java.util.Properties; import java.util.function.Supplier; import javax.net.ssl.SSLContext; import org.apache.nifi.jetty.configuration.connector.StandardServerConnectorFactory; @@ -42,6 +41,7 @@ import org.apache.nifi.minifi.bootstrap.configuration.differentiators.Differentiator; import org.apache.nifi.minifi.bootstrap.configuration.differentiators.WholeConfigDifferentiator; import org.apache.nifi.minifi.bootstrap.configuration.ingestors.interfaces.ChangeIngestor; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.apache.nifi.security.ssl.StandardKeyStoreBuilder; import org.apache.nifi.security.ssl.StandardSslContextBuilder; import org.apache.nifi.security.util.KeystoreType; @@ -100,7 +100,7 @@ public RestChangeIngestor() { } @Override - public void initialize(Properties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { + public void initialize(BootstrapProperties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier) { logger.info("Initializing RestChangeIngestor"); this.differentiator = ofNullable(properties.getProperty(DIFFERENTIATOR_KEY)) .filter(not(String::isBlank)) @@ -154,7 +154,7 @@ public int getPort() { return ((ServerConnector) jetty.getConnectors()[0]).getLocalPort(); } - private void createConnector(Properties properties) { + private void createConnector(BootstrapProperties properties) { ServerConnector http = new ServerConnector(jetty); http.setPort(Integer.parseInt(properties.getProperty(PORT_KEY, "0"))); @@ -167,7 +167,7 @@ private void createConnector(Properties properties) { logger.info("Added an http connector on the host '{}' and port '{}'", http.getHost(), http.getPort()); } - private void createSecureConnector(Properties properties) { + private void createSecureConnector(BootstrapProperties properties) { KeyStore keyStore; KeyStore trustStore = null; diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/interfaces/ChangeIngestor.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/interfaces/ChangeIngestor.java index dcd39cd6d11d7..96e5c4e50c581 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/interfaces/ChangeIngestor.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/interfaces/ChangeIngestor.java @@ -17,14 +17,13 @@ package org.apache.nifi.minifi.bootstrap.configuration.ingestors.interfaces; +import java.io.IOException; import org.apache.nifi.minifi.bootstrap.ConfigurationFileHolder; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier; - -import java.io.IOException; -import java.util.Properties; +import org.apache.nifi.minifi.properties.BootstrapProperties; public interface ChangeIngestor { - void initialize(Properties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier); + void initialize(BootstrapProperties properties, ConfigurationFileHolder configurationFileHolder, ConfigurationChangeNotifier configurationChangeNotifier); void start(); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java index 1957b05aec9b6..96cc04ad29061 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapFileProvider.java @@ -22,7 +22,6 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -35,6 +34,8 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.minifi.properties.BootstrapProperties; +import org.apache.nifi.minifi.properties.BootstrapPropertiesLoader; import org.apache.nifi.util.file.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,6 +62,10 @@ public BootstrapFileProvider(File bootstrapConfigFile) { this.bootstrapConfigFile = bootstrapConfigFile; } + public String getBootstrapFilePath() { + return bootstrapConfigFile.getAbsolutePath(); + } + public static File getBootstrapConfFile() { File bootstrapConfigFile = Optional.ofNullable(System.getProperty(BOOTSTRAP_CONFIG_FILE_SYSTEM_PROPERTY_KEY)) .map(File::new) @@ -110,19 +115,12 @@ public File getBootstrapConfNewFile() { return newFile; } - public Properties getBootstrapProperties() throws IOException { - if (!bootstrapConfigFile.exists()) { - throw new FileNotFoundException(bootstrapConfigFile.getAbsolutePath()); - } - - Properties bootstrapProperties = BootstrapProperties.getInstance(); - try (FileInputStream fis = new FileInputStream(bootstrapConfigFile)) { - bootstrapProperties.load(fis); - } - - logProperties("Bootstrap", bootstrapProperties); + public BootstrapProperties getBootstrapProperties() { + return BootstrapPropertiesLoader.load(bootstrapConfigFile); + } - return bootstrapProperties; + public BootstrapProperties getProtectedBootstrapProperties() { + return BootstrapPropertiesLoader.loadProtectedProperties(bootstrapConfigFile).getApplicationProperties(); } public Properties getStatusProperties() { diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProvider.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProvider.java index b75c0157e1bec..ebe6f36b31b75 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProvider.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProvider.java @@ -18,7 +18,7 @@ package org.apache.nifi.minifi.bootstrap.service; import java.io.IOException; -import java.util.Properties; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,7 +36,7 @@ public GracefulShutdownParameterProvider(BootstrapFileProvider bootstrapFileProv } public int getGracefulShutdownSeconds() throws IOException { - Properties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); String gracefulShutdown = bootstrapProperties.getProperty(GRACEFUL_SHUTDOWN_PROP, DEFAULT_GRACEFUL_SHUTDOWN_VALUE); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java index ea0f04dd84758..5925ac3b5e298 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiConfigurationChangeListener.java @@ -32,7 +32,6 @@ import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.file.Path; -import java.util.Properties; import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.io.FilenameUtils; import org.apache.nifi.controller.flow.VersionedDataflow; @@ -42,6 +41,7 @@ import org.apache.nifi.minifi.commons.api.MiNiFiProperties; import org.apache.nifi.minifi.commons.service.FlowEnrichService; import org.apache.nifi.minifi.commons.service.FlowSerDeService; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; public class MiNiFiConfigurationChangeListener implements ConfigurationChangeListener { @@ -76,7 +76,7 @@ public void handleChange(InputStream flowConfigInputStream) throws Configuration Path currentRawFlowConfigFile = null; Path backupRawFlowConfigFile = null; try { - Properties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); currentFlowConfigFile = Path.of(bootstrapProperties.getProperty(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey())).toAbsolutePath(); backupFlowConfigFile = Path.of(currentFlowConfigFile + BACKUP_EXTENSION); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiExecCommandProvider.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiExecCommandProvider.java index 8f2b0fce08bde..0e99379a6df8d 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiExecCommandProvider.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiExecCommandProvider.java @@ -28,12 +28,13 @@ import java.nio.file.Path; import java.util.List; import java.util.Optional; -import java.util.Properties; import java.util.stream.Stream; +import org.apache.nifi.minifi.properties.BootstrapProperties; public class MiNiFiExecCommandProvider { public static final String LOG_DIR = "org.apache.nifi.minifi.bootstrap.config.log.dir"; + public static final String MINIFI_BOOTSTRAP_CONF_FILE_PATH = "minifi.bootstrap.conf.file.path"; public static final String DEFAULT_LOG_DIR = "./logs"; public static final String APP_LOG_FILE_NAME = "org.apache.nifi.minifi.bootstrap.config.log.app.file.name"; @@ -73,7 +74,7 @@ public MiNiFiExecCommandProvider(BootstrapFileProvider bootstrapFileProvider) { this.bootstrapFileProvider = bootstrapFileProvider; } - public static String getMiNiFiPropertiesPath(Properties props, File confDir) { + public static String getMiNiFiPropertiesPath(BootstrapProperties props, File confDir) { return ofNullable(props.getProperty(PROPERTIES_FILE_KEY)) .orElseGet(() -> ofNullable(confDir) .filter(File::exists) @@ -92,7 +93,7 @@ public static String getMiNiFiPropertiesPath(Properties props, File confDir) { * @throws IOException throws IOException if any of the configuration file read fails */ public List getMiNiFiExecCommand(int listenPort, File workingDir) throws IOException { - Properties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); + BootstrapProperties bootstrapProperties = bootstrapFileProvider.getBootstrapProperties(); File confDir = getFile(bootstrapProperties.getProperty(CONF_DIR_KEY, DEFAULT_CONF_DIR).trim(), workingDir); File libDir = getFile(bootstrapProperties.getProperty(LIB_DIR_KEY, DEFAULT_LIB_DIR).trim(), workingDir); @@ -107,6 +108,7 @@ public List getMiNiFiExecCommand(int listenPort, File workingDir) throws List javaAdditionalArgs = getJavaAdditionalArgs(bootstrapProperties); List systemProperties = List.of( systemProperty(PROPERTIES_FILE_PATH, getMiNiFiPropertiesPath(bootstrapProperties, confDir)), + systemProperty(MINIFI_BOOTSTRAP_CONF_FILE_PATH, bootstrapFileProvider.getBootstrapFilePath()), systemProperty(NIFI_BOOTSTRAP_LISTEN_PORT, listenPort), systemProperty(APP, MINIFI_CLASS_NAME), systemProperty(LOG_DIR, minifiLogDir), @@ -116,8 +118,7 @@ public List getMiNiFiExecCommand(int listenPort, File workingDir) throws systemProperty(BOOTSTRAP_LOG_FILE_EXTENSION, minifiBootstrapLogFileExtension) ); - return List.of(javaCommand, javaAdditionalArgs, systemProperties, List.of(MINIFI_FULLY_QUALIFIED_CLASS_NAME)) - .stream() + return Stream.of(javaCommand, javaAdditionalArgs, systemProperties, List.of(MINIFI_FULLY_QUALIFIED_CLASS_NAME)) .flatMap(List::stream) .toList(); } @@ -127,7 +128,7 @@ private File getFile(String filename, File workingDir) { return file.isAbsolute() ? file : new File(workingDir, filename).getAbsoluteFile(); } - private String getJavaCommand(Properties bootstrapProperties) { + private String getJavaCommand(BootstrapProperties bootstrapProperties) { String javaCommand = bootstrapProperties.getProperty(JAVA_COMMAND_KEY, DEFAULT_JAVA_CMD); return javaCommand.equals(DEFAULT_JAVA_CMD) ? ofNullable(System.getenv(JAVA_HOME_ENVIRONMENT_VARIABLE)) @@ -159,15 +160,16 @@ private String buildClassPath(File confDir, File libDir) { .collect(joining(File.pathSeparator)); } - private List getJavaAdditionalArgs(Properties props) { - return props.entrySet() + private List getJavaAdditionalArgs(BootstrapProperties props) { + return props.getPropertyKeys() .stream() - .filter(entry -> ((String) entry.getKey()).startsWith(JAVA_ARG_KEY_PREFIX)) - .map(entry -> (String) entry.getValue()) + .filter(key -> key.startsWith(JAVA_ARG_KEY_PREFIX)) + .map(props::getProperty) .toList(); } private String systemProperty(String key, Object value) { return String.format(SYSTEM_PROPERTY_TEMPLATE, key, value); } + } \ No newline at end of file diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java index 939ded36f756f..42c55c8bf6a09 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGenerator.java @@ -19,6 +19,7 @@ import static java.lang.String.join; import static java.lang.System.getProperty; +import static java.util.Map.entry; import static java.util.Optional.ofNullable; import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -59,6 +60,7 @@ import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeException; import org.apache.nifi.minifi.bootstrap.util.OrderedProperties; import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.apache.nifi.util.NiFiProperties; public class MiNiFiPropertiesGenerator { @@ -139,15 +141,19 @@ public class MiNiFiPropertiesGenerator { Triple.of(NiFiProperties.FLOW_CONFIGURATION_FILE, "./conf/flow.json.gz", EMPTY) ); - static final Map MINIFI_TO_NIFI_PROPERTY_MAPPING = Map.of( - MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey(), NiFiProperties.FLOW_CONFIGURATION_FILE, - MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE.getKey(), NiFiProperties.SECURITY_KEYSTORE, - MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_TYPE.getKey(), NiFiProperties.SECURITY_KEYSTORE_TYPE, - MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_PASSWD.getKey(), NiFiProperties.SECURITY_KEYSTORE_PASSWD, - MiNiFiProperties.NIFI_MINIFI_SECURITY_KEY_PASSWD.getKey(), NiFiProperties.SECURITY_KEY_PASSWD, - MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE.getKey(), NiFiProperties.SECURITY_TRUSTSTORE, - MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE_TYPE.getKey(), NiFiProperties.SECURITY_TRUSTSTORE_TYPE, - MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE_PASSWD.getKey(), NiFiProperties.SECURITY_TRUSTSTORE_PASSWD + static final String PROTECTED_POSTFIX = ".protected"; + static final Map MINIFI_TO_NIFI_PROPERTY_MAPPING = Map.ofEntries( + entry(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey(), NiFiProperties.FLOW_CONFIGURATION_FILE), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE.getKey(), NiFiProperties.SECURITY_KEYSTORE), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_TYPE.getKey(), NiFiProperties.SECURITY_KEYSTORE_TYPE), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_PASSWD.getKey(), NiFiProperties.SECURITY_KEYSTORE_PASSWD), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_PASSWD.getKey() + PROTECTED_POSTFIX, NiFiProperties.SECURITY_KEYSTORE_PASSWD + PROTECTED_POSTFIX), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_KEY_PASSWD.getKey(), NiFiProperties.SECURITY_KEY_PASSWD), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_KEY_PASSWD.getKey() + PROTECTED_POSTFIX, NiFiProperties.SECURITY_KEY_PASSWD + PROTECTED_POSTFIX), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE.getKey(), NiFiProperties.SECURITY_TRUSTSTORE), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE_TYPE.getKey(), NiFiProperties.SECURITY_TRUSTSTORE_TYPE), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE_PASSWD.getKey(), NiFiProperties.SECURITY_TRUSTSTORE_PASSWD), + entry(MiNiFiProperties.NIFI_MINIFI_SECURITY_TRUSTSTORE_PASSWD.getKey() + PROTECTED_POSTFIX, NiFiProperties.SECURITY_TRUSTSTORE_PASSWD + PROTECTED_POSTFIX) ); static final String DEFAULT_SENSITIVE_PROPERTIES_ENCODING_ALGORITHM = "NIFI_PBKDF2_AES_GCM_256"; @@ -160,7 +166,7 @@ public class MiNiFiPropertiesGenerator { public static final String FILE_EXTENSION_DELIMITER = "."; - public void generateMinifiProperties(String configDirectory, Properties bootstrapProperties) throws ConfigurationChangeException { + public void generateMinifiProperties(String configDirectory, BootstrapProperties bootstrapProperties) throws ConfigurationChangeException { String minifiPropertiesFileName = Path.of(getMiNiFiPropertiesPath(bootstrapProperties, new File(configDirectory))).getFileName().toString(); Path minifiPropertiesFile = Path.of(configDirectory, minifiPropertiesFileName); @@ -188,22 +194,22 @@ private Map extractSensitivePropertiesConfiguration(Path minifiP ); } - private OrderedProperties prepareMinifiProperties(Properties bootstrapProperties, Map existingSensitivePropertiesConfiguration) { + private OrderedProperties prepareMinifiProperties(BootstrapProperties bootstrapProperties, Map existingSensitivePropertiesConfiguration) { OrderedProperties minifiProperties = new OrderedProperties(); NIFI_PROPERTIES_WITH_DEFAULT_VALUES_AND_COMMENTS .forEach(triple -> minifiProperties.setProperty(triple.getLeft(), triple.getMiddle(), triple.getRight())); - getNonBlankPropertiesWithPredicate(bootstrapProperties, entry -> MINIFI_TO_NIFI_PROPERTY_MAPPING.containsKey(entry.getKey())) + getNonBlankPropertiesWithPredicate(bootstrapProperties, MINIFI_TO_NIFI_PROPERTY_MAPPING::containsKey) .forEach(entry -> minifiProperties.setProperty(MINIFI_TO_NIFI_PROPERTY_MAPPING.get(entry.getKey()), entry.getValue())); getSensitiveProperties(bootstrapProperties, existingSensitivePropertiesConfiguration) .forEach(entry -> minifiProperties.setProperty(entry.getKey(), entry.getValue())); - getNonBlankPropertiesWithPredicate(bootstrapProperties, entry -> ((String) entry.getKey()).startsWith(C2_PROPERTY_PREFIX)) + getNonBlankPropertiesWithPredicate(bootstrapProperties, key -> key.startsWith(C2_PROPERTY_PREFIX)) .forEach(entry -> minifiProperties.setProperty(entry.getKey(), entry.getValue())); - getNonBlankPropertiesWithPredicate(bootstrapProperties, entry -> ((String) entry.getKey()).startsWith(NIFI_PREFIX)) + getNonBlankPropertiesWithPredicate(bootstrapProperties, key -> key.startsWith(NIFI_PREFIX)) .forEach(entry -> minifiProperties.setProperty(entry.getKey(), entry.getValue())); bootstrapFileAndLogProperties() @@ -212,19 +218,19 @@ private OrderedProperties prepareMinifiProperties(Properties bootstrapProperties return minifiProperties; } - private List> getNonBlankPropertiesWithPredicate(Properties bootstrapProperties, Predicate predicate) { + private List> getNonBlankPropertiesWithPredicate(BootstrapProperties bootstrapProperties, Predicate predicate) { return ofNullable(bootstrapProperties) - .map(Properties::entrySet) + .map(BootstrapProperties::getPropertyKeys) .orElseGet(Set::of) .stream() .filter(predicate) - .filter(entry -> isNotBlank((String) entry.getValue())) - .map(entry -> Pair.of((String) entry.getKey(), (String) entry.getValue())) + .map(key -> Pair.of(key, bootstrapProperties.getProperty(key))) + .filter(pair -> isNotBlank(pair.getValue())) .sorted((o1, o2) -> Comparator.naturalOrder().compare(o1.getKey(), o2.getKey())) .toList(); } - private List> getSensitiveProperties(Properties bootstrapProperties, Map existingSensitivePropertiesConfiguration) { + private List> getSensitiveProperties(BootstrapProperties bootstrapProperties, Map existingSensitivePropertiesConfiguration) { return existingSensitivePropertiesConfiguration.isEmpty() ? List.of( Pair.of(NiFiProperties.SENSITIVE_PROPS_KEY, diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/PeriodicStatusReporterManager.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/PeriodicStatusReporterManager.java index 6b9833774b5df..1db737e76b3d9 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/PeriodicStatusReporterManager.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/PeriodicStatusReporterManager.java @@ -17,35 +17,35 @@ package org.apache.nifi.minifi.bootstrap.service; +import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_STATUS_REPORTER_COMPONENTS; + import java.lang.reflect.InvocationTargetException; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Properties; import java.util.Set; import org.apache.nifi.minifi.bootstrap.MiNiFiParameters; import org.apache.nifi.minifi.bootstrap.MiNiFiStatus; import org.apache.nifi.minifi.bootstrap.QueryableStatusAggregator; import org.apache.nifi.minifi.bootstrap.status.PeriodicStatusReporter; import org.apache.nifi.minifi.commons.status.FlowStatusReport; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_STATUS_REPORTER_COMPONENTS; - public class PeriodicStatusReporterManager implements QueryableStatusAggregator { private static final Logger LOGGER = LoggerFactory.getLogger(PeriodicStatusReporterManager.class); private static final String FLOW_STATUS_REPORT_CMD = "FLOW_STATUS_REPORT"; - private final Properties bootstrapProperties; + private final BootstrapProperties bootstrapProperties; private final MiNiFiStatusProvider miNiFiStatusProvider; private final MiNiFiCommandSender miNiFiCommandSender; private final MiNiFiParameters miNiFiParameters; private Set periodicStatusReporters = Collections.emptySet(); - public PeriodicStatusReporterManager(Properties bootstrapProperties, MiNiFiStatusProvider miNiFiStatusProvider, MiNiFiCommandSender miNiFiCommandSender, + public PeriodicStatusReporterManager(BootstrapProperties bootstrapProperties, MiNiFiStatusProvider miNiFiStatusProvider, MiNiFiCommandSender miNiFiCommandSender, MiNiFiParameters miNiFiParameters) { this.bootstrapProperties = bootstrapProperties; this.miNiFiStatusProvider = miNiFiStatusProvider; diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/UpdatePropertiesService.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/UpdatePropertiesService.java index 36e68f7124744..a6058f953c701 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/UpdatePropertiesService.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/UpdatePropertiesService.java @@ -25,10 +25,10 @@ import java.io.IOException; import java.nio.file.Files; import java.util.Optional; -import java.util.Properties; import org.apache.nifi.minifi.bootstrap.RunMiNiFi; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeException; import org.apache.nifi.minifi.commons.api.MiNiFiCommandState; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; public class UpdatePropertiesService { @@ -59,7 +59,7 @@ public Optional handleUpdate() { Files.copy(bootstrapFileProvider.getBootstrapConfNewFile().toPath(), bootstrapConfigFile.toPath(), REPLACE_EXISTING); // already from new - commandState = generateConfigfilesBasedOnNewProperties(bootstrapConfigFile, bootstrapSwapConfigFile, bootstrapFileProvider.getBootstrapProperties()); + commandState = generateConfigfilesBasedOnNewProperties(bootstrapConfigFile, bootstrapSwapConfigFile, bootstrapFileProvider.getProtectedBootstrapProperties()); } catch (Exception e) { commandState = Optional.of(MiNiFiCommandState.NOT_APPLIED_WITHOUT_RESTART); logger.error("Failed to load new bootstrap properties", e); @@ -67,7 +67,7 @@ public Optional handleUpdate() { return commandState; } - private Optional generateConfigfilesBasedOnNewProperties(File bootstrapConfigFile, File bootstrapSwapConfigFile, Properties bootstrapProperties) + private Optional generateConfigfilesBasedOnNewProperties(File bootstrapConfigFile, File bootstrapSwapConfigFile, BootstrapProperties bootstrapProperties) throws IOException, ConfigurationChangeException { Optional commandState = Optional.empty(); try { diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/PeriodicStatusReporter.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/PeriodicStatusReporter.java index 0816aa79ea921..6cb53617ff671 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/PeriodicStatusReporter.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/PeriodicStatusReporter.java @@ -17,12 +17,11 @@ package org.apache.nifi.minifi.bootstrap.status; -import org.apache.nifi.minifi.bootstrap.QueryableStatusAggregator; - -import java.util.Properties; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.apache.nifi.minifi.bootstrap.QueryableStatusAggregator; +import org.apache.nifi.minifi.properties.BootstrapProperties; public abstract class PeriodicStatusReporter { @@ -38,7 +37,7 @@ public abstract class PeriodicStatusReporter { * * @param properties from the bootstrap configuration */ - public abstract void initialize(Properties properties, QueryableStatusAggregator queryableStatusAggregator); + public abstract void initialize(BootstrapProperties properties, QueryableStatusAggregator queryableStatusAggregator); /** * Begins the associated reporting service provided by the given implementation. In most implementations, no action will occur until this method is invoked. The implementing class must have set diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLogger.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLogger.java index 2d6f7fa5bb031..0f58dbdcbf08f 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLogger.java +++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLogger.java @@ -22,11 +22,11 @@ import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY; import java.io.IOException; -import java.util.Properties; import org.apache.nifi.logging.LogLevel; import org.apache.nifi.minifi.bootstrap.QueryableStatusAggregator; import org.apache.nifi.minifi.bootstrap.status.PeriodicStatusReporter; import org.apache.nifi.minifi.commons.status.FlowStatusReport; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,7 +41,7 @@ public class StatusLogger extends PeriodicStatusReporter { static final String ENCOUNTERED_IO_EXCEPTION = "Encountered an IO Exception while attempting to query the flow status."; @Override - public void initialize(Properties properties, QueryableStatusAggregator queryableStatusAggregator) { + public void initialize(BootstrapProperties properties, QueryableStatusAggregator queryableStatusAggregator) { this.queryableStatusAggregator = queryableStatusAggregator; String periodString = properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey()); diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestorTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestorTest.java index cc967e552c06a..08dbc4b836ca0 100644 --- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestorTest.java +++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/FileChangeIngestorTest.java @@ -18,8 +18,11 @@ package org.apache.nifi.minifi.bootstrap.configuration.ingestors; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import static org.apache.nifi.minifi.bootstrap.configuration.ingestors.FileChangeIngestor.DEFAULT_POLLING_PERIOD_INTERVAL; import static org.apache.nifi.minifi.bootstrap.configuration.ingestors.PullHttpChangeIngestor.PULL_HTTP_BASE_KEY; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,12 +34,12 @@ import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.util.Collections; -import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; import org.apache.nifi.minifi.bootstrap.ConfigurationFileHolder; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier; import org.apache.nifi.minifi.bootstrap.configuration.differentiators.Differentiator; import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -49,7 +52,7 @@ public class FileChangeIngestorTest { private FileChangeIngestor notifierSpy; private WatchService mockWatchService; - private Properties testProperties; + private BootstrapProperties testProperties; private Differentiator mockDifferentiator; private ConfigurationChangeNotifier testNotifier; @@ -60,15 +63,15 @@ public void setUp() { notifierSpy = Mockito.spy(new FileChangeIngestor()); mockDifferentiator = mock(Differentiator.class); testNotifier = mock(ConfigurationChangeNotifier.class); + testProperties = mock(BootstrapProperties.class); setMocks(); - testProperties = new Properties(); - testProperties.put(FileChangeIngestor.CONFIG_FILE_PATH_KEY, TEST_CONFIG_PATH); - testProperties.put(PullHttpChangeIngestor.OVERRIDE_SECURITY, "true"); - testProperties.put(PULL_HTTP_BASE_KEY + ".override.core", "true"); - testProperties.put(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY, FileChangeIngestor.DEFAULT_POLLING_PERIOD_INTERVAL); - testProperties.put(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey(), MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getDefaultValue()); + when(testProperties.getProperty(FileChangeIngestor.CONFIG_FILE_PATH_KEY)).thenReturn(TEST_CONFIG_PATH); + when(testProperties.getProperty(PullHttpChangeIngestor.OVERRIDE_SECURITY)).thenReturn("true"); + when(testProperties.getProperty(PULL_HTTP_BASE_KEY + ".override.core")).thenReturn("true"); + when(testProperties.getProperty(eq(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY), any())).thenReturn(String.valueOf(DEFAULT_POLLING_PERIOD_INTERVAL)); + when(testProperties.getProperty(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey())).thenReturn(MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getDefaultValue()); } @AfterEach @@ -78,7 +81,7 @@ public void tearDown() { @Test public void testInitializeInvalidFile() { - testProperties.put(FileChangeIngestor.CONFIG_FILE_PATH_KEY, "/land/of/make/believe"); + when(testProperties.getProperty(FileChangeIngestor.CONFIG_FILE_PATH_KEY)).thenReturn("/land/of/make/believe"); assertThrows(IllegalStateException.class, () -> notifierSpy.initialize(testProperties, mock(ConfigurationFileHolder.class), mock(ConfigurationChangeNotifier.class))); } @@ -89,13 +92,12 @@ public void testInitializeValidFile() { @Test public void testInitializeInvalidPollingPeriod() { - testProperties.put(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY, "abc"); + when(testProperties.getProperty(eq(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY), any())).thenReturn("abc"); assertThrows(IllegalStateException.class, () -> notifierSpy.initialize(testProperties, mock(ConfigurationFileHolder.class), mock(ConfigurationChangeNotifier.class))); } @Test public void testInitializeUseDefaultPolling() { - testProperties.remove(FileChangeIngestor.POLLING_PERIOD_INTERVAL_KEY); notifierSpy.initialize(testProperties, mock(ConfigurationFileHolder.class), mock(ConfigurationChangeNotifier.class)); } diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java index 2f7d644ef3ac5..8597da3168e28 100644 --- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java +++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java @@ -25,7 +25,8 @@ import java.nio.ByteBuffer; import java.security.KeyStore; import java.util.Collections; -import java.util.Properties; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; @@ -35,6 +36,7 @@ import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeListener; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier; import org.apache.nifi.minifi.bootstrap.configuration.ListenerHandleResult; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.apache.nifi.security.ssl.StandardKeyStoreBuilder; import org.apache.nifi.security.ssl.StandardSslContextBuilder; import org.apache.nifi.security.ssl.StandardTrustManagerBuilder; @@ -50,16 +52,17 @@ public class RestChangeIngestorSSLTest extends RestChangeIngestorCommonTest { public static void setUpHttps() throws IOException, InterruptedException { final TlsConfiguration tlsConfiguration = new TemporaryKeyStoreBuilder().trustStoreType("JKS").build(); - Properties properties = new Properties(); - properties.setProperty(RestChangeIngestor.TRUSTSTORE_LOCATION_KEY, tlsConfiguration.getTruststorePath()); - properties.setProperty(RestChangeIngestor.TRUSTSTORE_PASSWORD_KEY, tlsConfiguration.getTruststorePassword()); - properties.setProperty(RestChangeIngestor.TRUSTSTORE_TYPE_KEY, tlsConfiguration.getTruststoreType().getType()); - properties.setProperty(RestChangeIngestor.KEYSTORE_LOCATION_KEY, tlsConfiguration.getKeystorePath()); - properties.setProperty(RestChangeIngestor.KEYSTORE_PASSWORD_KEY, tlsConfiguration.getKeystorePassword()); - properties.setProperty(RestChangeIngestor.KEYSTORE_TYPE_KEY, tlsConfiguration.getKeystoreType().getType()); - properties.setProperty(RestChangeIngestor.NEED_CLIENT_AUTH_KEY, "false"); - properties.put(PullHttpChangeIngestor.OVERRIDE_SECURITY, "true"); - properties.put(PULL_HTTP_BASE_KEY + ".override.core", "true"); + Map bootstrapProperties = new HashMap<>(); + bootstrapProperties.put(RestChangeIngestor.TRUSTSTORE_LOCATION_KEY, tlsConfiguration.getTruststorePath()); + bootstrapProperties.put(RestChangeIngestor.TRUSTSTORE_PASSWORD_KEY, tlsConfiguration.getTruststorePassword()); + bootstrapProperties.put(RestChangeIngestor.TRUSTSTORE_TYPE_KEY, tlsConfiguration.getTruststoreType().getType()); + bootstrapProperties.put(RestChangeIngestor.KEYSTORE_LOCATION_KEY, tlsConfiguration.getKeystorePath()); + bootstrapProperties.put(RestChangeIngestor.KEYSTORE_PASSWORD_KEY, tlsConfiguration.getKeystorePassword()); + bootstrapProperties.put(RestChangeIngestor.KEYSTORE_TYPE_KEY, tlsConfiguration.getKeystoreType().getType()); + bootstrapProperties.put(RestChangeIngestor.NEED_CLIENT_AUTH_KEY, "false"); + bootstrapProperties.put(PullHttpChangeIngestor.OVERRIDE_SECURITY, "true"); + bootstrapProperties.put(PULL_HTTP_BASE_KEY + ".override.core", "true"); + BootstrapProperties properties = new BootstrapProperties(bootstrapProperties); restChangeIngestor = new RestChangeIngestor(); diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorTest.java index 64142eccbf683..57c395975411d 100644 --- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorTest.java +++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorTest.java @@ -18,15 +18,20 @@ package org.apache.nifi.minifi.bootstrap.configuration.ingestors; import static org.apache.nifi.minifi.bootstrap.configuration.ingestors.PullHttpChangeIngestor.PULL_HTTP_BASE_KEY; +import static org.apache.nifi.minifi.bootstrap.configuration.ingestors.RestChangeIngestor.HOST_KEY; +import static org.apache.nifi.minifi.bootstrap.configuration.ingestors.RestChangeIngestor.PORT_KEY; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.net.MalformedURLException; import java.nio.ByteBuffer; -import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; import okhttp3.OkHttpClient; import org.apache.nifi.minifi.bootstrap.ConfigurationFileHolder; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.mockito.Mockito; @@ -35,9 +40,11 @@ public class RestChangeIngestorTest extends RestChangeIngestorCommonTest { @BeforeAll public static void setUp() throws InterruptedException, MalformedURLException { - Properties properties = new Properties(); - properties.put(PullHttpChangeIngestor.OVERRIDE_SECURITY, "true"); - properties.put(PULL_HTTP_BASE_KEY + ".override.core", "true"); + BootstrapProperties properties = mock(BootstrapProperties.class); + when(properties.getProperty(PullHttpChangeIngestor.OVERRIDE_SECURITY)).thenReturn("true"); + when(properties.getProperty(PULL_HTTP_BASE_KEY + ".override.core")).thenReturn("true"); + when(properties.getProperty(eq(PORT_KEY), any())).thenReturn("0"); + when(properties.getProperty(eq(HOST_KEY), any())).thenReturn("localhost"); restChangeIngestor = new RestChangeIngestor(); testNotifier = Mockito.mock(ConfigurationChangeNotifier.class); diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProviderTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProviderTest.java index 87f3ecd810294..e580b1cadf504 100644 --- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProviderTest.java +++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/GracefulShutdownParameterProviderTest.java @@ -20,10 +20,14 @@ import static org.apache.nifi.minifi.bootstrap.service.GracefulShutdownParameterProvider.DEFAULT_GRACEFUL_SHUTDOWN_VALUE; import static org.apache.nifi.minifi.bootstrap.service.GracefulShutdownParameterProvider.GRACEFUL_SHUTDOWN_PROP; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.IOException; -import java.util.Properties; +import java.util.Optional; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -46,10 +50,11 @@ class GracefulShutdownParameterProviderTest { @NullSource @ValueSource(strings = {"notAnInteger", "-1"}) void testGetBootstrapPropertiesShouldReturnDefaultShutdownPropertyValue(String shutdownProperty) throws IOException { - Properties properties = new Properties(); - if (shutdownProperty != null) { - properties.setProperty(GRACEFUL_SHUTDOWN_PROP, shutdownProperty); - } + BootstrapProperties properties = mock(BootstrapProperties.class); + + when(properties.getProperty(eq(GRACEFUL_SHUTDOWN_PROP), any())) + .thenReturn(Optional.ofNullable(shutdownProperty).orElse(DEFAULT_GRACEFUL_SHUTDOWN_VALUE)); + when(bootstrapFileProvider.getBootstrapProperties()).thenReturn(properties); assertEquals(Integer.parseInt(DEFAULT_GRACEFUL_SHUTDOWN_VALUE), gracefulShutdownParameterProvider.getGracefulShutdownSeconds()); @@ -57,8 +62,8 @@ void testGetBootstrapPropertiesShouldReturnDefaultShutdownPropertyValue(String s @Test void testGetBootstrapPropertiesShouldReturnShutdownPropertyValue() throws IOException { - Properties properties = new Properties(); - properties.setProperty(GRACEFUL_SHUTDOWN_PROP, "1000"); + BootstrapProperties properties = mock(BootstrapProperties.class); + when(properties.getProperty(eq(GRACEFUL_SHUTDOWN_PROP), any())).thenReturn("1000"); when(bootstrapFileProvider.getBootstrapProperties()).thenReturn(properties); assertEquals(1000, gracefulShutdownParameterProvider.getGracefulShutdownSeconds()); diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGeneratorTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGeneratorTest.java index 1ee026b445e83..9034e99b2b275 100644 --- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGeneratorTest.java +++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/service/MiNiFiPropertiesGeneratorTest.java @@ -53,6 +53,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeException; import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.apache.nifi.util.NiFiProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -82,7 +83,7 @@ public void setup() throws IOException { @Test public void testGenerateDefaultNiFiProperties() throws ConfigurationChangeException { // given - Properties bootstrapProperties = createBootstrapProperties(Map.of()); + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of()); // when testPropertiesGenerator.generateMinifiProperties(configDirectory.toString(), bootstrapProperties); @@ -101,7 +102,7 @@ public void testGenerateDefaultNiFiProperties() throws ConfigurationChangeExcept @Test public void testMiNiFiPropertiesMappedToAppropriateNiFiProperties() throws ConfigurationChangeException { // given - Properties bootstrapProperties = createBootstrapProperties(Stream.of( + BootstrapProperties bootstrapProperties = createBootstrapProperties(Stream.of( MiNiFiProperties.NIFI_MINIFI_FLOW_CONFIG.getKey(), MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE.getKey(), MiNiFiProperties.NIFI_MINIFI_SECURITY_KEYSTORE_TYPE.getKey(), @@ -126,7 +127,7 @@ public void testMiNiFiPropertiesMappedToAppropriateNiFiProperties() throws Confi @Test public void testSensitivePropertiesAreGeneratedWhenNotProvidedInBootstrap() throws ConfigurationChangeException { // given - Properties bootstrapProperties = createBootstrapProperties(Map.of()); + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of()); // when testPropertiesGenerator.generateMinifiProperties(configDirectory.toString(), bootstrapProperties); @@ -142,7 +143,7 @@ public void testSensitivePropertiesAreUsedWhenProvidedInBootstrap() throws Confi // given String sensitivePropertiesKey = "sensitive_properties_key"; String sensitivePropertiesAlgorithm = "sensitive_properties_algorithm"; - Properties bootstrapProperties = createBootstrapProperties(Map.of( + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of( MiNiFiProperties.NIFI_MINIFI_SENSITIVE_PROPS_KEY.getKey(), sensitivePropertiesKey, MiNiFiProperties.NIFI_MINIFI_SENSITIVE_PROPS_ALGORITHM.getKey(), sensitivePropertiesAlgorithm )); @@ -159,7 +160,7 @@ public void testSensitivePropertiesAreUsedWhenProvidedInBootstrap() throws Confi @Test public void testNonBlankC2PropertiesAreCopiedToMiNiFiProperties() throws ConfigurationChangeException { // given - Properties bootstrapProperties = createBootstrapProperties(Map.of( + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of( MiNiFiProperties.C2_ENABLE.getKey(), TRUE.toString(), MiNiFiProperties.C2_AGENT_CLASS.getKey(), EMPTY, MiNiFiProperties.C2_AGENT_IDENTIFIER.getKey(), SPACE @@ -180,7 +181,7 @@ public void testNonBlankC2PropertiesAreCopiedToMiNiFiProperties() throws Configu public void testDefaultNiFiPropertiesAreOverridden() throws ConfigurationChangeException { // given String archiveDir = "/path/to"; - Properties bootstrapProperties = createBootstrapProperties(Map.of( + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of( NiFiProperties.FLOW_CONFIGURATION_ARCHIVE_ENABLED, TRUE.toString(), NiFiProperties.FLOW_CONFIGURATION_ARCHIVE_DIR, archiveDir )); @@ -211,7 +212,7 @@ public void testDefaultNiFiPropertiesAreOverridden() throws ConfigurationChangeE @Test public void testArbitraryNiFiPropertyCanBePassedViaBootstrapConf() throws ConfigurationChangeException { // given - Properties bootstrapProperties = createBootstrapProperties(Map.of( + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of( "nifi.new.property", "new_property_value", "nifi.other.new.property", "other_new_property_value" )); @@ -229,7 +230,7 @@ public void testArbitraryNiFiPropertyCanBePassedViaBootstrapConf() throws Config @Test public void bootstrapFileAndLogPropertiesAreGeneratedIntoMiNiFiProperties() throws ConfigurationChangeException { // given - Properties bootstrapProperties = createBootstrapProperties(Map.of()); + BootstrapProperties bootstrapProperties = createBootstrapProperties(Map.of()); // when testPropertiesGenerator.generateMinifiProperties(configDirectory.toString(), bootstrapProperties); @@ -243,12 +244,13 @@ public void bootstrapFileAndLogPropertiesAreGeneratedIntoMiNiFiProperties() thro ); } - private Properties createBootstrapProperties(Map keyValues) { + private BootstrapProperties createBootstrapProperties(Map keyValues) { try (OutputStream outputStream = newOutputStream(bootstrapPropertiesFile)) { Properties properties = new Properties(); + BootstrapProperties bootstrapProperties = new BootstrapProperties(keyValues); properties.putAll(keyValues); properties.store(outputStream, EMPTY); - return properties; + return bootstrapProperties; } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLoggerTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLoggerTest.java index 918edacee7664..08cb00f403a90 100644 --- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLoggerTest.java +++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/status/reporters/StatusLoggerTest.java @@ -22,16 +22,18 @@ import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD; import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import java.io.IOException; -import java.util.Properties; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.nifi.logging.LogLevel; import org.apache.nifi.minifi.bootstrap.QueryableStatusAggregator; import org.apache.nifi.minifi.commons.status.FlowStatusReport; +import org.apache.nifi.minifi.properties.BootstrapProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -68,28 +70,28 @@ public void init() throws IOException { @Test public void testFailedInitDueToFatalLogLevel() { - Properties properties = new Properties(); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey(), "1"); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey(), LogLevel.FATAL.name()); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey(), MOCK_QUERY); + BootstrapProperties properties = mock(BootstrapProperties.class); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey())).willReturn("1"); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey())).willReturn(LogLevel.FATAL.name()); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey())).willReturn(MOCK_QUERY); assertThrows(IllegalStateException.class, () -> statusLogger.initialize(properties, queryableStatusAggregator)); } @Test public void testFailedInitDueToNoPeriod() { - Properties properties = new Properties(); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey(), LogLevel.INFO.name()); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey(), MOCK_QUERY); + BootstrapProperties properties = mock(BootstrapProperties.class); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey())).willReturn(LogLevel.INFO.name()); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey())).willReturn(MOCK_QUERY); assertThrows(IllegalStateException.class, () -> statusLogger.initialize(properties, queryableStatusAggregator)); } @Test public void testFailedInitDueToNoQuery() { - Properties properties = new Properties(); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey(), "1"); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey(), LogLevel.INFO.name()); + BootstrapProperties properties = mock(BootstrapProperties.class); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey())).willReturn(LogLevel.INFO.name()); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey())).willReturn(MOCK_QUERY); assertThrows(IllegalStateException.class, () -> statusLogger.initialize(properties, queryableStatusAggregator)); } @@ -139,13 +141,9 @@ public void testError() { verify(logger, Mockito.atLeastOnce()).error(MOCK_STATUS, (Throwable) null); } - // Exception testing @Test public void testTraceException() throws IOException { - Properties properties = new Properties(); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey(), "1"); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey(), LogLevel.TRACE.name()); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey(), MOCK_QUERY); + BootstrapProperties properties = getProperties(LogLevel.TRACE); IOException ioException = new IOException("This is an expected test exception"); Mockito.when(queryableStatusAggregator.statusReport(MOCK_QUERY)).thenThrow(ioException); @@ -205,11 +203,11 @@ public void testErrorException() throws IOException { verify(logger, Mockito.atLeastOnce()).error(ENCOUNTERED_IO_EXCEPTION, ioException); } - private static Properties getProperties(LogLevel logLevel) { - Properties properties = new Properties(); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey(), "1"); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey(), logLevel.name()); - properties.setProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey(), MOCK_QUERY); + private static BootstrapProperties getProperties(LogLevel logLevel) { + BootstrapProperties properties = mock(BootstrapProperties.class); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_PERIOD.getKey())).willReturn("1"); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_LEVEL.getKey())).willReturn(logLevel.name()); + given(properties.getProperty(NIFI_MINIFI_STATUS_REPORTER_LOG_QUERY.getKey())).willReturn(MOCK_QUERY); return properties; } @@ -222,7 +220,6 @@ public RunOnceScheduledExecutorService(int corePoolSize) { @Override public ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { command.run(); - // Return value is not used return null; } } diff --git a/minifi/minifi-c2/minifi-c2-service/pom.xml b/minifi/minifi-c2/minifi-c2-service/pom.xml index 70664942db5ba..6a5fccad41905 100644 --- a/minifi/minifi-c2/minifi-c2-service/pom.xml +++ b/minifi/minifi-c2/minifi-c2-service/pom.xml @@ -74,7 +74,6 @@ limitations under the License. com.google.guava guava - provided com.fasterxml.jackson.core @@ -97,7 +96,7 @@ limitations under the License. provided - io.swagger + io.swagger.core.v3 swagger-annotations provided diff --git a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java index f362ccea2213e..b233e774929ca 100644 --- a/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java +++ b/minifi/minifi-c2/minifi-c2-service/src/main/java/org/apache/nifi/minifi/c2/service/ConfigService.java @@ -26,11 +26,12 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.UncheckedExecutionException; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiParam; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -77,10 +78,6 @@ @Configuration @Path("/config") -@ApiModel( - value = "/config", - description = "Provides configuration and heartbeat/acknowledge capabilities for MiNiFi instances" -) public class ConfigService { public static final String MESSAGE_400 = "MiNiFi C2 server was unable to complete the request because it was invalid. The request should not be retried without modification."; @@ -177,15 +174,23 @@ protected ConfigurationProviderInfo initContentTypeInfo(List getPropertyValue(String name, Map properti private static Stream keyPermutations(String name) { return Stream.of(name, name.replace(DOT, UNDERSCORE), name.replace(HYPHEN, UNDERSCORE), name.replace(DOT, UNDERSCORE).replace(HYPHEN, UNDERSCORE)).distinct(); } + } diff --git a/minifi/minifi-commons/minifi-commons-utils/src/main/java/org/apache/nifi/minifi/commons/utils/SensitivePropertyUtils.java b/minifi/minifi-commons/minifi-commons-utils/src/main/java/org/apache/nifi/minifi/commons/utils/SensitivePropertyUtils.java new file mode 100644 index 0000000000000..301f2637d8a86 --- /dev/null +++ b/minifi/minifi-commons/minifi-commons-utils/src/main/java/org/apache/nifi/minifi/commons/utils/SensitivePropertyUtils.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.commons.utils; + +import static java.lang.String.format; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Optional; +import java.util.Properties; + +public class SensitivePropertyUtils { + + public static final String MINIFI_BOOTSTRAP_SENSITIVE_KEY = "minifi.bootstrap.sensitive.key"; + private static final String EMPTY = ""; + + private SensitivePropertyUtils() { + } + + public static String getFormattedKey() { + String key = getKey(System.getProperty("minifi.bootstrap.conf.file.path")); + // Format the key (check hex validity and remove spaces) + return getFormattedKey(key); + } + + public static String getFormattedKey(String unformattedKey) { + String key = formatHexKey(unformattedKey); + + if (isNotEmpty(key) && !isHexKeyValid(key)) { + throw new IllegalArgumentException("The key was not provided in valid hex format and of the correct length"); + } else { + return key; + } + } + + private static String formatHexKey(String input) { + return Optional.ofNullable(input) + .map(String::trim) + .filter(SensitivePropertyUtils::isNotEmpty) + .map(str -> str.replaceAll("[^0-9a-fA-F]", EMPTY).toLowerCase()) + .orElse(EMPTY); + } + + private static boolean isHexKeyValid(String key) { + return Optional.ofNullable(key) + .map(String::trim) + .filter(SensitivePropertyUtils::isNotEmpty) + .filter(k -> k.matches("^[0-9a-fA-F]{64}$")) + .isPresent(); + } + + private static String getKey(String bootstrapConfigFilePath) { + Properties properties = new Properties(); + + try (InputStream inputStream = new BufferedInputStream(new FileInputStream(bootstrapConfigFilePath))) { + properties.load(inputStream); + } catch (Exception e) { + throw new RuntimeException(format("Loading Bootstrap Properties [%s] failed", bootstrapConfigFilePath), e); + } + + return properties.getProperty(MINIFI_BOOTSTRAP_SENSITIVE_KEY); + } + + private static boolean isNotEmpty(String keyFilePath) { + return keyFilePath != null && !keyFilePath.isBlank(); + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml new file mode 100644 index 0000000000000..3b5249d22d86b --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/pom.xml @@ -0,0 +1,55 @@ + + + + + 4.0.0 + + org.apache.nifi.minifi + minifi-framework + 2.0.0-SNAPSHOT + + + minifi-properties-loader + + + + org.apache.nifi + nifi-property-protection-loader + + + org.apache.nifi + nifi-property-protection-cipher + + + org.apache.nifi + nifi-properties + + + org.apache.nifi.minifi + minifi-commons-utils + provided + + + org.apache.nifi.minifi + minifi-commons-api + + + + \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapProperties.java new file mode 100644 index 0000000000000..29bac65691cd5 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapProperties.java @@ -0,0 +1,71 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.properties; + +import static org.apache.nifi.minifi.commons.utils.PropertyUtil.resolvePropertyValue; + +import java.util.Collections; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.nifi.properties.ApplicationProperties; + +/** + * Extends Properties functionality with System and Environment property override possibility. The property resolution also works with + * dots and hyphens that are not supported in some shells. + */ +public class BootstrapProperties extends ApplicationProperties { + + public BootstrapProperties() { + super(Collections.emptyMap()); + } + + public BootstrapProperties(Properties properties) { + super(properties); + } + public BootstrapProperties(Map properties) { + super(properties); + } + + @Override + public String getProperty(String key) { + return resolvePropertyValue(key, System.getProperties()) + .or(() -> resolvePropertyValue(key, System.getenv())) + .orElseGet(() -> super.getProperty(key)); + } + + @Override + public String getProperty(String key, String defaultValue) { + return resolvePropertyValue(key, System.getProperties()) + .or(() -> resolvePropertyValue(key, System.getenv())) + .orElseGet(() -> super.getProperty(key, defaultValue)); + } + + @Override + public Set getPropertyKeys() { + Set systemKeys = System.getProperties().keySet().stream().map(String::valueOf).collect(Collectors.toSet()); + return Stream.of(systemKeys, System.getenv().keySet(), super.getPropertyKeys()) + .flatMap(Set::stream) + .collect(Collectors.toSet()); + } + + public boolean containsKey(String key) { + return getPropertyKeys().contains(key); + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java new file mode 100644 index 0000000000000..4c24394b8b97b --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoader.java @@ -0,0 +1,49 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.properties; + +import static java.lang.String.format; +import static org.apache.nifi.minifi.commons.utils.SensitivePropertyUtils.MINIFI_BOOTSTRAP_SENSITIVE_KEY; +import static org.apache.nifi.minifi.commons.utils.SensitivePropertyUtils.getFormattedKey; + +import java.io.File; +import org.apache.nifi.properties.AesGcmSensitivePropertyProvider; + +public class BootstrapPropertiesLoader { + + public static BootstrapProperties load(File file) { + ProtectedBootstrapProperties protectedProperties = loadProtectedProperties(file); + if (protectedProperties.hasProtectedKeys()) { + String sensitiveKey = protectedProperties.getApplicationProperties().getProperty(MINIFI_BOOTSTRAP_SENSITIVE_KEY); + validateSensitiveKeyProperty(sensitiveKey); + String keyHex = getFormattedKey(sensitiveKey); + protectedProperties.addSensitivePropertyProvider(new AesGcmSensitivePropertyProvider(keyHex)); + } + return protectedProperties.getUnprotectedProperties(); + } + + public static ProtectedBootstrapProperties loadProtectedProperties(File file) { + return new ProtectedBootstrapProperties(PropertiesLoader.load(file, "Bootstrap")); + } + + private static void validateSensitiveKeyProperty(String sensitiveKey) { + if (sensitiveKey == null || sensitiveKey.trim().isEmpty()) { + throw new IllegalArgumentException(format("bootstrap.conf contains protected properties but %s is not found", MINIFI_BOOTSTRAP_SENSITIVE_KEY)); + } + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/DuplicateDetectingProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/DuplicateDetectingProperties.java new file mode 100644 index 0000000000000..92fc64430f9ec --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/DuplicateDetectingProperties.java @@ -0,0 +1,53 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.properties; + +import java.util.HashSet; +import java.util.Properties; +import java.util.Set; + +class DuplicateDetectingProperties extends Properties { + // Only need to retain Properties key. This will help prevent possible inadvertent exposure of sensitive Properties value + private final Set duplicateKeys = new HashSet<>(); + private final Set redundantKeys = new HashSet<>(); + + public DuplicateDetectingProperties() { + super(); + } + + public Set duplicateKeySet() { + return duplicateKeys; + } + + public Set redundantKeySet() { + return redundantKeys; + } + + @Override + public Object put(Object key, Object value) { + Object existingValue = super.put(key, value); + if (existingValue != null) { + if (existingValue.toString().equals(value.toString())) { + redundantKeys.add(key.toString()); + } else { + duplicateKeys.add(key.toString()); + } + } + return value; + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java new file mode 100644 index 0000000000000..d15fa3ee37f08 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoader.java @@ -0,0 +1,104 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.properties; + +import java.io.File; +import org.apache.nifi.properties.AesGcmSensitivePropertyProvider; +import org.apache.nifi.util.NiFiBootstrapUtils; +import org.apache.nifi.util.NiFiProperties; + +public class MiNiFiPropertiesLoader { + + private static final String DEFAULT_APPLICATION_PROPERTIES_FILE_PATH = NiFiBootstrapUtils.getDefaultApplicationPropertiesFilePath(); + + private NiFiProperties instance; + private String keyHex; + + public MiNiFiPropertiesLoader(String keyHex) { + this.keyHex = keyHex; + } + + /** + * Returns a {@link ProtectedMiNiFiProperties} instance loaded from the + * serialized form in the file. Responsible for actually reading from disk + * and deserializing the properties. Returns a protected instance to allow + * for decryption operations. + * + * @param file the file containing serialized properties + * @return the ProtectedMiNiFiProperties instance + */ + ProtectedMiNiFiProperties loadProtectedProperties(File file) { + return new ProtectedMiNiFiProperties(PropertiesLoader.load(file, "Application")); + } + + /** + * Returns an instance of {@link NiFiProperties} loaded from the provided + * {@link File}. If any properties are protected, will attempt to use the + * {@link AesGcmSensitivePropertyProvider} to unprotect them + * transparently. + * + * @param file the File containing the serialized properties + * @return the NiFiProperties instance + */ + public NiFiProperties load(File file) { + ProtectedMiNiFiProperties protectedProperties = loadProtectedProperties(file); + if (protectedProperties.hasProtectedKeys()) { + protectedProperties.addSensitivePropertyProvider(new AesGcmSensitivePropertyProvider(keyHex)); + } + return new MultiSourceMinifiProperties(protectedProperties.getUnprotectedPropertiesAsMap()); + } + + /** + * Returns an instance of {@link NiFiProperties}. If the path is empty, this + * will load the default properties file as specified by + * {@code NiFiProperties.PROPERTY_FILE_PATH}. + * + * @param path the path of the serialized properties file + * @return the NiFiProperties instance + * @see MiNiFiPropertiesLoader#load(File) + */ + public NiFiProperties load(String path) { + if (path != null && !path.trim().isEmpty()) { + return load(new File(path)); + } else { + return loadDefault(); + } + } + + /** + * Returns the loaded {@link NiFiProperties} instance. If none is currently + * loaded, attempts to load the default instance. + *

+ *

+ * NOTE: This method is used reflectively by the process which starts MiNiFi + * so changes to it must be made in conjunction with that mechanism.

+ * + * @return the current NiFiProperties instance + */ + public NiFiProperties get() { + if (instance == null) { + instance = loadDefault(); + } + + return instance; + } + + private NiFiProperties loadDefault() { + return load(DEFAULT_APPLICATION_PROPERTIES_FILE_PATH); + } + +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java new file mode 100644 index 0000000000000..f39a97dee5ec1 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/MultiSourceMinifiProperties.java @@ -0,0 +1,55 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.properties; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.nifi.minifi.commons.utils.PropertyUtil; +import org.apache.nifi.util.NiFiProperties; + +/** + * Extends NiFi properties functionality with System and Environment property override possibility. The property resolution also works with + * dots and hyphens that are not supported in some shells. + */ +public class MultiSourceMinifiProperties extends NiFiProperties { + + public MultiSourceMinifiProperties(Map props) { + super(props); + } + + @Override + public Set getPropertyKeys() { + return Stream.of(System.getProperties().stringPropertyNames(), System.getenv().keySet(), super.getPropertyKeys()) + .flatMap(Set::stream) + .collect(Collectors.toSet()); + } + + @Override + public int size() { + return getPropertyKeys().size(); + } + + @Override + public String getProperty(String key) { + return PropertyUtil.resolvePropertyValue(key, System.getProperties()) + .or(() -> PropertyUtil.resolvePropertyValue(key, System.getenv())) + .orElseGet(() -> super.getProperty(key)); + } + +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java new file mode 100644 index 0000000000000..9785fda997cc1 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/PropertiesLoader.java @@ -0,0 +1,61 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.properties; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public interface PropertiesLoader { + + static final Logger logger = LoggerFactory.getLogger(PropertiesLoader.class); + + static Properties load(File file, String propertiesType) { + if (file == null || !file.exists() || !file.canRead()) { + throw new IllegalArgumentException(String.format("{} Properties [%s] not found", propertiesType, file)); + } + + logger.info("Loading {} Properties [{}]", propertiesType, file); + DuplicateDetectingProperties rawProperties = new DuplicateDetectingProperties(); + + try (InputStream inputStream = new BufferedInputStream(new FileInputStream(file))) { + rawProperties.load(inputStream); + } catch (Exception e) { + throw new RuntimeException(String.format("Loading {} Properties [%s] failed", propertiesType, file), e); + } + + if (!rawProperties.redundantKeySet().isEmpty()) { + logger.warn("Duplicate property keys with the same value were detected in the properties file: {}", String.join(", ", rawProperties.redundantKeySet())); + } + if (!rawProperties.duplicateKeySet().isEmpty()) { + throw new IllegalArgumentException("Duplicate property keys with different values were detected in the properties file: " + String.join(", ", rawProperties.duplicateKeySet())); + } + + Properties properties = new Properties(); + rawProperties.stringPropertyNames() + .forEach(key -> { + String property = rawProperties.getProperty(key); + properties.setProperty(key, property.trim()); + }); + return properties; + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedBootstrapProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedBootstrapProperties.java new file mode 100644 index 0000000000000..486574a822b8e --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedBootstrapProperties.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.properties; + +import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.ADDITIONAL_SENSITIVE_PROPERTIES_KEY; +import static org.apache.nifi.minifi.properties.ProtectedMiNiFiProperties.DEFAULT_SENSITIVE_PROPERTIES; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.properties.ApplicationPropertiesProtector; +import org.apache.nifi.properties.ProtectedProperties; +import org.apache.nifi.properties.SensitivePropertyProtectionException; +import org.apache.nifi.properties.SensitivePropertyProtector; +import org.apache.nifi.properties.SensitivePropertyProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ProtectedBootstrapProperties extends BootstrapProperties implements ProtectedProperties, + SensitivePropertyProtector { + + private static final Logger logger = LoggerFactory.getLogger(ProtectedBootstrapProperties.class); + + private BootstrapProperties bootstrapProperties; + + private final SensitivePropertyProtector propertyProtectionDelegate; + + public ProtectedBootstrapProperties(BootstrapProperties props) { + super(); + this.bootstrapProperties = props; + this.propertyProtectionDelegate = new ApplicationPropertiesProtector<>(this); + logger.debug("Loaded {} properties (including {} protection schemes) into ProtectedBootstrapProperties", getApplicationProperties().getPropertyKeys().size(), + getProtectedPropertyKeys().size()); + } + + public ProtectedBootstrapProperties(Properties rawProps) { + this(new BootstrapProperties(rawProps)); + } + + @Override + public Set getPropertyKeysIncludingProtectionSchemes() { + return propertyProtectionDelegate.getPropertyKeysIncludingProtectionSchemes(); + } + + @Override + public List getSensitivePropertyKeys() { + return propertyProtectionDelegate.getSensitivePropertyKeys(); + } + + @Override + public List getPopulatedSensitivePropertyKeys() { + return propertyProtectionDelegate.getPopulatedSensitivePropertyKeys(); + } + + @Override + public boolean hasProtectedKeys() { + return propertyProtectionDelegate.hasProtectedKeys(); + } + + @Override + public Map getProtectedPropertyKeys() { + return propertyProtectionDelegate.getProtectedPropertyKeys(); + } + + @Override + public boolean isPropertySensitive(String key) { + return propertyProtectionDelegate.isPropertySensitive(key); + } + + @Override + public boolean isPropertyProtected(String key) { + return propertyProtectionDelegate.isPropertyProtected(key); + } + + @Override + public BootstrapProperties getUnprotectedProperties() throws SensitivePropertyProtectionException { + return propertyProtectionDelegate.getUnprotectedProperties(); + } + + @Override + public void addSensitivePropertyProvider(SensitivePropertyProvider sensitivePropertyProvider) { + propertyProtectionDelegate.addSensitivePropertyProvider(sensitivePropertyProvider); + } + + @Override + public String getAdditionalSensitivePropertiesKeys() { + return getProperty(getAdditionalSensitivePropertiesKeysName()); + } + + @Override + public String getAdditionalSensitivePropertiesKeysName() { + return ADDITIONAL_SENSITIVE_PROPERTIES_KEY; + } + + @Override + public List getDefaultSensitiveProperties() { + return Stream.of(DEFAULT_SENSITIVE_PROPERTIES, Arrays.stream(MiNiFiProperties.values()).filter(MiNiFiProperties::isSensitive).map(MiNiFiProperties::getKey).collect(Collectors.toList())) + .flatMap(List::stream).distinct().collect(Collectors.toList()); + } + + @Override + public BootstrapProperties getApplicationProperties() { + if (this.bootstrapProperties == null) { + this.bootstrapProperties = new BootstrapProperties(); + } + + return this.bootstrapProperties; + } + + @Override + public BootstrapProperties createApplicationProperties(Properties rawProperties) { + return new BootstrapProperties(rawProperties); + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedMiNiFiProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedMiNiFiProperties.java new file mode 100644 index 0000000000000..238a110413895 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/main/java/org/apache/nifi/minifi/properties/ProtectedMiNiFiProperties.java @@ -0,0 +1,239 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.properties; + +import static java.util.Arrays.asList; +import static org.apache.nifi.minifi.commons.api.MiNiFiProperties.ADDITIONAL_SENSITIVE_PROPERTIES_KEY; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.nifi.minifi.commons.api.MiNiFiProperties; +import org.apache.nifi.properties.ApplicationPropertiesProtector; +import org.apache.nifi.properties.ProtectedProperties; +import org.apache.nifi.properties.SensitivePropertyProtectionException; +import org.apache.nifi.properties.SensitivePropertyProtector; +import org.apache.nifi.properties.SensitivePropertyProvider; +import org.apache.nifi.util.NiFiProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Decorator class for intermediate phase when {@link MiNiFiPropertiesLoader} loads the + * raw properties file and performs unprotection activities before returning a clean + * implementation of {@link NiFiProperties}. + * This encapsulates the sensitive property access logic from external consumers + * of {@code NiFiProperties}. + */ +public class ProtectedMiNiFiProperties extends NiFiProperties implements ProtectedProperties, + SensitivePropertyProtector { + private static final Logger logger = LoggerFactory.getLogger(ProtectedMiNiFiProperties.class); + public static final List DEFAULT_SENSITIVE_PROPERTIES = new ArrayList<>(asList( + SECURITY_KEY_PASSWD, + SECURITY_KEYSTORE_PASSWD, + SECURITY_TRUSTSTORE_PASSWD, + SENSITIVE_PROPS_KEY + )); + + private final SensitivePropertyProtector propertyProtectionDelegate; + + private NiFiProperties applicationProperties; + + public ProtectedMiNiFiProperties() { + this(new NiFiProperties()); + } + + /** + * Creates an instance containing the provided {@link NiFiProperties}. + * + * @param props the NiFiProperties to contain + */ + public ProtectedMiNiFiProperties(NiFiProperties props) { + this.applicationProperties = props; + this.propertyProtectionDelegate = new ApplicationPropertiesProtector<>(this); + logger.debug("Loaded {} properties (including {} protection schemes) into ProtectedNiFiProperties", getApplicationProperties() + .getPropertyKeys().size(), getProtectedPropertyKeys().size()); + } + + /** + * Creates an instance containing the provided raw {@link Properties}. + * + * @param rawProps the Properties to contain + */ + public ProtectedMiNiFiProperties(Properties rawProps) { + this(new NiFiProperties(rawProps)); + } + + @Override + public String getAdditionalSensitivePropertiesKeys() { + return getProperty(getAdditionalSensitivePropertiesKeysName()); + } + + @Override + public String getAdditionalSensitivePropertiesKeysName() { + return ADDITIONAL_SENSITIVE_PROPERTIES_KEY; + } + + @Override + public List getDefaultSensitiveProperties() { + return Stream.of(DEFAULT_SENSITIVE_PROPERTIES, + Arrays.stream(MiNiFiProperties.values()).filter(MiNiFiProperties::isSensitive).map(MiNiFiProperties::getKey).toList()).flatMap(List::stream).distinct().toList(); + } + + /** + * Returns the internal representation of the {@link NiFiProperties} -- protected + * or not as determined by the current state. No guarantee is made to the + * protection state of these properties. If the internal reference is null, a new + * {@link NiFiProperties} instance is created. + * + * @return the internal properties + */ + public NiFiProperties getApplicationProperties() { + if (this.applicationProperties == null) { + this.applicationProperties = new NiFiProperties(); + } + + return this.applicationProperties; + } + + @Override + public NiFiProperties createApplicationProperties(final Properties rawProperties) { + return new NiFiProperties(rawProperties); + } + + /** + * Retrieves the property value for the given property key. + * + * @param key the key of property value to lookup + * @return value of property at given key or null if not found + */ + @Override + public String getProperty(String key) { + return getApplicationProperties().getProperty(key); + } + + /** + * Retrieves all known property keys. + * + * @return all known property keys + */ + @Override + public Set getPropertyKeys() { + return propertyProtectionDelegate.getPropertyKeys(); + } + + /** + * Returns the number of properties, excluding protection scheme properties. + *

+ * Example: + *

+ * key: E(value, key) + * key.protected: aes/gcm/256 + * key2: value2 + *

+ * would return size 2 + * + * @return the count of real properties + */ + @Override + public int size() { + return propertyProtectionDelegate.size(); + } + + @Override + public Set getPropertyKeysIncludingProtectionSchemes() { + return propertyProtectionDelegate.getPropertyKeysIncludingProtectionSchemes(); + } + + @Override + public List getSensitivePropertyKeys() { + return propertyProtectionDelegate.getSensitivePropertyKeys(); + } + + @Override + public List getPopulatedSensitivePropertyKeys() { + return propertyProtectionDelegate.getPopulatedSensitivePropertyKeys(); + } + + @Override + public boolean hasProtectedKeys() { + return propertyProtectionDelegate.hasProtectedKeys(); + } + + @Override + public Map getProtectedPropertyKeys() { + return propertyProtectionDelegate.getProtectedPropertyKeys(); + } + + @Override + public boolean isPropertySensitive(final String key) { + return propertyProtectionDelegate.isPropertySensitive(key); + } + + @Override + public boolean isPropertyProtected(final String key) { + return propertyProtectionDelegate.isPropertyProtected(key); + } + + @Override + public NiFiProperties getUnprotectedProperties() throws SensitivePropertyProtectionException { + return propertyProtectionDelegate.getUnprotectedProperties(); + } + + @Override + public void addSensitivePropertyProvider(final SensitivePropertyProvider sensitivePropertyProvider) { + propertyProtectionDelegate.addSensitivePropertyProvider(sensitivePropertyProvider); + } + + public Map getUnprotectedPropertiesAsMap() { + NiFiProperties niFiProperties = propertyProtectionDelegate.getUnprotectedProperties(); + return niFiProperties.getPropertyKeys().stream().collect(Collectors.toMap(Function.identity(), niFiProperties::getProperty)); + } + + /** + * Returns the number of properties that are marked as protected in the provided {@link NiFiProperties} instance without requiring external creation of a + * {@link ProtectedMiNiFiProperties} instance. + * + * @param plainProperties the instance to count protected properties + * @return the number of protected properties + */ + public static int countProtectedProperties(final NiFiProperties plainProperties) { + return new ProtectedMiNiFiProperties(plainProperties).getProtectedPropertyKeys().size(); + } + + /** + * Returns the number of properties that are marked as sensitive in the provided {@link NiFiProperties} instance without requiring external creation of a + * {@link ProtectedMiNiFiProperties} instance. + * + * @param plainProperties the instance to count sensitive properties + * @return the number of sensitive properties + */ + public static int countSensitiveProperties(final NiFiProperties plainProperties) { + return new ProtectedMiNiFiProperties(plainProperties).getSensitivePropertyKeys().size(); + } + + @Override + public String toString() { + return String.format("%s Size [%d]", getClass().getSimpleName(), size()); + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoaderTest.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoaderTest.java new file mode 100644 index 0000000000000..c3d3febcac776 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/BootstrapPropertiesLoaderTest.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.File; +import java.net.URL; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; + +class BootstrapPropertiesLoaderTest { + + private static final String NON_EXISTING_FILE_PATH = "/conf/nonexisting.conf"; + private static final String DUPLICATED_ITEMS_FILE_PATH = "/conf/bootstrap_duplicated_items.conf"; + private static final String UNPROTECTED_ITEMS_FILE_PATH = "/conf/bootstrap_unprotected.conf"; + private static final String PROTECTED_ITEMS_FILE_PATH = "/conf/bootstrap_protected.conf"; + private static final String PROTECTED_ITEMS_WITHOUT_SENSITIVE_KEY_FILE_PATH = "/conf/bootstrap_protected_without_sensitive_key.conf"; + + private static final Map UNPROTECTED_PROPERTIES = Map.of("nifi.minifi.security.keystorePasswd", "testPassword", "nifi.minifi.sensitive.props.key", "testSensitivePropsKey"); + + @Test + void shouldThrowIllegalArgumentExceptionIfFileIsNotProvided() { + assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(null)); + } + + @Test + void shouldThrowIllegalArgumentExceptionIfFileDoesNotExists() { + assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(new File(NON_EXISTING_FILE_PATH))); + } + + @Test + void shouldThrowIllegalArgumentExceptionIfTheConfigFileContainsDuplicatedKeysWithDifferentValues() { + assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(getFile(DUPLICATED_ITEMS_FILE_PATH))); + } + + @Test + void shouldReturnPropertiesIfConfigFileDoesNotContainProtectedProperties() { + BootstrapProperties bootstrapProperties = BootstrapPropertiesLoader.load(getFile(UNPROTECTED_ITEMS_FILE_PATH)); + + assertEquals(UNPROTECTED_PROPERTIES, + bootstrapProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), bootstrapProperties::getProperty))); + } + + @Test + void shouldReturnUnProtectedProperties() { + BootstrapProperties bootstrapProperties = BootstrapPropertiesLoader.load(getFile(PROTECTED_ITEMS_FILE_PATH)); + + assertEquals(UNPROTECTED_PROPERTIES, + bootstrapProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), bootstrapProperties::getProperty))); + } + + @Test + void shouldThrowIllegalArgumentExceptionIfFileContainsProtectedPropertiesButSensitiveKeyIsMissing() { + assertThrows(IllegalArgumentException.class, () -> BootstrapPropertiesLoader.load(getFile(PROTECTED_ITEMS_WITHOUT_SENSITIVE_KEY_FILE_PATH))); + } + + private File getFile(String duplicatedItemsFilePath) { + URL resource = BootstrapPropertiesLoaderTest.class.getResource(duplicatedItemsFilePath); + assertNotNull(resource); + return new File(resource.getPath()); + } +} \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoaderTest.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoaderTest.java new file mode 100644 index 0000000000000..fd4c863dd0f22 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/java/org/apache/nifi/minifi/properties/MiNiFiPropertiesLoaderTest.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.properties; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.io.File; +import java.net.URL; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.apache.nifi.util.NiFiProperties; +import org.junit.jupiter.api.Test; + +class MiNiFiPropertiesLoaderTest { + private static final String NON_EXISTING_FILE_PATH = "/conf/nonexisting.properties"; + private static final String DUPLICATED_ITEMS_FILE_PATH = "/conf/bootstrap_duplicated_items.conf"; + private static final String UNPROTECTED_ITEMS_FILE_PATH = "/conf/minifi_unprotected.properties"; + private static final String PROTECTED_ITEMS_FILE_PATH = "/conf/minifi_protected.properties"; + private static final Map UNPROTECTED_PROPERTIES = Map.of("nifi.security.keystorePasswd", "testPassword", "nifi.security.keyPasswd", + "testSensitivePropsKey"); + private static final String PROTECTION_KEY = "00714ae7a77b24cde1d36bd19472777e0d4ab02c38913b7f9bf41f3963147b4f"; + + @Test + void shouldThrowIllegalArgumentExceptionIfFileIsNotProvided() { + MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); + assertThrows(IllegalArgumentException.class, () -> miNiFiPropertiesLoader.load((String) null)); + } + + @Test + void shouldThrowIllegalArgumentExceptionIfFileDoesNotExists() { + MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); + assertThrows(IllegalArgumentException.class, () -> miNiFiPropertiesLoader.load(new File(NON_EXISTING_FILE_PATH))); + } + + @Test + void shouldThrowIllegalArgumentExceptionIfTheConfigFileContainsDuplicatedKeysWithDifferentValues() { + MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); + + assertThrows(IllegalArgumentException.class, () -> miNiFiPropertiesLoader.load(getFile(DUPLICATED_ITEMS_FILE_PATH))); + } + + @Test + void shouldReturnPropertiesIfConfigFileDoesNotContainProtectedProperties() { + MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(""); + + NiFiProperties niFiProperties = miNiFiPropertiesLoader.load(getFile(UNPROTECTED_ITEMS_FILE_PATH)); + + assertEquals(UNPROTECTED_PROPERTIES, + niFiProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), niFiProperties::getProperty))); + } + + @Test + void shouldReturnUnProtectedProperties() { + MiNiFiPropertiesLoader miNiFiPropertiesLoader = new MiNiFiPropertiesLoader(PROTECTION_KEY); + + NiFiProperties niFiProperties = miNiFiPropertiesLoader.load(getUrl(PROTECTED_ITEMS_FILE_PATH).getPath()); + + assertEquals(UNPROTECTED_PROPERTIES, + niFiProperties.getPropertyKeys().stream().filter(UNPROTECTED_PROPERTIES::containsKey).collect(Collectors.toMap(Function.identity(), niFiProperties::getProperty))); + } + + private File getFile(String propertiesFilePath) { + URL resource = getUrl(propertiesFilePath); + return new File(resource.getPath()); + } + + private static URL getUrl(String propertiesFilePath) { + URL resource = BootstrapPropertiesLoaderTest.class.getResource(propertiesFilePath); + assertNotNull(resource); + return resource; + } +} \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_duplicated_items.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_duplicated_items.conf new file mode 100644 index 0000000000000..dd742bafdabd8 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_duplicated_items.conf @@ -0,0 +1,18 @@ +# 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. + +# property file that contains the same key with different values +property1=test +property1=test2 \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected.conf new file mode 100644 index 0000000000000..86966e8999639 --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected.conf @@ -0,0 +1,22 @@ +# 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. + +# property file that contains the protected properties and a sensitive key to decrypt it +nifi.minifi.security.keystorePasswd=noBD32A0ANcz/BHv||nhtyNhlFgNNZcVhgxEOg2xUZ5UAihgyBit1drQ== +nifi.minifi.security.keystorePasswd.protected=aes/gcm/256 +nifi.minifi.sensitive.props.key=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== +nifi.minifi.sensitive.props.key.protected=aes/gcm/256 + +minifi.bootstrap.sensitive.key=00714ae7a77b24cde1d36bd19472777e0d4ab02c38913b7f9bf41f3963147b4f diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected_without_sensitive_key.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected_without_sensitive_key.conf new file mode 100644 index 0000000000000..bcc8fe9d8a2ba --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_protected_without_sensitive_key.conf @@ -0,0 +1,20 @@ +# 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. + +# property file that contains the protected properties but without minifi.bootstrap.sensitive.key +nifi.minifi.security.keystorePasswd=noBD32A0ANcz/BHv||nhtyNhlFgNNZcVhgxEOg2xUZ5UAihgyBit1drQ== +nifi.minifi.security.keystorePasswd.protected=aes/gcm/256 +nifi.minifi.sensitive.props.key=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== +nifi.minifi.sensitive.props.key.protected=aes/gcm/256 diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_unprotected.conf b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_unprotected.conf new file mode 100644 index 0000000000000..e08d4790a5c4c --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/bootstrap_unprotected.conf @@ -0,0 +1,18 @@ +# 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. + +# property file that contains the unprotected properties +nifi.minifi.security.keystorePasswd=testPassword +nifi.minifi.sensitive.props.key=testSensitivePropsKey \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_duplicated.properties b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_duplicated.properties new file mode 100644 index 0000000000000..285d126c1defe --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_duplicated.properties @@ -0,0 +1,20 @@ +# 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. + +nifi.security.keystorePasswd=s+jNt0t608+F0uq9||PWPtOCr5fmItmL8ZsgpheQxkkJJzXWqrNvqdCL/gcGE2cy1NTgGDhI1apuacNHjj +nifi.security.keystorePasswd=123 +nifi.security.keystorePasswd.protected=aes/gcm/256 +nifi.security.keyPasswd=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== +nifi.security.keyPasswd.protected=aes/gcm/256 \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_protected.properties b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_protected.properties new file mode 100644 index 0000000000000..85319171cf80c --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_protected.properties @@ -0,0 +1,19 @@ +# 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. + +nifi.security.keystorePasswd=noBD32A0ANcz/BHv||nhtyNhlFgNNZcVhgxEOg2xUZ5UAihgyBit1drQ== +nifi.security.keystorePasswd.protected=aes/gcm/256 +nifi.security.keyPasswd=JUMeAtpD1Q7CiXHt||BppiPMoWXxkKBl5mYsxP5vkVabsXZyLu2lxjyv9LMHc6RJEE9g== +nifi.security.keyPasswd.protected=aes/gcm/256 \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_unprotected.properties b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_unprotected.properties new file mode 100644 index 0000000000000..06d04d3f31a6a --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-properties-loader/src/test/resources/conf/minifi_unprotected.properties @@ -0,0 +1,17 @@ +# 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. + +nifi.security.keystorePasswd=testPassword +nifi.security.keyPasswd=testSensitivePropsKey \ No newline at end of file diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/pom.xml b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/pom.xml index 8601de6541a13..5d9b2156330c2 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/pom.xml +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/pom.xml @@ -58,8 +58,9 @@ limitations under the License. provided - org.apache.nifi - nifi-properties-loader + org.apache.nifi.minifi + minifi-properties-loader + 2.0.0-SNAPSHOT provided @@ -76,5 +77,6 @@ limitations under the License. com.fasterxml.jackson.core jackson-databind + diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java index 02ecc75e85ba7..567381ddda772 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/MiNiFi.java @@ -16,8 +16,14 @@ */ package org.apache.nifi.minifi; +import static org.apache.nifi.minifi.commons.utils.SensitivePropertyUtils.getFormattedKey; +import static org.apache.nifi.minifi.util.BootstrapClassLoaderUtils.createBootstrapClassLoader; + import java.io.File; import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Set; import java.util.Timer; import java.util.TimerTask; @@ -30,7 +36,6 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.nifi.NiFiServer; import org.apache.nifi.bundle.Bundle; -import org.apache.nifi.minifi.util.MultiSourceMinifiProperties; import org.apache.nifi.nar.ExtensionMapping; import org.apache.nifi.nar.NarClassLoaders; import org.apache.nifi.nar.NarClassLoadersHolder; @@ -46,6 +51,7 @@ public class MiNiFi { private static final Logger logger = LoggerFactory.getLogger(MiNiFi.class); + private final MiNiFiServer minifiServer; private volatile boolean shutdown = false; @@ -155,7 +161,7 @@ protected void shutdownHook(boolean isReload) { logger.info("MiNiFi server shutdown completed (nicely or otherwise)."); } catch (final Throwable t) { - logger.warn("Problem occurred ensuring MiNiFi server was properly terminated due to " + t); + logger.warn("Problem occurred ensuring MiNiFi server was properly terminated due to {}", t.getMessage()); } } @@ -218,10 +224,41 @@ public void run() { public static void main(String[] args) { logger.info("Launching MiNiFi..."); try { - NiFiProperties niFiProperties = MultiSourceMinifiProperties.getInstance(); - new MiNiFi(niFiProperties); + NiFiProperties properties = getValidatedMiNifiProperties(); + new MiNiFi(properties); } catch (final Throwable t) { logger.error("Failure to launch MiNiFi due to " + t, t); } } + + protected static NiFiProperties getValidatedMiNifiProperties() { + NiFiProperties properties = initializeProperties(createBootstrapClassLoader()); + properties.validate(); + return properties; + } + + private static NiFiProperties initializeProperties(ClassLoader boostrapLoader) { + ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); + String key = getFormattedKey(); + + Thread.currentThread().setContextClassLoader(boostrapLoader); + + try { + Class propsLoaderClass = Class.forName("org.apache.nifi.minifi.properties.MiNiFiPropertiesLoader", true, boostrapLoader); + Constructor constructor = propsLoaderClass.getDeclaredConstructor(String.class); + Object loaderInstance = constructor.newInstance(key); + Method getMethod = propsLoaderClass.getMethod("get"); + NiFiProperties properties = (NiFiProperties) getMethod.invoke(loaderInstance); + logger.info("Application Properties loaded [{}]", properties.size()); + return properties; + } catch (InvocationTargetException wrappedException) { + throw new IllegalArgumentException("There was an issue decrypting protected properties", wrappedException.getCause() == null ? wrappedException : wrappedException.getCause()); + } catch (final IllegalAccessException | NoSuchMethodException | ClassNotFoundException | InstantiationException reex) { + throw new IllegalArgumentException("Unable to access properties loader in the expected manner - apparent classpath or build issue", reex); + } catch (final RuntimeException e) { + throw new IllegalArgumentException("There was an issue decrypting protected properties", e); + } finally { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } + } } diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/util/BootstrapClassLoaderUtils.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/util/BootstrapClassLoaderUtils.java new file mode 100644 index 0000000000000..0c7580cc60afe --- /dev/null +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/util/BootstrapClassLoaderUtils.java @@ -0,0 +1,59 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.util; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Util for creating class loader with bootstrap libs. + */ +public final class BootstrapClassLoaderUtils { + private static final Logger LOGGER = LoggerFactory.getLogger(BootstrapClassLoaderUtils.class); + private static final String LIB_BOOTSTRAP_DIR = "lib/bootstrap"; + + private BootstrapClassLoaderUtils() { + + } + + public static ClassLoader createBootstrapClassLoader() { + List urls = new ArrayList<>(); + try (Stream files = Files.list(Paths.get(LIB_BOOTSTRAP_DIR))) { + files.forEach(p -> { + try { + urls.add(p.toUri().toURL()); + } catch (MalformedURLException mef) { + LOGGER.warn("Unable to load bootstrap library [{}]", p.getFileName(), mef); + } + }); + } catch (IOException ioe) { + LOGGER.warn("Unable to access lib/bootstrap to create bootstrap classloader", ioe); + } + return new URLClassLoader(urls.toArray(new URL[0]), Thread.currentThread().getContextClassLoader()); + } +} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/util/MultiSourceMinifiProperties.java b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/util/MultiSourceMinifiProperties.java deleted file mode 100644 index 95096b8bf7813..0000000000000 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/minifi-runtime/src/main/java/org/apache/nifi/minifi/util/MultiSourceMinifiProperties.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ -package org.apache.nifi.minifi.util; - -import static org.apache.nifi.minifi.commons.utils.PropertyUtil.resolvePropertyValue; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.util.Properties; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.apache.nifi.util.NiFiProperties; - -/** - * Extends NiFi properties functionality with System and Environment property override possibility. The property resolution also works with - * dots and hyphens that are not supported in some shells. - */ -public class MultiSourceMinifiProperties extends NiFiProperties { - - private final Properties properties = new Properties(); - - public static MultiSourceMinifiProperties getInstance() { - return new MultiSourceMinifiProperties(); - } - - private MultiSourceMinifiProperties() { - readFromPropertiesFile(); - } - - @Override - public Set getPropertyKeys() { - return Stream.of(System.getProperties().stringPropertyNames(), System.getenv().keySet(), properties.stringPropertyNames()) - .flatMap(Set::stream) - .collect(Collectors.toSet()); - } - - @Override - public int size() { - return getPropertyKeys().size(); - } - - @Override - public String getProperty(String key) { - return resolvePropertyValue(key, System.getProperties()) - .or(() -> resolvePropertyValue(key, System.getenv())) - .orElseGet(() -> properties.getProperty(key)); - } - - private void readFromPropertiesFile() { - String propertiesFilePath = System.getProperty(NiFiProperties.PROPERTIES_FILE_PATH); - - if (propertiesFilePath != null) { - File propertiesFile = new File(propertiesFilePath.trim()); - - if (!propertiesFile.exists()) { - throw new RuntimeException("Properties file doesn't exist '" + propertiesFile.getAbsolutePath() + "'"); - } - - if (!propertiesFile.canRead()) { - throw new RuntimeException("Properties file exists but cannot be read '" + propertiesFile.getAbsolutePath() + "'"); - } - - try (InputStream inStream = new BufferedInputStream(new FileInputStream(propertiesFile))) { - properties.load(inStream); - } catch (Exception ex) { - throw new RuntimeException("Cannot load properties file due to " + ex.getLocalizedMessage(), ex); - } - } - } -} diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/pom.xml b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/pom.xml index ff95f02a9d65f..8beb586c7832b 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/pom.xml +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/minifi-framework/pom.xml @@ -30,6 +30,7 @@ limitations under the License. minifi-runtime minifi-resources minifi-server + minifi-properties-loader diff --git a/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml b/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml index 2369df008f75b..cc6fda3dc0013 100644 --- a/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml +++ b/minifi/minifi-nar-bundles/minifi-framework-bundle/pom.xml @@ -71,8 +71,7 @@ limitations under the License. org.apache.nifi - nifi-properties-loader - 2.0.0-SNAPSHOT + minifi-properties-loader org.apache.nifi @@ -80,6 +79,16 @@ limitations under the License. 2.0.0-SNAPSHOT test + + org.apache.nifi + nifi-property-protection-loader + 2.0.0-SNAPSHOT + + + org.apache.nifi + nifi-property-protection-cipher + 2.0.0-SNAPSHOT + \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md b/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md index 17fe2f564fdbd..29f8c859b6d49 100644 --- a/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md +++ b/minifi/minifi-toolkit/minifi-toolkit-assembly/README.md @@ -19,18 +19,19 @@ MiNiFi is a child project effort of Apache NiFi. The MiNiFi toolkit aids in cre ## Table of Contents - [Requirements](#requirements) -- [Getting Started](#getting-started) +- [MiNiFi Toolkit Converter](#minifi-toolkit-converter) +- [Encrypting Sensitive Properties in bootstrap.conf](#encrypt-sensitive-properties-in-bootstrapconf) - [Getting Help](#getting-help) - [Documentation](#documentation) - [License](#license) - [Export Control](#export-control) ## Requirements -* JRE 1.8 +* JRE 21 -## Getting Started +The latest version of the MiNiFi Toolkit can be found at https://nifi.apache.org/minifi/download.html under the `MiNiFi Toolkit Binaries` section. -The latest version of the MiNiFi Toolkit Converter can be found at https://nifi.apache.org/minifi/download.html under the `MiNiFi Toolkit Binaries` section. +# MiNiFi Toolkit Converter After downloading the binary and extracting it, to run the MiNiFi Toolkit Converter: - Change directory to the location where you installed MiNiFi Toolkit and run it and view usage information @@ -60,6 +61,87 @@ After downloading the binary and extracting it, to run the MiNiFi Toolkit Conver ## Note It's not guaranteed in all circumstances that the migration will result in a correct flow. For example if a processor's configuration has changed between version, the conversion tool won't be aware of this, and will use the deprecated property names. You will need to fix such issues manually. +# Encrypting Sensitive Properties in bootstrap.conf + +## MiNiFi Encrypt-Config Tool +The encrypt-config command line tool (invoked in minifi-toolkit as ./bin/encrypt-config.sh or bin\encrypt-config.bat) reads from a bootstrap.conf file with plaintext sensitive configuration values and encrypts each value using a random encryption key. It replaces the plain values with the protected value in the same file, or writes to a new bootstrap.conf file if specified. + +The supported encryption algorithm utilized is AES/GCM 256-bit. + +### Usage +To show help: + +``` +./bin/encrypt-config.sh -h +``` + +The following are the available options: +* -b, --bootstrapConf Path to file containing Bootstrap Configuration [bootstrap.conf] +* -B, --outputBootstrapConf Path to output file for Bootstrap Configuration [bootstrap.conf] with root key configured +* -h, --help Show help message and exit. + +### Example +As an example of how the tool works with the following existing values in the bootstrap.conf file: +``` +nifi.sensitive.props.key=thisIsABadSensitiveKeyPassword +nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 +nifi.sensitive.props.additional.keys= + +nifi.security.keystore=/path/to/keystore.jks +nifi.security.keystoreType=JKS +nifi.security.keystorePasswd=thisIsABadKeystorePassword +nifi.security.keyPasswd=thisIsABadKeyPassword +nifi.security.truststore= +nifi.security.truststoreType= +nifi.security.truststorePasswd= +c2.security.truststore.location= +c2.security.truststore.password=thisIsABadTruststorePassword +c2.security.truststore.type=JKS +c2.security.keystore.location= +c2.security.keystore.password=thisIsABadKeystorePassword +c2.security.keystore.type=JKS +``` +Enter the following arguments when using the tool: +``` +encrypt-config.sh \ +-b bootstrap.conf \ +``` +As a result, the bootstrap.conf file is overwritten with protected properties and sibling encryption identifiers (aes/gcm/256, the currently supported algorithm): +``` +nifi.sensitive.props.key=4OjkrFywZb7BlGz4||Tm9pg0jV4TltvVKeiMlm9zBsqmtmYUA2QkzcLKQpspyggtQuhNAkAla5s2695A== +nifi.sensitive.props.key.protected=aes/gcm/256 +nifi.sensitive.props.algorithm=NIFI_PBKDF2_AES_GCM_256 +nifi.sensitive.props.additional.keys= + +nifi.security.keystore=/path/to/keystore.jks +nifi.security.keystoreType=JKS +nifi.security.keystorePasswd=iXDmDCadoNJ3VotZ||WvOGbrii4Gk0vr3b6mDstZg+NE0BPZUPk6LVqQlf2Sx3G5XFbUbUYAUz +nifi.security.keystorePasswd.protected=aes/gcm/256 +nifi.security.keyPasswd=199uUUgpPqB4Fuoo||KckbW7iu+HZf1r4KSMQAFn8NLJK+CnUuayqPsTsdM0Wxou1BHg== +nifi.security.keyPasswd.protected=aes/gcm/256 +nifi.security.truststore= +nifi.security.truststoreType= +nifi.security.truststorePasswd= +c2.security.truststore.location= +c2.security.truststore.password=0pHpp+l/WHsDM/sm||fXBvDAQ1BXvNQ8b4EHKa1GspsLx+UD+2EDhph0HbsdmgpVhEv4qj0q5TDo0= +c2.security.truststore.password.protected=aes/gcm/256 +c2.security.truststore.type=JKS +c2.security.keystore.location= +c2.security.keystore.password=j+80L7++RNDf9INQ||RX/QkdVFwRos6Y4XJ8YSUWoI3W5Wx50dyw7HrAA84719SvfxA9eUSDEA +c2.security.keystore.password.protected=aes/gcm/256 +c2.security.keystore.type=JKS +``` + +Additionally, the bootstrap.conf file is updated with the encryption key as follows: +``` +minifi.bootstrap.sensitive.key=c92623e798be949379d0d18f432a57f1b74732141be321cb4af9ed94aa0ae8ac +``` + +Sensitive configuration values are encrypted by the tool by default, however you can encrypt any additional properties, if desired. To encrypt additional properties, specify them as comma-separated values in the minifi.sensitive.props.additional.keys property. + +If the bootstrap.conf file already has valid protected values, those property values are not modified by the tool. + + ## Getting Help If you have questions, you can reach out to our mailing list: dev@nifi.apache.org ([archive](https://mail-archives.apache.org/mod_mbox/nifi-dev)). diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml b/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml index 7f32bfcd07b79..90c1b1a9a746d 100644 --- a/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml +++ b/minifi/minifi-toolkit/minifi-toolkit-assembly/pom.xml @@ -62,6 +62,16 @@ limitations under the License. minifi-toolkit-configuration ${project.version} + + org.apache.nifi.minifi + minifi-toolkit-encrypt-config + ${project.version} + + + org.slf4j + slf4j-api + compile + diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat b/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat new file mode 100644 index 0000000000000..589d5a96902e1 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.bat @@ -0,0 +1,41 @@ +@echo off +rem +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed with +rem this work for additional information regarding copyright ownership. +rem The ASF licenses this file to You under the Apache License, Version 2.0 +rem (the "License"); you may not use this file except in compliance with +rem the License. You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. +rem + +rem Use JAVA_HOME if it's set; otherwise, just use java + +if "%JAVA_HOME%" == "" goto noJavaHome +if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome +set JAVA_EXE=%JAVA_HOME%\bin\java.exe +goto startConfig + +:noJavaHome +echo The JAVA_HOME environment variable is not defined correctly. +echo Instead the PATH will be used to find the java executable. +echo. +set JAVA_EXE=java +goto startConfig + +:startConfig +set LIB_DIR=%~dp0..\classpath;%~dp0..\lib + +if "%JAVA_OPTS%" == "" set JAVA_OPTS=-Xms128m -Xmx256m + +SET JAVA_PARAMS=-cp %LIB_DIR%\* %JAVA_OPTS% org.apache.nifi.minifi.toolkit.config.EncryptConfigCommand + +cmd.exe /C ""%JAVA_EXE%" %JAVA_PARAMS% %* "" + diff --git a/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh b/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh new file mode 100644 index 0000000000000..4aa5e13707ce0 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-assembly/src/main/resources/bin/encrypt-config.sh @@ -0,0 +1,119 @@ +#!/bin/sh +# +# 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. +# +# + +# Script structure inspired from Apache Karaf and other Apache projects with similar startup approaches + +SCRIPT_DIR=$(dirname "$0") +SCRIPT_NAME=$(basename "$0") +MINIFI_TOOLKIT_HOME=$(cd "${SCRIPT_DIR}" && cd .. && pwd) +PROGNAME=$(basename "$0") + + +warn() { + echo "${PROGNAME}: $*" +} + +die() { + warn "$*" + exit 1 +} + +detectOS() { + # OS specific support (must be 'true' or 'false'). + cygwin=false; + aix=false; + os400=false; + darwin=false; + case "$(uname)" in + CYGWIN*) + cygwin=true + ;; + AIX*) + aix=true + ;; + OS400*) + os400=true + ;; + Darwin) + darwin=true + ;; + esac + # For AIX, set an environment variable + if ${aix}; then + export LDR_CNTRL=MAXDATA=0xB0000000@DSA + echo ${LDR_CNTRL} + fi +} + +locateJava() { + # Setup the Java Virtual Machine + if $cygwin ; then + [ -n "${JAVA}" ] && JAVA=$(cygpath --unix "${JAVA}") + [ -n "${JAVA_HOME}" ] && JAVA_HOME=$(cygpath --unix "${JAVA_HOME}") + fi + + if [ "x${JAVA}" = "x" ] && [ -r /etc/gentoo-release ] ; then + JAVA_HOME=$(java-config --jre-home) + fi + if [ "x${JAVA}" = "x" ]; then + if [ "x${JAVA_HOME}" != "x" ]; then + if [ ! -d "${JAVA_HOME}" ]; then + die "JAVA_HOME is not valid: ${JAVA_HOME}" + fi + JAVA="${JAVA_HOME}/bin/java" + else + warn "JAVA_HOME not set; results may vary" + JAVA=$(type java) + JAVA=$(expr "${JAVA}" : '.* \(/.*\)$') + if [ "x${JAVA}" = "x" ]; then + die "java command not found" + fi + fi + fi +} + +init() { + # Determine if there is special OS handling we must perform + detectOS + + # Locate the Java VM to execute + locateJava +} + +run() { + LIBS="${MINIFI_TOOLKIT_HOME}/lib/*" + + sudo_cmd_prefix="" + if $cygwin; then + MINIFI_TOOLKIT_HOME=$(cygpath --path --windows "${MINIFI_TOOLKIT_HOME}") + CLASSPATH="$MINIFI_TOOLKIT_HOME/classpath;$(cygpath --path --windows "${LIBS}")" + else + CLASSPATH="$MINIFI_TOOLKIT_HOME/classpath:${LIBS}" + fi + + export JAVA_HOME="$JAVA_HOME" + export MINIFI_TOOLKIT_HOME="$MINIFI_TOOLKIT_HOME" + + umask 0077 + exec "${JAVA}" -cp "${CLASSPATH}" ${JAVA_OPTS:--Xms128m -Xmx256m} org.apache.nifi.minifi.toolkit.config.EncryptConfigCommand "$@" +} + + +init +run "$@" diff --git a/minifi/minifi-toolkit/minifi-toolkit-configuration/pom.xml b/minifi/minifi-toolkit/minifi-toolkit-configuration/pom.xml index 4dcbe0730b5ea..f95df2e635028 100644 --- a/minifi/minifi-toolkit/minifi-toolkit-configuration/pom.xml +++ b/minifi/minifi-toolkit/minifi-toolkit-configuration/pom.xml @@ -35,10 +35,6 @@ limitations under the License. minifi-toolkit-schema ${project.version} - - org.apache.nifi - nifi-framework-core - org.apache.nifi nifi-property-utils @@ -48,6 +44,20 @@ limitations under the License. org.apache.nifi nifi-properties + + + commons-io + commons-io + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + + + + com.fasterxml.jackson.module + jackson-module-jakarta-xmlbind-annotations + diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/pom.xml b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/pom.xml new file mode 100644 index 0000000000000..fd936cad8d4cb --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/pom.xml @@ -0,0 +1,57 @@ + + + + + org.apache.nifi.minifi + minifi-toolkit + 2.0.0-SNAPSHOT + + 4.0.0 + + minifi-toolkit-encrypt-config + Tool to encrypt sensitive configuration values + + + info.picocli + picocli + 4.7.5 + + + org.apache.nifi + nifi-property-protection-api + 2.0.0-SNAPSHOT + + + org.apache.nifi + nifi-property-protection-cipher + 2.0.0-SNAPSHOT + + + org.apache.nifi.minifi + minifi-properties-loader + 2.0.0-SNAPSHOT + + + org.slf4j + slf4j-api + compile + + + org.apache.nifi.minifi + minifi-commons-utils + + + diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/EncryptConfigCommand.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/EncryptConfigCommand.java new file mode 100644 index 0000000000000..9e9942ac33402 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/EncryptConfigCommand.java @@ -0,0 +1,42 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.toolkit.config; + +import org.apache.nifi.minifi.toolkit.config.command.MiNiFiEncryptConfig; +import picocli.CommandLine; + +/** + * Encrypt Config Command launcher for Command Line implementation + */ +public class EncryptConfigCommand { + + /** + * Main command method launches Picocli Command Line implementation of Encrypt Config + * + * @param arguments Command line arguments + */ + public static void main(String[] arguments) { + CommandLine commandLine = new CommandLine(new MiNiFiEncryptConfig()); + if (arguments.length == 0) { + commandLine.usage(System.out); + } else { + int status = commandLine.execute(arguments); + System.exit(status); + } + } + +} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/command/MiNiFiEncryptConfig.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/command/MiNiFiEncryptConfig.java new file mode 100644 index 0000000000000..f5e6248240206 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/command/MiNiFiEncryptConfig.java @@ -0,0 +1,146 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.toolkit.config.command; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.security.SecureRandom; +import java.util.HashSet; +import java.util.HexFormat; +import java.util.Optional; +import java.util.Set; +import org.apache.nifi.minifi.properties.BootstrapProperties; +import org.apache.nifi.minifi.properties.BootstrapPropertiesLoader; +import org.apache.nifi.minifi.properties.ProtectedBootstrapProperties; +import org.apache.nifi.minifi.toolkit.config.transformer.ApplicationPropertiesFileTransformer; +import org.apache.nifi.minifi.toolkit.config.transformer.BootstrapConfigurationFileTransformer; +import org.apache.nifi.minifi.toolkit.config.transformer.FileTransformer; +import org.apache.nifi.properties.AesGcmSensitivePropertyProvider; +import org.apache.nifi.properties.SensitivePropertyProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import picocli.CommandLine.Command; +import picocli.CommandLine.Option; + +/** + * Shared Encrypt Configuration for NiFi and NiFi Registry + */ +@Command( + name = "encrypt-config", + sortOptions = false, + mixinStandardHelpOptions = true, + usageHelpWidth = 160, + separator = " ", + version = { + "Java ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})" + }, + descriptionHeading = "Description: ", + description = { + "encrypt-config supports protection of sensitive values in Apache MiNiFi" + } +) +public class MiNiFiEncryptConfig implements Runnable{ + + static final String BOOTSTRAP_ROOT_KEY_PROPERTY = "minifi.bootstrap.sensitive.key"; + + private static final String WORKING_FILE_NAME_FORMAT = "%s.%d.working"; + private static final int KEY_LENGTH = 32; + + @Option( + names = {"-b", "--bootstrapConf"}, + description = "Path to file containing Bootstrap Configuration [bootstrap.conf] for optional root key and property protection scheme settings" + ) + Path bootstrapConfPath; + + @Option( + names = {"-B", "--outputBootstrapConf"}, + description = "Path to output file for Bootstrap Configuration [bootstrap.conf] with root key configured" + ) + Path outputBootstrapConf; + + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + @Override + public void run() { + processBootstrapConf(); + } + + /** + * Process bootstrap.conf writing new Root Key to specified Root Key Property when bootstrap.conf is specified + * + */ + protected void processBootstrapConf() { + BootstrapProperties unprotectedProperties = BootstrapPropertiesLoader.load(bootstrapConfPath.toFile()); + + logger.info("Started processing Bootstrap Configuration [{}]", bootstrapConfPath); + + String newRootKey = getRootKey(); + + Set sensitivePropertyNames = new HashSet<>((new ProtectedBootstrapProperties(unprotectedProperties)).getSensitivePropertyKeys()); + FileTransformer fileTransformer2 = new ApplicationPropertiesFileTransformer(unprotectedProperties, getInputSensitivePropertyProvider(newRootKey), sensitivePropertyNames); + runFileTransformer(fileTransformer2, bootstrapConfPath, outputBootstrapConf); + + FileTransformer fileTransformer = new BootstrapConfigurationFileTransformer(BOOTSTRAP_ROOT_KEY_PROPERTY, newRootKey); + runFileTransformer(fileTransformer, Optional.ofNullable(outputBootstrapConf).orElse(bootstrapConfPath), outputBootstrapConf); + logger.info("Completed processing Bootstrap Configuration [{}]", bootstrapConfPath); + } + + private String getRootKey() { + SecureRandom secureRandom = new SecureRandom(); + byte[] sensitivePropertiesKeyBinary = new byte[KEY_LENGTH]; + secureRandom.nextBytes(sensitivePropertiesKeyBinary); + return HexFormat.of().formatHex(sensitivePropertiesKeyBinary); + } + + /** + * Run File Transformer using working path based on output path + * + * @param fileTransformer File Transformer to be invoked + * @param inputPath Input path of file to be transformed + * @param outputPath Output path for transformed file that defaults to the input path when not specified + */ + protected void runFileTransformer(FileTransformer fileTransformer, Path inputPath, Path outputPath) { + Path configuredOutputPath = outputPath == null ? inputPath : outputPath; + Path workingPath = getWorkingPath(configuredOutputPath); + try { + fileTransformer.transform(inputPath, workingPath); + Files.move(workingPath, configuredOutputPath, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + String message = String.format("Processing Configuration [%s] failed", inputPath); + throw new UncheckedIOException(message, e); + } + } + + + /** + * Get Input Sensitive Property Provider for decrypting previous values + * + * @return Input Sensitive Property Provider + */ + protected SensitivePropertyProvider getInputSensitivePropertyProvider(String keyHex) { + return new AesGcmSensitivePropertyProvider(keyHex); + } + + private Path getWorkingPath(Path resourcePath) { + Path fileName = resourcePath.getFileName(); + String workingFileName = String.format(WORKING_FILE_NAME_FORMAT, fileName, System.currentTimeMillis()); + return resourcePath.resolveSibling(workingFileName); + } +} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java new file mode 100644 index 0000000000000..5cdc8668dd868 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformer.java @@ -0,0 +1,152 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.toolkit.config.transformer; + +import static org.apache.nifi.properties.ApplicationPropertiesProtector.PROTECTED_KEY_SUFFIX; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.nifi.properties.ApplicationProperties; +import org.apache.nifi.properties.ApplicationPropertiesProtector; +import org.apache.nifi.properties.ProtectedPropertyContext; +import org.apache.nifi.properties.SensitivePropertyProvider; + +/** + * File Transformer supporting transformation of Application Properties with sensitive property values + */ +public class ApplicationPropertiesFileTransformer implements FileTransformer { + + private static final Pattern PROPERTY_VALUE_PATTERN = Pattern.compile("^([^#!][^=]+?)\\s*=\\s?(.+)"); + + private static final int NAME_GROUP = 1; + + private static final int VALUE_GROUP = 2; + + private static final char PROPERTY_VALUE_SEPARATOR = '='; + + private final ApplicationProperties applicationProperties; + + private final SensitivePropertyProvider outputSensitivePropertyProvider; + + private final Set sensitivePropertyNames; + + /** + * Application Properties File Transformer uses provided Application Properties as the source of protected values + * + * @param applicationProperties Application Properties containing decrypted source property values + * @param outputSensitivePropertyProvider Sensitive Property Provider encrypts specified sensitive property values + * @param sensitivePropertyNames Sensitive Property Names marked for encryption + */ + public ApplicationPropertiesFileTransformer( + ApplicationProperties applicationProperties, + SensitivePropertyProvider outputSensitivePropertyProvider, + Set sensitivePropertyNames + ) { + this.applicationProperties = Objects.requireNonNull(applicationProperties, "Application Properties required"); + this.outputSensitivePropertyProvider = Objects.requireNonNull(outputSensitivePropertyProvider, "Output Property Provider required"); + this.sensitivePropertyNames = Objects.requireNonNull(sensitivePropertyNames, "Sensitive Property Names required"); + } + + /** + * Transform input application properties using configured Sensitive Property Provider and write output properties + * + * @param inputPath Input file path to be transformed containing source application properties + * @param outputPath Output file path for protected application properties + * @throws IOException Thrown on transformation failures + */ + @Override + public void transform(Path inputPath, Path outputPath) throws IOException { + Objects.requireNonNull(inputPath, "Input path required"); + Objects.requireNonNull(outputPath, "Output path required"); + + try (BufferedReader reader = Files.newBufferedReader(inputPath); + BufferedWriter writer = Files.newBufferedWriter(outputPath)) { + transform(reader, writer); + } + } + + private void transform(BufferedReader reader, BufferedWriter writer) throws IOException { + String line = reader.readLine(); + while (line != null) { + Matcher matcher = PROPERTY_VALUE_PATTERN.matcher(line); + String nextLine = null; + if (matcher.matches()) { + nextLine = processPropertyLine(reader, writer, matcher, line); + } else { + writeNonSensitiveLine(writer, line); + } + + line = nextLine == null ? reader.readLine() : nextLine; + } + } + + private String processPropertyLine(BufferedReader reader, BufferedWriter writer, Matcher matcher, String line) throws IOException { + String actualPropertyName = matcher.group(NAME_GROUP); + String actualPropertyValue = matcher.group(VALUE_GROUP); + String nextLine = null; + + if (!actualPropertyName.endsWith(PROTECTED_KEY_SUFFIX)) { + nextLine = reader.readLine(); + if (sensitivePropertyNames.contains(actualPropertyName) || isNextPropertyProtected(actualPropertyName, nextLine)) { + String applicationProperty = applicationProperties.getProperty(actualPropertyName, actualPropertyValue); + writeProtectedProperty(writer, actualPropertyName, applicationProperty); + } else { + writeNonSensitiveLine(writer, line); + } + } + return nextLine; + } + + private void writeNonSensitiveLine(BufferedWriter writer, String line) throws IOException { + writer.write(line); + writer.newLine(); + } + + private boolean isNextPropertyProtected(String actualPropertyName, String nextLine) { + if (nextLine != null) { + Matcher nextLineMatcher = PROPERTY_VALUE_PATTERN.matcher(nextLine); + if (nextLineMatcher.matches()) { + String protectedActualPropertyName = ApplicationPropertiesProtector.getProtectionKey(actualPropertyName); + String nextName = nextLineMatcher.group(NAME_GROUP); + return protectedActualPropertyName.equals(nextName); + } + } + return false; + } + + private void writeProtectedProperty(BufferedWriter writer, String name, String value) throws IOException { + ProtectedPropertyContext propertyContext = ProtectedPropertyContext.defaultContext(name); + String protectedValue = outputSensitivePropertyProvider.protect(value, propertyContext); + + writer.write(name); + writer.write(PROPERTY_VALUE_SEPARATOR); + writeNonSensitiveLine(writer, protectedValue); + + String protectedName = ApplicationPropertiesProtector.getProtectionKey(name); + writer.write(protectedName); + writer.write(PROPERTY_VALUE_SEPARATOR); + String protectionIdentifierKey = outputSensitivePropertyProvider.getIdentifierKey(); + writeNonSensitiveLine(writer, protectionIdentifierKey); + } +} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java new file mode 100644 index 0000000000000..8325c1ef70efd --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformer.java @@ -0,0 +1,108 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.toolkit.config.transformer; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * File Transformer supporting Bootstrap Configuration with updated Root Key + */ +public class BootstrapConfigurationFileTransformer implements FileTransformer { + + private static final Pattern PROPERTY_VALUE_PATTERN = Pattern.compile("^([^#!][^=]+?)\\s*=.*"); + + private static final int NAME_GROUP = 1; + + private static final char PROPERTY_VALUE_SEPARATOR = '='; + + private final String rootKeyPropertyName; + + private final String rootKey; + + /** + * Bootstrap Configuration File Transformer writes provided Root Key to output files + * + * @param rootKeyPropertyName Root Key property name to be written + * @param rootKey Root Key to be written + */ + public BootstrapConfigurationFileTransformer(String rootKeyPropertyName, String rootKey) { + this.rootKeyPropertyName = Objects.requireNonNull(rootKeyPropertyName, "Root Key Property Name required"); + this.rootKey = Objects.requireNonNull(rootKey, "Root Key required"); + } + + /** + * Transform input configuration and write Root Key to output location + * + * @param inputPath Input file path to be transformed containing Bootstrap Configuration + * @param outputPath Output file path for updated configuration + * @throws IOException Thrown on transformation failures + */ + @Override + public void transform(Path inputPath, Path outputPath) throws IOException { + Objects.requireNonNull(inputPath, "Input path required"); + Objects.requireNonNull(outputPath, "Output path required"); + + try (BufferedReader reader = Files.newBufferedReader(inputPath); + BufferedWriter writer = Files.newBufferedWriter(outputPath)) { + transform(reader, writer); + } + } + + private void transform(BufferedReader reader, BufferedWriter writer) throws IOException { + boolean rootKeyPropertyNotFound = true; + + String line = reader.readLine(); + while (line != null) { + Matcher matcher = PROPERTY_VALUE_PATTERN.matcher(line); + if (matcher.matches()) { + String name = matcher.group(NAME_GROUP); + + if (rootKeyPropertyName.equals(name)) { + writeRootKey(writer); + rootKeyPropertyNotFound = false; + } else { + writer.write(line); + writer.newLine(); + } + } else { + writer.write(line); + writer.newLine(); + } + + line = reader.readLine(); + } + + if (rootKeyPropertyNotFound) { + writer.newLine(); + writeRootKey(writer); + } + } + + private void writeRootKey(BufferedWriter writer) throws IOException { + writer.write(rootKeyPropertyName); + writer.write(PROPERTY_VALUE_SEPARATOR); + writer.write(rootKey); + writer.newLine(); + } +} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/FileTransformer.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/FileTransformer.java new file mode 100644 index 0000000000000..ecc05a43b649c --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/main/java/org/apache/nifi/minifi/toolkit/config/transformer/FileTransformer.java @@ -0,0 +1,34 @@ +/* + * 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. + */ +package org.apache.nifi.minifi.toolkit.config.transformer; + +import java.io.IOException; +import java.nio.file.Path; + +/** + * Abstraction for transforming Files + */ +public interface FileTransformer { + /** + * Transform input file and write contents to output file path + * + * @param inputPath Input file path to be transformed + * @param outputPath Output file path + * @throws IOException Thrown on input or output processing failures + */ + void transform(Path inputPath, Path outputPath) throws IOException; +} diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java new file mode 100644 index 0000000000000..11bf6b01066a3 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/ApplicationPropertiesFileTransformerTest.java @@ -0,0 +1,99 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.toolkit.config.transformer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.Set; +import org.apache.nifi.properties.ApplicationProperties; +import org.apache.nifi.properties.SensitivePropertyProvider; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class ApplicationPropertiesFileTransformerTest { + + private static final String UNPROTECTED_BOOTSTRAP_CONF = "/transformer/unprotected.conf"; + private static final String PROTECTED_BOOTSTRAP_PROPERTIES = "/transformer/protected.conf"; + private static final String PROPERTIES_TRANSFORMED = "transformed.conf"; + private static final String SENSITIVE_PROPERTY_NAME_1 = "property1"; + private static final String SENSITIVE_PROPERTY_NAME_2 = "property2"; + private static final String SENSITIVE_PROPERTY_NAME_3 = "property3"; + private static final String PROVIDER_IDENTIFIER_KEY = "mocked-provider"; + private static final String UNPROTECTED = "UNPROTECTED"; + private static final String ENCRYPTED = "ENCRYPTED"; + + private static final Set SENSITIVE_PROPERTY_NAMES = Set.of(SENSITIVE_PROPERTY_NAME_1, SENSITIVE_PROPERTY_NAME_2, SENSITIVE_PROPERTY_NAME_3); + + @TempDir + private Path tempDir; + + @Mock + private SensitivePropertyProvider sensitivePropertyProvider; + + @Test + void shouldTransformProperties() throws URISyntaxException, IOException { + Path propertiesPath = getResourcePath(UNPROTECTED_BOOTSTRAP_CONF); + + Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); + Files.copy(propertiesPath, tempPropertiesPath); + + Path outputPropertiesPath = tempDir.resolve(PROPERTIES_TRANSFORMED); + ApplicationProperties applicationProperties = new ApplicationProperties(Map.of(SENSITIVE_PROPERTY_NAME_3, UNPROTECTED)); + FileTransformer transformer = new ApplicationPropertiesFileTransformer(applicationProperties, sensitivePropertyProvider, SENSITIVE_PROPERTY_NAMES); + + when(sensitivePropertyProvider.getIdentifierKey()).thenReturn(PROVIDER_IDENTIFIER_KEY); + when(sensitivePropertyProvider.protect(eq(UNPROTECTED), any())).thenReturn(ENCRYPTED); + + transformer.transform(tempPropertiesPath, outputPropertiesPath); + + Properties expectedProperties = loadProperties(getResourcePath(PROTECTED_BOOTSTRAP_PROPERTIES)); + Properties resultProperties = loadProperties(outputPropertiesPath); + + assertEquals(expectedProperties, resultProperties); + } + + private Properties loadProperties(Path resourcePath) throws IOException { + Properties properties = new Properties(); + try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { + properties.load(propertiesStream); + } + return properties; + } + + private Path getResourcePath(String resource) throws URISyntaxException { + final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); + return Paths.get(resourceUrl.toURI()); + } +} \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformerTest.java b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformerTest.java new file mode 100644 index 0000000000000..cd05132aef002 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/java/org/apache/nifi/minifi/toolkit/config/transformer/BootstrapConfigurationFileTransformerTest.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package org.apache.nifi.minifi.toolkit.config.transformer; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Objects; +import java.util.Properties; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class BootstrapConfigurationFileTransformerTest { + private static final String BOOTSTRAP_ROOT_KEY_PROPERTY = "minifi.bootstrap.sensitive.key"; + private static final String MOCK_KEY = "mockKey"; + private static final String BOOTSTRAP_CONF_FILE_WITHOUT_KEY = "/transformer/bootstrap_without_key.conf"; + private static final String BOOTSTRAP_CONF_TRANSFORMED= "transformed.conf"; + + @TempDir + private Path tempDir; + + @Test + void shouldWriteRootPropertyKeyIfItIsNotPresent() throws URISyntaxException, IOException { + Path propertiesPath = getResourcePath(BOOTSTRAP_CONF_FILE_WITHOUT_KEY); + + Path tempPropertiesPath = tempDir.resolve(propertiesPath.getFileName()); + Files.copy(propertiesPath, tempPropertiesPath); + + Path outputPropertiesPath = tempDir.resolve(BOOTSTRAP_CONF_TRANSFORMED); + + BootstrapConfigurationFileTransformer transformer = new BootstrapConfigurationFileTransformer(BOOTSTRAP_ROOT_KEY_PROPERTY, MOCK_KEY); + transformer.transform(tempPropertiesPath, outputPropertiesPath); + + Properties properties = loadProperties(outputPropertiesPath); + assertEquals(MOCK_KEY, properties.get(BOOTSTRAP_ROOT_KEY_PROPERTY)); + } + + private Properties loadProperties(Path resourcePath) throws IOException { + Properties properties = new Properties(); + try (InputStream propertiesStream = Files.newInputStream(resourcePath)) { + properties.load(propertiesStream); + } + return properties; + } + + private Path getResourcePath(String resource) throws URISyntaxException { + final URL resourceUrl = Objects.requireNonNull(getClass().getResource(resource), String.format("Resource [%s] not found", resource)); + return Paths.get(resourceUrl.toURI()); + } +} \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/bootstrap_without_key.conf b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/bootstrap_without_key.conf new file mode 100644 index 0000000000000..ae1e83eeb3d49 --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/bootstrap_without_key.conf @@ -0,0 +1,14 @@ +# 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. diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/protected.conf b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/protected.conf new file mode 100644 index 0000000000000..573f76b514abe --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/protected.conf @@ -0,0 +1,22 @@ +# 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. + +property1=ENCRYPTED +property1.protected=mocked-provider +property2=ENCRYPTED +property2.protected=mocked-provider +nonsensitive.property=value +property3=ENCRYPTED +property3.protected=mocked-provider \ No newline at end of file diff --git a/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/unprotected.conf b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/unprotected.conf new file mode 100644 index 0000000000000..5efa9a484d0fb --- /dev/null +++ b/minifi/minifi-toolkit/minifi-toolkit-encrypt-config/src/test/resources/transformer/unprotected.conf @@ -0,0 +1,20 @@ +# 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. + +property1=UNPROTECTED +property2=UNPROTECTED +nonsensitive.property=value +property3=ENCRYPTED +property3.protected=mocked-provider \ No newline at end of file diff --git a/minifi/minifi-toolkit/pom.xml b/minifi/minifi-toolkit/pom.xml index f625769a64527..175f7d8d51221 100644 --- a/minifi/minifi-toolkit/pom.xml +++ b/minifi/minifi-toolkit/pom.xml @@ -29,5 +29,13 @@ limitations under the License. minifi-toolkit-schema minifi-toolkit-configuration minifi-toolkit-assembly + minifi-toolkit-encrypt-config + + + + org.slf4j + slf4j-simple + + diff --git a/minifi/pom.xml b/minifi/pom.xml index aa13d86aa9590..6178e865e18ce 100644 --- a/minifi/pom.xml +++ b/minifi/pom.xml @@ -86,6 +86,11 @@ limitations under the License. minifi-resources 2.0.0-SNAPSHOT + + org.apache.nifi.minifi + minifi-properties-loader + 2.0.0-SNAPSHOT + org.apache.nifi.minifi minifi-provenance-repository-nar diff --git a/nifi-api/pom.xml b/nifi-api/pom.xml index 92265155f22d6..a45c9e1354d6b 100644 --- a/nifi-api/pom.xml +++ b/nifi-api/pom.xml @@ -34,7 +34,7 @@ --> - io.swagger + io.swagger.core.v3 swagger-annotations compile true diff --git a/nifi-api/src/main/java/org/apache/nifi/components/AllowableValue.java b/nifi-api/src/main/java/org/apache/nifi/components/AllowableValue.java index b8303ae122c4d..3a76683274521 100644 --- a/nifi-api/src/main/java/org/apache/nifi/components/AllowableValue.java +++ b/nifi-api/src/main/java/org/apache/nifi/components/AllowableValue.java @@ -43,9 +43,8 @@ public AllowableValue(final String value) { * Constructs a new AllowableValue with the given value and display name and * no description * - * @param value that is allowed + * @param value that is allowed * @param displayName to display for the value - * * @throws NullPointerException if either argument is null */ public AllowableValue(final String value, final String displayName) { @@ -56,10 +55,9 @@ public AllowableValue(final String value, final String displayName) { * Constructs a new AllowableValue with the given value, display name, and * description * - * @param value that is valid + * @param value that is valid * @param displayName to show for the value * @param description of the value - * * @throws NullPointerException if identifier or value is null */ public AllowableValue(final String value, final String displayName, final String description) { @@ -68,6 +66,14 @@ public AllowableValue(final String value, final String displayName, final String this.description = description; } + public static AllowableValue fromDescribedValue(final DescribedValue describedValue) { + if (describedValue instanceof AllowableValue allowableValue) { + return allowableValue; + } + + return new AllowableValue(describedValue.getValue(), describedValue.getDisplayName(), describedValue.getDescription()); + } + /** * @return the value of this AllowableValue */ @@ -106,8 +112,7 @@ public boolean equals(final Object obj) { return true; } - if (obj instanceof AllowableValue) { - final AllowableValue other = (AllowableValue) obj; + if (obj instanceof AllowableValue other) { return (this.value.equals(other.getValue())); } else if (obj instanceof String) { return this.value.equals(obj); diff --git a/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java b/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java index 1d039058f4413..35d0a8f131c50 100644 --- a/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java +++ b/nifi-api/src/main/java/org/apache/nifi/components/PropertyDescriptor.java @@ -19,9 +19,9 @@ import org.apache.nifi.components.resource.ResourceCardinality; import org.apache.nifi.components.resource.ResourceDefinition; import org.apache.nifi.components.resource.ResourceReference; -import org.apache.nifi.components.resource.StandardResourceReferenceFactory; import org.apache.nifi.components.resource.ResourceType; import org.apache.nifi.components.resource.StandardResourceDefinition; +import org.apache.nifi.components.resource.StandardResourceReferenceFactory; import org.apache.nifi.controller.ControllerService; import org.apache.nifi.expression.ExpressionLanguageScope; @@ -38,7 +38,6 @@ /** * An immutable object for holding information about a type of component * property. - * */ public final class PropertyDescriptor implements Comparable { @@ -123,15 +122,15 @@ protected PropertyDescriptor(final Builder builder) { this.name = builder.name; this.description = builder.description; this.defaultValue = builder.defaultValue; - this.allowableValues = builder.allowableValues == null ? null : Collections.unmodifiableList(new ArrayList<>(builder.allowableValues)); + this.allowableValues = builder.allowableValues == null ? null : List.copyOf(builder.allowableValues); this.required = builder.required; this.sensitive = builder.sensitive; this.dynamic = builder.dynamic; this.dynamicallyModifiesClasspath = builder.dynamicallyModifiesClasspath; this.expressionLanguageScope = builder.expressionLanguageScope; this.controllerServiceDefinition = builder.controllerServiceDefinition; - this.validators = Collections.unmodifiableList(new ArrayList<>(builder.validators)); - this.dependencies = builder.dependencies == null ? Collections.emptySet() : Collections.unmodifiableSet(new HashSet<>(builder.dependencies)); + this.validators = List.copyOf(builder.validators); + this.dependencies = builder.dependencies == null ? Collections.emptySet() : Set.copyOf(builder.dependencies); this.resourceDefinition = builder.resourceDefinition; } @@ -148,7 +147,7 @@ public int compareTo(final PropertyDescriptor o) { * If this descriptor has a set of allowable values then the given value is * only checked against the allowable values. * - * @param input the value to validate + * @param input the value to validate * @param context the context of validation * @return the result of validating the input */ @@ -188,15 +187,15 @@ public ValidationResult validate(final String input, final ValidationContext con final ControllerService service = context.getControllerServiceLookup().getControllerService(input); if (service == null) { return new ValidationResult.Builder() - .input(input) - .subject(getDisplayName()) - .valid(false) - .explanation("Property references a Controller Service that does not exist") - .build(); + .input(input) + .subject(getDisplayName()) + .valid(false) + .explanation("Property references a Controller Service that does not exist") + .build(); } else { return new ValidationResult.Builder() - .valid(true) - .build(); + .valid(true) + .build(); } } @@ -293,15 +292,13 @@ public Builder description(final String description) { } /** - * Specifies the initial value and the default value that will be used - * if the user does not specify a value. When {@link #build()} is - * called, if Allowable Values have been set (see - * {@link #allowableValues(AllowableValue...)}) and this value is not - * one of those Allowable Values, an Exception will be thrown. If the - * Allowable Values have been set using the - * {@link #allowableValues(AllowableValue...)} method, the default value - * should be set to the "Value" of the {@link AllowableValue} object - * (see {@link AllowableValue#getValue()}). + * Specifies the initial value and the default value that will be used if the user does not specify a value. + *

+ * When {@link #build()} is called, if Allowable Values have been set (see {@link #allowableValues(DescribedValue...)} and overloads) + * and this value is not one of those Allowable Values, an Exception will be thrown. + * If the Allowable Values have been set, the default value should be set to + * the "Value" of the {@link DescribedValue} object (see {@link DescribedValue#getValue()}). + * There's an overload available for this (see {@link #defaultValue(DescribedValue)}). * * @param value default value * @return the builder @@ -314,15 +311,12 @@ public Builder defaultValue(final String value) { } /** - * Specifies the initial value and the default value that will be used - * if the user does not specify a value. When {@link #build()} is - * called, if Allowable Values have been set (see - * {@link #allowableValues(AllowableValue...)}) - * and the "Value" of the {@link DescribedValue} object is not - * the "Value" of one of those Allowable Values, an Exception will be thrown. - * If the Allowable Values have been set using the - * {@link #allowableValues(AllowableValue...)} method, the default value - * should be set providing the {@link AllowableValue} to this method. + * Specifies the initial value and the default value that will be used if the user does not specify a value. + *

+ * Sets the default value to the "Value" of the {@link DescribedValue} object. + * When {@link #build()} is called, if Allowable Values have been set (see {@link #allowableValues(DescribedValue...)} and overloads) + * and this value is not one of those Allowable Values, an Exception will be thrown. + * In case there is not a restricted set of Allowable Values {@link #defaultValue(String)} may be used. * * @param value default value holder * @return the builder @@ -331,6 +325,16 @@ public Builder defaultValue(final DescribedValue value) { return defaultValue(value != null ? value.getValue() : null); } + /** + * Clears the initial value and default value from this Property. + * + * @return the builder + */ + public Builder clearDefaultValue() { + this.defaultValue = null; + return this; + } + public Builder dynamic(final boolean dynamic) { this.dynamic = dynamic; return this; @@ -342,17 +346,17 @@ public Builder dynamic(final boolean dynamic) { * libraries for the given component. *

* NOTE: If a component contains a PropertyDescriptor where dynamicallyModifiesClasspath is set to true, - * the component may also be annotated with @RequiresInstanceClassloading, in which case every class will - * be loaded by a separate InstanceClassLoader for each processor instance.
- * It also allows to load native libraries from the extra classpath. - *

- * One can chose to omit the annotation. In this case the loading of native libraries from the extra classpath - * is not supported. - * Also by default, classes will be loaded by a common NarClassLoader, however it's possible to acquire an - * InstanceClassLoader by calling Thread.currentThread().getContextClassLoader() which can be used manually - * to load required classes on an instance-by-instance basis - * (by calling {@link Class#forName(String, boolean, ClassLoader)} for example). - * + * the component may also be annotated with @RequiresInstanceClassloading, in which case every class will + * be loaded by a separate InstanceClassLoader for each processor instance.
+ * It also allows to load native libraries from the extra classpath. + *

+ * One can choose to omit the annotation. In this case the loading of native libraries from the extra classpath + * is not supported. + * Also by default, classes will be loaded by a common NarClassLoader, however it's possible to acquire an + * InstanceClassLoader by calling Thread.currentThread().getContextClassLoader() which can be used manually + * to load required classes on an instance-by-instance basis + * (by calling {@link Class#forName(String, boolean, ClassLoader)} for example). + *

* Any property descriptor that dynamically modifies the classpath should also make use of the {@link #identifiesExternalResource(ResourceCardinality, ResourceType, ResourceType...)} method * to indicate that the property descriptor references external resources and optionally restrict which types of resources and how many resources the property allows. * @@ -365,92 +369,110 @@ public Builder dynamicallyModifiesClasspath(final boolean dynamicallyModifiesCla } /** - * @param values contrained set of values + * Sets the Allowable Values for this Property. + * + * @param values constrained set of values * @return the builder */ public Builder allowableValues(final Set values) { if (null != values) { - this.allowableValues = new ArrayList<>(); - - for (final String value : values) { - this.allowableValues.add(new AllowableValue(value, value)); - } + this.allowableValues = values.stream().map(AllowableValue::new).toList(); } return this; } + /** + * Sets the Allowable Values for this Property. + *

+ * Uses the {@link Enum#name()} of each value as "Value" for the {@link AllowableValue}. + * In case the enum value is a {@link DescribedValue}, uses the information provided instead + * (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, {@link DescribedValue#getDescription()}). + * + * @param values constrained set of values + * @return the builder + */ public > Builder allowableValues(final E[] values) { if (null != values) { - this.allowableValues = new ArrayList<>(); - for (final E value : values) { - allowableValues.add(new AllowableValue(value.name(), value.name())); - } + this.allowableValues = Arrays.stream(values) + .map(enumValue -> enumValue instanceof DescribedValue describedValue + ? AllowableValue.fromDescribedValue(describedValue) : new AllowableValue(enumValue.name())) + .toList(); } return this; } /** - * Stores allowable values from an enum class. - * @param enumClass an enum class that implements the DescribedValue interface and contains a set of values - * @param generic parameter for an enum class that implements the DescribedValue interface + * Sets the Allowable Values for this Property. + *

+ * Uses the {@link Enum#name()} of each value from {@link Class#getEnumConstants()} as "Value" for the {@link AllowableValue}. + * In case the enum value is a {@link DescribedValue}, uses the information provided instead + * (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, {@link DescribedValue#getDescription()}). + * + * @param enumClass an enum class that contains a set of values and optionally implements the DescribedValue interface + * @param generic parameter for an enum class, that may implement the DescribedValue interface * @return the builder */ - public & DescribedValue> Builder allowableValues(final Class enumClass) { - this.allowableValues = new ArrayList<>(); - for (E enumValue : enumClass.getEnumConstants()) { - this.allowableValues.add(new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription())); - } - return this; + public > Builder allowableValues(final Class enumClass) { + return allowableValues(enumClass.getEnumConstants()); } /** - * Stores allowable values from a set of enum values. - * @param enumValues a set of enum values that implements the DescribedValue interface - * @param generic parameter for the enum values' class that implements the DescribedValue interface + * Sets the Allowable Values for this Property. + *

+ * Uses the {@link Enum#name()} of each value of the {@link EnumSet} as "Value" for the {@link AllowableValue}. + * In case the enum value is a {@link DescribedValue}, uses the information provided instead + * (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, {@link DescribedValue#getDescription()}). + * + * @param enumValues an enum set that contains a set of values and optionally implements the DescribedValue interface + * @param generic parameter for an enum class, that may implement the DescribedValue interface * @return the builder */ - public & DescribedValue> Builder allowableValues(final EnumSet enumValues) { - this.allowableValues = new ArrayList<>(); - for (E enumValue : enumValues) { - this.allowableValues.add(new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription())); + public > Builder allowableValues(final EnumSet enumValues) { + if (null != enumValues) { + this.allowableValues = enumValues.stream() + .map(enumValue -> enumValue instanceof DescribedValue describedValue + ? AllowableValue.fromDescribedValue(describedValue) : new AllowableValue(enumValue.name())) + .toList(); } return this; } /** + * Sets the Allowable Values for this Property. + * * @param values constrained set of values * @return the builder */ public Builder allowableValues(final String... values) { if (null != values) { - this.allowableValues = new ArrayList<>(); - for (final String value : values) { - allowableValues.add(new AllowableValue(value, value)); - } + this.allowableValues = Arrays.stream(values).map(AllowableValue::new).toList(); } return this; } /** - * Clears all Allowable Values from this Property + * Sets the Allowable Values for this Property. + *

+ * Uses the information provided by each {@link DescribedValue} (see {@link DescribedValue#getValue()}, {@link DescribedValue#getDisplayName()}, + * {@link DescribedValue#getDescription()}) to populate the {@link AllowableValue}s. * + * @param values constrained set of values * @return the builder */ - public Builder clearAllowableValues() { - this.allowableValues = null; + public Builder allowableValues(final DescribedValue... values) { + if (null != values) { + this.allowableValues = Arrays.stream(values).map(AllowableValue::fromDescribedValue).toList(); + } return this; } /** - * Sets the Allowable Values for this Property + * Clears all Allowable Values from this Property * - * @param values contrained set of values * @return the builder */ - public Builder allowableValues(final AllowableValue... values) { - if (null != values) { - this.allowableValues = Arrays.asList(values); - } + public Builder clearAllowableValues() { + this.allowableValues = null; return this; } @@ -498,7 +520,7 @@ public Builder clearValidators() { * Service that implements the given interface * * @param controllerServiceDefinition the interface that is implemented - * by the Controller Service + * by the Controller Service * @return the builder */ public Builder identifiesControllerService(final Class controllerServiceDefinition) { @@ -533,12 +555,12 @@ private boolean isValueAllowed(final String value) { * *

  • If the ResourceCardinality is MULTIPLE, the given property value may consist of one or more resources, each separted by a comma and optional white space.
  • * - * + *

    * Generally, any property descriptor that makes use of the {@link #dynamicallyModifiesClasspath(boolean)} method to dynamically update its classpath should also * make use of this method, specifying which types of resources are allowed and how many. * - * @param cardinality specifies how many resources the property should allow - * @param resourceType the type of resource that is allowed + * @param cardinality specifies how many resources the property should allow + * @param resourceType the type of resource that is allowed * @param additionalResourceTypes if more than one type of resource is allowed, any resource type in addition to the given resource type may be provided * @return the builder */ @@ -558,15 +580,15 @@ public Builder identifiesExternalResource(final ResourceCardinality cardinality, * Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a non-null value. * Furthermore, if one or more explicit Allowable Values are provided, this Property will not be relevant unless the given Property's value is equal to one of the given Allowable Values. * If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied. - * + *

    * In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given * Allowable Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for * validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component * will still be valid, because the value of this property is irrelevant. - * + *

    * If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid. * - * @param property the property that must be set in order for this property to become relevant + * @param property the property that must be set in order for this property to become relevant * @param dependentValues the possible values for the given property for which this Property is relevant * @return the builder */ @@ -593,16 +615,16 @@ public Builder dependsOn(final PropertyDescriptor property, final AllowableValue * Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a value equal to one of the given * String arguments. * If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied. - * + *

    * In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given * Allowable Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for * validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component * will still be valid, because the value of this property is irrelevant. - * + *

    * If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid. * - * @param property the property that must be set in order for this property to become relevant - * @param firstDependentValue the first value for the given property for which this Property is relevant + * @param property the property that must be set in order for this property to become relevant + * @param firstDependentValue the first value for the given property for which this Property is relevant * @param additionalDependentValues any other values for the given property for which this Property is relevant * @return the builder */ @@ -621,25 +643,25 @@ public Builder dependsOn(final PropertyDescriptor property, final String firstDe * Establishes a relationship between this Property and the given property by declaring that this Property is only relevant if the given Property has a value equal to one of the given * {@link DescribedValue} arguments. * If this method is called multiple times, each with a different dependency, then a relationship is established such that this Property is relevant only if all dependencies are satisfied. - * + *

    * In the case that this property is NOT considered to be relevant (meaning that it depends on a property whose value is not specified, or whose value does not match one of the given * Described Values), the property will not be shown in the component's configuration in the User Interface. Additionally, this property's value will not be considered for * validation. That is, if this property is configured with an invalid value and this property depends on Property Foo, and Property Foo does not have a value set, then the component * will still be valid, because the value of this property is irrelevant. - * + *

    * If the given property is not relevant (because its dependencies are not satisfied), this property is also considered not to be valid. * - * @param property the property that must be set in order for this property to become relevant - * @param firstDependentValue the first value for the given property for which this Property is relevant + * @param property the property that must be set in order for this property to become relevant + * @param firstDependentValue the first value for the given property for which this Property is relevant * @param additionalDependentValues any other values for the given property for which this Property is relevant * @return the builder */ public Builder dependsOn(final PropertyDescriptor property, final DescribedValue firstDependentValue, final DescribedValue... additionalDependentValues) { final AllowableValue[] dependentValues = new AllowableValue[additionalDependentValues.length + 1]; - dependentValues[0] = toAllowableValue(firstDependentValue); + dependentValues[0] = AllowableValue.fromDescribedValue(firstDependentValue); int i = 1; for (final DescribedValue additionalDependentValue : additionalDependentValues) { - dependentValues[i++] = toAllowableValue(additionalDependentValue); + dependentValues[i++] = AllowableValue.fromDescribedValue(additionalDependentValue); } return dependsOn(property, dependentValues); @@ -655,16 +677,11 @@ public Builder clearDependsOn() { return this; } - private AllowableValue toAllowableValue(DescribedValue describedValue) { - return new AllowableValue(describedValue.getValue(), describedValue.getDisplayName(), describedValue.getDescription()); - } - /** * @return a PropertyDescriptor as configured - * * @throws IllegalStateException if allowable values are configured but - * no default value is set, or the default value is not contained within - * the allowable values. + * no default value is set, or the default value is not contained within + * the allowable values. */ public PropertyDescriptor build() { if (name == null) { @@ -740,18 +757,14 @@ public ResourceDefinition getResourceDefinition() { @Override public boolean equals(final Object other) { - if (other == null) { - return false; - } - if (!(other instanceof PropertyDescriptor)) { - return false; - } if (this == other) { return true; } + if (other instanceof PropertyDescriptor otherPropertyDescriptor) { + return this.name.equals(otherPropertyDescriptor.name); + } - final PropertyDescriptor desc = (PropertyDescriptor) other; - return this.name.equals(desc.name); + return false; } @Override @@ -768,7 +781,7 @@ private static final class ConstrainedSetValidator implements Validator { private static final String POSITIVE_EXPLANATION = "Given value found in allowed set"; private static final String NEGATIVE_EXPLANATION = "Given value not found in allowed set '%1$s'"; - private static final String VALUE_DEMARCATOR = ", "; + private static final String VALUE_DELIMITER = ", "; private final String validStrings; private final Collection validValues; @@ -780,20 +793,8 @@ private static final class ConstrainedSetValidator implements Validator { * @throws NullPointerException if the given validValues is null */ private ConstrainedSetValidator(final Collection validValues) { - String validVals = ""; - if (!validValues.isEmpty()) { - final StringBuilder valuesBuilder = new StringBuilder(); - for (final AllowableValue value : validValues) { - valuesBuilder.append(value).append(VALUE_DEMARCATOR); - } - validVals = valuesBuilder.substring(0, valuesBuilder.length() - VALUE_DEMARCATOR.length()); - } - validStrings = validVals; - - this.validValues = new ArrayList<>(validValues.size()); - for (final AllowableValue value : validValues) { - this.validValues.add(value.getValue()); - } + this.validValues = validValues.stream().map(AllowableValue::getValue).toList(); + this.validStrings = String.join(VALUE_DELIMITER, this.validValues); } @Override @@ -824,13 +825,13 @@ public ResourceDefinitionValidator(final ResourceDefinition resourceDefinition, @Override public ValidationResult validate(final String subject, final String configuredInput, final ValidationContext context) { final ValidationResult.Builder resultBuilder = new ValidationResult.Builder() - .input(configuredInput) - .subject(subject); + .input(configuredInput) + .subject(subject); if (configuredInput == null) { return resultBuilder.valid(false) - .explanation("No value specified") - .build(); + .explanation("No value specified") + .build(); } // If Expression Language is supported and is used in the property value, we cannot perform validation against the configured @@ -843,8 +844,8 @@ public ValidationResult validate(final String subject, final String configuredIn resultBuilder.input(input); } else { return resultBuilder.valid(true) - .explanation("Expression Language is present, so validation of property value cannot be performed") - .build(); + .explanation("Expression Language is present, so validation of property value cannot be performed") + .build(); } } @@ -854,15 +855,15 @@ public ValidationResult validate(final String subject, final String configuredIn final boolean allowsText = resourceDefinition.getResourceTypes().contains(ResourceType.TEXT); if (allowsText) { return resultBuilder.valid(true) - .explanation("Property allows for Resource Type of Text, so validation of property value cannot be performed") - .build(); + .explanation("Property allows for Resource Type of Text, so validation of property value cannot be performed") + .build(); } final String[] splits = input.split(","); if (resourceDefinition.getCardinality() == ResourceCardinality.SINGLE && splits.length > 1) { return resultBuilder.valid(false) - .explanation("Property only supports a single Resource but " + splits.length + " resources were specified") - .build(); + .explanation("Property only supports a single Resource but " + splits.length + " resources were specified") + .build(); } final Set resourceTypes = resourceDefinition.getResourceTypes(); @@ -885,25 +886,25 @@ public ValidationResult validate(final String subject, final String configuredIn if (!resourceTypes.contains(resourceReference.getResourceType())) { return resultBuilder.valid(false) - .explanation("Specified Resource is a " + resourceReference.getResourceType().name() + " but this property does not allow this type of resource") - .build(); + .explanation("Specified Resource is a " + resourceReference.getResourceType().name() + " but this property does not allow this type of resource") + .build(); } } if (count == 0) { return resultBuilder.valid(false) - .explanation("No resources were specified") - .build(); + .explanation("No resources were specified") + .build(); } if (!nonExistentResources.isEmpty()) { return resultBuilder.valid(false) - .explanation("The specified resource(s) do not exist or could not be accessed: " + nonExistentResources) - .build(); + .explanation("The specified resource(s) do not exist or could not be accessed: " + nonExistentResources) + .build(); } return resultBuilder.valid(true) - .build(); + .build(); } } } diff --git a/nifi-api/src/main/java/org/apache/nifi/components/PropertyValue.java b/nifi-api/src/main/java/org/apache/nifi/components/PropertyValue.java index 096dd907acea5..4e52c54cb9b21 100644 --- a/nifi-api/src/main/java/org/apache/nifi/components/PropertyValue.java +++ b/nifi-api/src/main/java/org/apache/nifi/components/PropertyValue.java @@ -135,16 +135,18 @@ public interface PropertyValue { ResourceReferences asResources(); /** - * @param the generic type of the enum used as allowable values - * @param enumType the class of the enum used as allowable values - * @return the DescribedValue enum entry whose value is the raw value of the - * this, or null if the value is not set. - * Throws an IllegalArgumentException if none of the enum entries correspond to the specified raw value. + * Returns the property value as one of the configured allowableValues, see {@link PropertyDescriptor.Builder#allowableValues(Class)} + *

    + * The {@link Class#getEnumConstants()} of the provided enum are searched for an entry matching the value of this. + * In case an enum value is a {@link DescribedValue}, uses the defined {@link DescribedValue#getValue()} for comparison. + * Otherwise, the {@link Enum#name()} is used. * - * @throws IllegalArgumentException if the value of this - * does not point to any of the entries of the specified enum type. + * @param the generic type of the enum used as allowableValues + * @param enumType the class of the enum used as allowableValues + * @return the matching enum entry, or null if the value is not set. + * @throws IllegalArgumentException if no enum entry matching the value of this is found. */ - & DescribedValue> E asDescribedValue(Class enumType) throws IllegalArgumentException; + > E asAllowableValue(Class enumType) throws IllegalArgumentException; /** * @return true if the user has configured a value, or if the diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/BatchSize.java b/nifi-api/src/main/java/org/apache/nifi/flow/BatchSize.java index 305807a67cfa6..05ba824f6042a 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/BatchSize.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/BatchSize.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -26,7 +26,7 @@ public class BatchSize { private String size; private String duration; - @ApiModelProperty("Preferred number of flow files to include in a transaction.") + @Schema(description = "Preferred number of flow files to include in a transaction.") public Integer getCount() { return count; } @@ -35,7 +35,7 @@ public void setCount(Integer count) { this.count = count; } - @ApiModelProperty("Preferred number of bytes to include in a transaction.") + @Schema(description = "Preferred number of bytes to include in a transaction.") public String getSize() { return size; } @@ -44,7 +44,7 @@ public void setSize(String size) { this.size = size; } - @ApiModelProperty("Preferred amount of time that a transaction should span.") + @Schema(description = "Preferred amount of time that a transaction should span.") public String getDuration() { return duration; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/Bundle.java b/nifi-api/src/main/java/org/apache/nifi/flow/Bundle.java index 019b05255963e..ddfd5678d978c 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/Bundle.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/Bundle.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -35,7 +35,7 @@ public Bundle(final String group, final String artifact, final String version) { this.version = version; } - @ApiModelProperty("The group of the bundle") + @Schema(description = "The group of the bundle") public String getGroup() { return group; } @@ -44,7 +44,7 @@ public void setGroup(String group) { this.group = group; } - @ApiModelProperty("The artifact of the bundle") + @Schema(description = "The artifact of the bundle") public String getArtifact() { return artifact; } @@ -53,7 +53,7 @@ public void setArtifact(String artifact) { this.artifact = artifact; } - @ApiModelProperty("The version of the bundle") + @Schema(description = "The version of the bundle") public String getVersion() { return version; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/ConnectableComponent.java b/nifi-api/src/main/java/org/apache/nifi/flow/ConnectableComponent.java index 7926ed22660db..c4264db94e803 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/ConnectableComponent.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/ConnectableComponent.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -29,7 +29,7 @@ public class ConnectableComponent { private String name; private String comments; - @ApiModelProperty(value = "The id of the connectable component.", required = true) + @Schema(description = "The id of the connectable component.") public String getId() { return id; } @@ -38,7 +38,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The instance ID of an existing component that is described by this VersionedComponent, or null if this is not mapped to an instantiated component") + @Schema(description = "The instance ID of an existing component that is described by this VersionedComponent, or null if this is not mapped to an instantiated component") public String getInstanceIdentifier() { return instanceId; } @@ -47,7 +47,7 @@ public void setInstanceIdentifier(String instanceIdentifier) { this.instanceId = instanceIdentifier; } - @ApiModelProperty(value = "The type of component the connectable is.", required = true) + @Schema(description = "The type of component the connectable is.") public ConnectableComponentType getType() { return type; } @@ -56,7 +56,7 @@ public void setType(ConnectableComponentType type) { this.type = type; } - @ApiModelProperty(value = "The id of the group that the connectable component resides in", required = true) + @Schema(description = "The id of the group that the connectable component resides in") public String getGroupId() { return groupId; } @@ -65,7 +65,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty("The name of the connectable component") + @Schema(description = "The name of the connectable component") public String getName() { return name; } @@ -74,7 +74,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The comments for the connectable component.") + @Schema(description = "The comments for the connectable component.") public String getComments() { return comments; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/ControllerServiceAPI.java b/nifi-api/src/main/java/org/apache/nifi/flow/ControllerServiceAPI.java index ab7648f6be3d0..ab28fc353ba02 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/ControllerServiceAPI.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/ControllerServiceAPI.java @@ -19,13 +19,13 @@ import java.util.Objects; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class ControllerServiceAPI { private String type; private Bundle bundle; - @ApiModelProperty("The fully qualified name of the service interface.") + @Schema(description = "The fully qualified name of the service interface.") public String getType() { return type; } @@ -34,7 +34,7 @@ public void setType(String type) { this.type = type; } - @ApiModelProperty("The details of the artifact that bundled this service interface.") + @Schema(description = "The details of the artifact that bundled this service interface.") public Bundle getBundle() { return bundle; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/ExternalControllerServiceReference.java b/nifi-api/src/main/java/org/apache/nifi/flow/ExternalControllerServiceReference.java index 2e7ba92fbcba4..f7d023e989bc1 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/ExternalControllerServiceReference.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/ExternalControllerServiceReference.java @@ -16,16 +16,15 @@ */ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; -@ApiModel +@Schema public class ExternalControllerServiceReference { private String identifier; private String name; - @ApiModelProperty("The identifier of the controller service") + @Schema(description = "The identifier of the controller service") public String getIdentifier() { return identifier; } @@ -34,7 +33,7 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } - @ApiModelProperty("The name of the controller service") + @Schema(description = "The name of the controller service") public String getName() { return name; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/ParameterProviderReference.java b/nifi-api/src/main/java/org/apache/nifi/flow/ParameterProviderReference.java index 93e7041dd8055..e8c82561753c0 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/ParameterProviderReference.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/ParameterProviderReference.java @@ -16,10 +16,9 @@ */ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; -@ApiModel +@Schema public class ParameterProviderReference { private String identifier; @@ -27,7 +26,7 @@ public class ParameterProviderReference { private String type; private Bundle bundle; - @ApiModelProperty("The fully qualified name of the parameter provider class.") + @Schema(description = "The fully qualified name of the parameter provider class.") public String getType() { return type; } @@ -36,7 +35,7 @@ public void setType(final String type) { this.type = type; } - @ApiModelProperty("The details of the artifact that bundled this parameter provider.") + @Schema(description = "The details of the artifact that bundled this parameter provider.") public Bundle getBundle() { return bundle; } @@ -45,7 +44,7 @@ public void setBundle(final Bundle bundle) { this.bundle = bundle; } - @ApiModelProperty("The identifier of the parameter provider") + @Schema(description = "The identifier of the parameter provider") public String getIdentifier() { return identifier; } @@ -54,7 +53,7 @@ public void setIdentifier(final String identifier) { this.identifier = identifier; } - @ApiModelProperty("The name of the parameter provider") + @Schema(description = "The name of the parameter provider") public String getName() { return name; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/Position.java b/nifi-api/src/main/java/org/apache/nifi/flow/Position.java index f7c1c272a4b3a..d9a1e5a3c719e 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/Position.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/Position.java @@ -17,12 +17,11 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; -@ApiModel(description = "The position of a component on the graph") +@Schema(description = "The position of a component on the graph") public class Position { private double x; private double y; @@ -35,7 +34,7 @@ public Position(double x, double y) { this.y = y; } - @ApiModelProperty("The x coordinate.") + @Schema(description = "The x coordinate.") public double getX() { return x; } @@ -44,7 +43,7 @@ public void setX(double x) { this.x = x; } - @ApiModelProperty("The y coordinate.") + @Schema(description = "The y coordinate.") public double getY() { return y; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedComponent.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedComponent.java index 639d6fb3bbd8a..d645069433f75 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedComponent.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedComponent.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -31,7 +31,7 @@ public abstract class VersionedComponent { private String comments; private Position position; - @ApiModelProperty("The component's unique identifier") + @Schema(description = "The component's unique identifier") public String getIdentifier() { return identifier; } @@ -40,7 +40,7 @@ public void setIdentifier(String identifier) { this.identifier = identifier; } - @ApiModelProperty("The instance ID of an existing component that is described by this VersionedComponent, or null if this is not mapped to an instantiated component") + @Schema(description = "The instance ID of an existing component that is described by this VersionedComponent, or null if this is not mapped to an instantiated component") public String getInstanceIdentifier() { return instanceIdentifier; } @@ -49,7 +49,7 @@ public void setInstanceIdentifier(String instanceIdentifier) { this.instanceIdentifier = instanceIdentifier; } - @ApiModelProperty("The ID of the Process Group that this component belongs to") + @Schema(description = "The ID of the Process Group that this component belongs to") public String getGroupIdentifier() { return groupId; } @@ -58,7 +58,7 @@ public void setGroupIdentifier(String groupId) { this.groupId = groupId; } - @ApiModelProperty("The component's name") + @Schema(description = "The component's name") public String getName() { return name; } @@ -67,7 +67,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The component's position on the graph") + @Schema(description = "The component's position on the graph") public Position getPosition() { return position; } @@ -76,7 +76,7 @@ public void setPosition(Position position) { this.position = position; } - @ApiModelProperty("The user-supplied comments for the component") + @Schema(description = "The user-supplied comments for the component") public String getComments() { return comments; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConfigurableExtension.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConfigurableExtension.java index 5e3b5076d8286..d21059d5216f2 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConfigurableExtension.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConfigurableExtension.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Map; @@ -30,7 +30,7 @@ public abstract class VersionedConfigurableExtension extends VersionedComponent private Map propertyDescriptors; @Override - @ApiModelProperty("The type of the extension component") + @Schema(description = "The type of the extension component") public String getType() { return type; } @@ -41,7 +41,7 @@ public void setType(final String type) { } @Override - @ApiModelProperty("Information about the bundle from which the component came") + @Schema(description = "Information about the bundle from which the component came") public Bundle getBundle() { return bundle; } @@ -53,7 +53,7 @@ public void setBundle(Bundle bundle) { @Override - @ApiModelProperty("The properties for the component. Properties whose value is not set will only contain the property name.") + @Schema(description = "The properties for the component. Properties whose value is not set will only contain the property name.") public Map getProperties() { return properties; } @@ -64,7 +64,7 @@ public void setProperties(Map properties) { } @Override - @ApiModelProperty("The property descriptors for the component.") + @Schema(description = "The property descriptors for the component.") public Map getPropertyDescriptors() { return propertyDescriptors; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConnection.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConnection.java index 44725b8475e81..c8e36df7b52f2 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConnection.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedConnection.java @@ -20,7 +20,7 @@ import java.util.List; import java.util.Set; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class VersionedConnection extends VersionedComponent { private ConnectableComponent source; @@ -39,8 +39,7 @@ public class VersionedConnection extends VersionedComponent { private String partitioningAttribute; private String loadBalanceCompression; - - @ApiModelProperty("The source of the connection.") + @Schema(description = "The source of the connection.") public ConnectableComponent getSource() { return source; } @@ -49,7 +48,7 @@ public void setSource(ConnectableComponent source) { this.source = source; } - @ApiModelProperty("The destination of the connection.") + @Schema(description = "The destination of the connection.") public ConnectableComponent getDestination() { return destination; } @@ -58,7 +57,7 @@ public void setDestination(ConnectableComponent destination) { this.destination = destination; } - @ApiModelProperty("The bend points on the connection.") + @Schema(description = "The bend points on the connection.") public List getBends() { return bends; } @@ -67,7 +66,7 @@ public void setBends(List bends) { this.bends = bends; } - @ApiModelProperty("The index of the bend point where to place the connection label.") + @Schema(description = "The index of the bend point where to place the connection label.") public Integer getLabelIndex() { return labelIndex; } @@ -76,8 +75,8 @@ public void setLabelIndex(Integer labelIndex) { this.labelIndex = labelIndex; } - @ApiModelProperty( - value = "The z index of the connection.", + @Schema( + description = "The z index of the connection.", name = "zIndex") // Jackson maps this method name to JSON key "zIndex", but Swagger does not by default public Long getzIndex() { return zIndex; @@ -87,7 +86,7 @@ public void setzIndex(Long zIndex) { this.zIndex = zIndex; } - @ApiModelProperty("The selected relationship that comprise the connection.") + @Schema(description = "The selected relationship that comprise the connection.") public Set getSelectedRelationships() { return selectedRelationships; } @@ -96,8 +95,7 @@ public void setSelectedRelationships(Set relationships) { this.selectedRelationships = relationships; } - - @ApiModelProperty("The object count threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing files " + @Schema(description = "The object count threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing files " + "over the limit are affected but it does help feeder processors to stop pushing too much into this work queue.") public Long getBackPressureObjectThreshold() { return backPressureObjectThreshold; @@ -107,8 +105,7 @@ public void setBackPressureObjectThreshold(Long backPressureObjectThreshold) { this.backPressureObjectThreshold = backPressureObjectThreshold; } - - @ApiModelProperty("The object data size threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing " + @Schema(description = "The object data size threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing " + "files over the limit are affected but it does help feeder processors to stop pushing too much into this work queue.") public String getBackPressureDataSizeThreshold() { return backPressureDataSizeThreshold; @@ -119,7 +116,7 @@ public void setBackPressureDataSizeThreshold(String backPressureDataSizeThreshol } - @ApiModelProperty("The amount of time a flow file may be in the flow before it will be automatically aged out of the flow. Once a flow file reaches this age it will be terminated from " + @Schema(description = "The amount of time a flow file may be in the flow before it will be automatically aged out of the flow. Once a flow file reaches this age it will be terminated from " + "the flow the next time a processor attempts to start work on it.") public String getFlowFileExpiration() { return flowFileExpiration; @@ -130,7 +127,7 @@ public void setFlowFileExpiration(String flowFileExpiration) { } - @ApiModelProperty("The comparators used to prioritize the queue.") + @Schema(description = "The comparators used to prioritize the queue.") public List getPrioritizers() { return prioritizers; } @@ -139,7 +136,7 @@ public void setPrioritizers(List prioritizers) { this.prioritizers = prioritizers; } - @ApiModelProperty(value = "The Strategy to use for load balancing data across the cluster, or null, if no Load Balance Strategy has been specified.", + @Schema(description = "The Strategy to use for load balancing data across the cluster, or null, if no Load Balance Strategy has been specified.", allowableValues = "DO_NOT_LOAD_BALANCE, PARTITION_BY_ATTRIBUTE, ROUND_ROBIN, SINGLE_NODE") public String getLoadBalanceStrategy() { return loadBalanceStrategy; @@ -149,7 +146,7 @@ public void setLoadBalanceStrategy(String loadBalanceStrategy) { this.loadBalanceStrategy = loadBalanceStrategy; } - @ApiModelProperty("The attribute to use for partitioning data as it is load balanced across the cluster. If the Load Balance Strategy is configured to use PARTITION_BY_ATTRIBUTE, the value " + + @Schema(description = "The attribute to use for partitioning data as it is load balanced across the cluster. If the Load Balance Strategy is configured to use PARTITION_BY_ATTRIBUTE, the value " + "returned by this method is the name of the FlowFile Attribute that will be used to determine which node in the cluster should receive a given FlowFile. If the Load Balance Strategy is " + "unset or is set to any other value, the Partitioning Attribute has no effect.") public String getPartitioningAttribute() { @@ -160,7 +157,7 @@ public void setPartitioningAttribute(final String partitioningAttribute) { this.partitioningAttribute = partitioningAttribute; } - @ApiModelProperty(value = "Whether or not compression should be used when transferring FlowFiles between nodes", + @Schema(description = "Whether or not compression should be used when transferring FlowFiles between nodes", allowableValues = "DO_NOT_COMPRESS, COMPRESS_ATTRIBUTES_ONLY, COMPRESS_ATTRIBUTES_AND_CONTENT") public String getLoadBalanceCompression() { return loadBalanceCompression; diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedControllerService.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedControllerService.java index 67f01080ddf0d..25b857ba95559 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedControllerService.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedControllerService.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; @@ -29,7 +29,7 @@ public class VersionedControllerService extends VersionedConfigurableExtension { private ScheduledState scheduledState; private String bulletinLevel; - @ApiModelProperty(value = "Lists the APIs this Controller Service implements.") + @Schema(description = "Lists the APIs this Controller Service implements.") public List getControllerServiceApis() { return controllerServiceApis; } @@ -38,7 +38,7 @@ public void setControllerServiceApis(List controllerServic this.controllerServiceApis = controllerServiceApis; } - @ApiModelProperty(value = "The annotation for the controller service. This is how the custom UI relays configuration to the controller service.") + @Schema(description = "The annotation for the controller service. This is how the custom UI relays configuration to the controller service.") public String getAnnotationData() { return annotationData; } @@ -52,7 +52,7 @@ public ComponentType getComponentType() { return ComponentType.CONTROLLER_SERVICE; } - @ApiModelProperty("The ScheduledState denoting whether the Controller Service is ENABLED or DISABLED") + @Schema(description = "The ScheduledState denoting whether the Controller Service is ENABLED or DISABLED") public ScheduledState getScheduledState() { return scheduledState; } @@ -61,7 +61,7 @@ public void setScheduledState(final ScheduledState scheduledState) { this.scheduledState = scheduledState; } - @ApiModelProperty("The level at which the controller service will report bulletins.") + @Schema(description = "The level at which the controller service will report bulletins.") public String getBulletinLevel() { return bulletinLevel; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowAnalysisRule.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowAnalysisRule.java index 233fd4adb043e..0d5abd829b369 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowAnalysisRule.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowAnalysisRule.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.flowanalysis.EnforcementPolicy; public class VersionedFlowAnalysisRule extends VersionedConfigurableExtension { @@ -25,7 +25,7 @@ public class VersionedFlowAnalysisRule extends VersionedConfigurableExtension { private ScheduledState scheduledState; private EnforcementPolicy enforcementPolicy; - @ApiModelProperty("How to handle violations.") + @Schema(description = "How to handle violations.") public EnforcementPolicy getEnforcementPolicy() { return enforcementPolicy; } @@ -39,7 +39,7 @@ public ComponentType getComponentType() { return ComponentType.FLOW_ANALYSIS_RULE; } - @ApiModelProperty("Indicates the scheduled state for the flow analysis rule") + @Schema(description = "Indicates the scheduled state for the flow analysis rule") public ScheduledState getScheduledState() { return scheduledState; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowCoordinates.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowCoordinates.java index 3d5fb2e47cda4..125982297c0ec 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowCoordinates.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowCoordinates.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -29,7 +29,7 @@ public class VersionedFlowCoordinates { private int version; private Boolean latest; - @ApiModelProperty("The identifier of the Flow Registry that contains the flow") + @Schema(description = "The identifier of the Flow Registry that contains the flow") public String getRegistryId() { return registryId; } @@ -38,7 +38,7 @@ public void setRegistryId(String registryId) { this.registryId = registryId; } - @ApiModelProperty("The location of the Flow Registry that stores the flow") + @Schema(description = "The location of the Flow Registry that stores the flow") public String getStorageLocation() { return storageLocation; } @@ -47,7 +47,7 @@ public void setStorageLocation(String storageLocation) { this.storageLocation = storageLocation; } - @ApiModelProperty("The UUID of the bucket that the flow resides in") + @Schema(description = "The UUID of the bucket that the flow resides in") public String getBucketId() { return bucketId; } @@ -56,7 +56,7 @@ public void setBucketId(String bucketId) { this.bucketId = bucketId; } - @ApiModelProperty("The UUID of the flow") + @Schema(description = "The UUID of the flow") public String getFlowId() { return flowId; } @@ -65,7 +65,7 @@ public void setFlowId(String flowId) { this.flowId = flowId; } - @ApiModelProperty("The version of the flow") + @Schema(description = "The version of the flow") public int getVersion() { return version; } @@ -74,7 +74,7 @@ public void setVersion(int version) { this.version = version; } - @ApiModelProperty("Whether or not these coordinates point to the latest version of the flow") + @Schema(description = "Whether or not these coordinates point to the latest version of the flow") public Boolean getLatest() { return latest; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowRegistryClient.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowRegistryClient.java index b0212bd0e76fd..3b4c9eb5a0c66 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowRegistryClient.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedFlowRegistryClient.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class VersionedFlowRegistryClient extends VersionedConfigurableExtension { private String description; @@ -28,7 +28,7 @@ public ComponentType getComponentType() { return ComponentType.FLOW_REGISTRY_CLIENT; } - @ApiModelProperty("The description of the registry") + @Schema(description = "The description of the registry") public String getDescription() { return description; } @@ -37,7 +37,7 @@ public void setDescription(final String description) { this.description = description; } - @ApiModelProperty(value = "The annotation for the reporting task. This is how the custom UI relays configuration to the reporting task.") + @Schema(description = "The annotation for the reporting task. This is how the custom UI relays configuration to the reporting task.") public String getAnnotationData() { return annotationData; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedLabel.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedLabel.java index 002030925158a..d0e8e2448600c 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedLabel.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedLabel.java @@ -19,7 +19,7 @@ import java.util.Map; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class VersionedLabel extends VersionedComponent { private String label; @@ -31,7 +31,7 @@ public class VersionedLabel extends VersionedComponent { private Map style; - @ApiModelProperty("The text that appears in the label.") + @Schema(description = "The text that appears in the label.") public String getLabel() { return label; } @@ -40,7 +40,7 @@ public void setLabel(final String label) { this.label = label; } - @ApiModelProperty("The styles for this label (font-size : 12px, background-color : #eee, etc).") + @Schema(description = "The styles for this label (font-size : 12px, background-color : #eee, etc).") public Map getStyle() { return style; } @@ -49,7 +49,7 @@ public void setStyle(final Map style) { this.style = style; } - @ApiModelProperty("The height of the label in pixels when at a 1:1 scale.") + @Schema(description = "The height of the label in pixels when at a 1:1 scale.") public Double getHeight() { return height; } @@ -58,7 +58,7 @@ public void setHeight(Double height) { this.height = height; } - @ApiModelProperty("The width of the label in pixels when at a 1:1 scale.") + @Schema(description = "The width of the label in pixels when at a 1:1 scale.") public Double getWidth() { return width; } @@ -67,8 +67,8 @@ public void setWidth(Double width) { this.width = width; } - @ApiModelProperty( - value = "The z index of the connection.", + @Schema( + description = "The z index of the connection.", name = "zIndex") // Jackson maps this method name to JSON key "zIndex", but Swagger does not by default public Long getzIndex() { return zIndex; diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameter.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameter.java index 9f71a7e21b08a..987e23ad4d3d9 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameter.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameter.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -28,7 +28,7 @@ public class VersionedParameter { private boolean provided; private String value; - @ApiModelProperty("The name of the parameter") + @Schema(description = "The name of the parameter") public String getName() { return name; } @@ -37,7 +37,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The description of the param") + @Schema(description = "The description of the param") public String getDescription() { return description; } @@ -46,7 +46,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty("Whether or not the parameter value is sensitive") + @Schema(description = "Whether or not the parameter value is sensitive") public boolean isSensitive() { return sensitive; } @@ -55,7 +55,7 @@ public void setSensitive(boolean sensitive) { this.sensitive = sensitive; } - @ApiModelProperty("Whether or not the parameter value is provided by a ParameterProvider") + @Schema(description = "Whether or not the parameter value is provided by a ParameterProvider") public boolean isProvided() { return provided; } @@ -64,7 +64,7 @@ public void setProvided(boolean provided) { this.provided = provided; } - @ApiModelProperty("The value of the parameter") + @Schema(description = "The value of the parameter") public String getValue() { return value; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterContext.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterContext.java index e7bcfc1fe344f..717ccbdcc2092 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterContext.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterContext.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; import java.util.Set; @@ -29,7 +29,7 @@ public class VersionedParameterContext extends VersionedComponent { private String parameterGroupName; private Boolean isSynchronized; - @ApiModelProperty("The description of the parameter context") + @Schema(description = "The description of the parameter context") public String getDescription() { return description; } @@ -38,7 +38,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty("The parameters in the context") + @Schema(description = "The parameters in the context") public Set getParameters() { return parameters; } @@ -47,7 +47,7 @@ public void setParameters(Set parameters) { this.parameters = parameters; } - @ApiModelProperty("The names of additional parameter contexts from which to inherit parameters") + @Schema(description = "The names of additional parameter contexts from which to inherit parameters") public List getInheritedParameterContexts() { return inheritedParameterContexts; } @@ -61,7 +61,7 @@ public ComponentType getComponentType() { return ComponentType.PARAMETER_CONTEXT; } - @ApiModelProperty("The identifier of an optional parameter provider") + @Schema(description = "The identifier of an optional parameter provider") public String getParameterProvider() { return parameterProvider; } @@ -70,7 +70,7 @@ public void setParameterProvider(String parameterProvider) { this.parameterProvider = parameterProvider; } - @ApiModelProperty("The corresponding parameter group name fetched from the parameter provider, if applicable") + @Schema(description = "The corresponding parameter group name fetched from the parameter provider, if applicable") public String getParameterGroupName() { return parameterGroupName; } @@ -79,7 +79,7 @@ public void setParameterGroupName(String parameterGroupName) { this.parameterGroupName = parameterGroupName; } - @ApiModelProperty("True if the parameter provider is set and the context should receive updates when its parameters are next fetched") + @Schema(description = "True if the parameter provider is set and the context should receive updates when its parameters are next fetched") public Boolean isSynchronized() { return isSynchronized; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterProvider.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterProvider.java index b37d5e04a37a2..576b1d0ddb356 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterProvider.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedParameterProvider.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Map; @@ -30,7 +30,7 @@ public class VersionedParameterProvider extends VersionedComponent implements Ve @Override - @ApiModelProperty(value = "The type of the parameter provider.") + @Schema(description = "The type of the parameter provider.") public String getType() { return type; } @@ -41,7 +41,7 @@ public void setType(final String type) { } @Override - @ApiModelProperty(value = "The details of the artifact that bundled this parameter provider type.") + @Schema(description = "The details of the artifact that bundled this parameter provider type.") public Bundle getBundle() { return bundle; } @@ -52,7 +52,7 @@ public void setBundle(Bundle bundle) { } @Override - @ApiModelProperty(value = "The properties of the parameter provider.") + @Schema(description = "The properties of the parameter provider.") public Map getProperties() { return properties; } @@ -63,7 +63,7 @@ public void setProperties(Map properties) { } @Override - @ApiModelProperty("The property descriptors for the parameter provider.") + @Schema(description = "The property descriptors for the parameter provider.") public Map getPropertyDescriptors() { return propertyDescriptors; } @@ -73,7 +73,7 @@ public void setPropertyDescriptors(Map prop this.propertyDescriptors = propertyDescriptors; } - @ApiModelProperty(value = "The annotation for the parameter provider. This is how the custom UI relays configuration to the parameter provider.") + @Schema(description = "The annotation for the parameter provider. This is how the custom UI relays configuration to the parameter provider.") public String getAnnotationData() { return annotationData; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPort.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPort.java index 6f62d159cd408..a5f40b208607d 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPort.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPort.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.components.PortFunction; public class VersionedPort extends VersionedComponent { @@ -27,7 +27,7 @@ public class VersionedPort extends VersionedComponent { private Boolean allowRemoteAccess; private PortFunction portFunction; - @ApiModelProperty("The number of tasks that should be concurrently scheduled for the port.") + @Schema(description = "The number of tasks that should be concurrently scheduled for the port.") public Integer getConcurrentlySchedulableTaskCount() { return concurrentlySchedulableTaskCount; } @@ -36,7 +36,7 @@ public void setConcurrentlySchedulableTaskCount(Integer concurrentlySchedulableT this.concurrentlySchedulableTaskCount = concurrentlySchedulableTaskCount; } - @ApiModelProperty("The type of port.") + @Schema(description = "The type of port.") public PortType getType() { return type; } @@ -45,7 +45,7 @@ public void setType(PortType type) { this.type = type; } - @ApiModelProperty("The scheduled state of the component") + @Schema(description = "The scheduled state of the component") public ScheduledState getScheduledState() { return scheduledState; } @@ -54,7 +54,7 @@ public void setScheduledState(ScheduledState scheduledState) { this.scheduledState = scheduledState; } - @ApiModelProperty("Whether or not this port allows remote access for site-to-site") + @Schema(description = "Whether or not this port allows remote access for site-to-site") public Boolean isAllowRemoteAccess() { return ((allowRemoteAccess != null) && allowRemoteAccess); } @@ -67,7 +67,7 @@ public void setAllowRemoteAccess(Boolean allowRemoteAccess) { this.allowRemoteAccess = allowRemoteAccess; } - @ApiModelProperty("Specifies how the Port should function") + @Schema(description = "Specifies how the Port should function") public PortFunction getPortFunction() { return portFunction; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessGroup.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessGroup.java index 00980aff47195..e63c59b9e6f31 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessGroup.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessGroup.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.HashSet; import java.util.Set; @@ -50,7 +50,7 @@ public class VersionedProcessGroup extends VersionedComponent { private String logFileSuffix; - @ApiModelProperty("The child Process Groups") + @Schema(description = "The child Process Groups") public Set getProcessGroups() { return processGroups; } @@ -59,7 +59,7 @@ public void setProcessGroups(Set processGroups) { this.processGroups = new HashSet<>(processGroups); } - @ApiModelProperty("The Remote Process Groups") + @Schema(description = "The Remote Process Groups") public Set getRemoteProcessGroups() { return remoteProcessGroups; } @@ -68,7 +68,7 @@ public void setRemoteProcessGroups(Set remoteProces this.remoteProcessGroups = new HashSet<>(remoteProcessGroups); } - @ApiModelProperty("The Processors") + @Schema(description = "The Processors") public Set getProcessors() { return processors; } @@ -77,7 +77,7 @@ public void setProcessors(Set processors) { this.processors = new HashSet<>(processors); } - @ApiModelProperty("The Input Ports") + @Schema(description = "The Input Ports") public Set getInputPorts() { return inputPorts; } @@ -86,7 +86,7 @@ public void setInputPorts(Set inputPorts) { this.inputPorts = new HashSet<>(inputPorts); } - @ApiModelProperty("The Output Ports") + @Schema(description = "The Output Ports") public Set getOutputPorts() { return outputPorts; } @@ -95,7 +95,7 @@ public void setOutputPorts(Set outputPorts) { this.outputPorts = new HashSet<>(outputPorts); } - @ApiModelProperty("The Connections") + @Schema(description = "The Connections") public Set getConnections() { return connections; } @@ -104,7 +104,7 @@ public void setConnections(Set connections) { this.connections = new HashSet<>(connections); } - @ApiModelProperty("The Labels") + @Schema(description = "The Labels") public Set getLabels() { return labels; } @@ -113,7 +113,7 @@ public void setLabels(Set labels) { this.labels = new HashSet<>(labels); } - @ApiModelProperty("The Funnels") + @Schema(description = "The Funnels") public Set getFunnels() { return funnels; } @@ -122,7 +122,7 @@ public void setFunnels(Set funnels) { this.funnels = new HashSet<>(funnels); } - @ApiModelProperty("The Controller Services") + @Schema(description = "The Controller Services") public Set getControllerServices() { return controllerServices; } @@ -140,12 +140,12 @@ public void setVersionedFlowCoordinates(VersionedFlowCoordinates flowCoordinates this.versionedFlowCoordinates = flowCoordinates; } - @ApiModelProperty("The coordinates where the remote flow is stored, or null if the Process Group is not directly under Version Control") + @Schema(description = "The coordinates where the remote flow is stored, or null if the Process Group is not directly under Version Control") public VersionedFlowCoordinates getVersionedFlowCoordinates() { return versionedFlowCoordinates; } - @ApiModelProperty("The name of the parameter context used by this process group") + @Schema(description = "The name of the parameter context used by this process group") public String getParameterContextName() { return parameterContextName; } @@ -154,7 +154,7 @@ public void setParameterContextName(String parameterContextName) { this.parameterContextName = parameterContextName; } - @ApiModelProperty(value = "The configured FlowFile Concurrency for the Process Group") + @Schema(description = "The configured FlowFile Concurrency for the Process Group") public String getFlowFileConcurrency() { return flowfileConcurrency; } @@ -163,7 +163,7 @@ public void setFlowFileConcurrency(final String flowfileConcurrency) { this.flowfileConcurrency = flowfileConcurrency; } - @ApiModelProperty(value = "The FlowFile Outbound Policy for the Process Group") + @Schema(description = "The FlowFile Outbound Policy for the Process Group") public String getFlowFileOutboundPolicy() { return flowfileOutboundPolicy; } @@ -172,7 +172,7 @@ public void setFlowFileOutboundPolicy(final String outboundPolicy) { this.flowfileOutboundPolicy = outboundPolicy; } - @ApiModelProperty(value = "The default FlowFile Expiration for this Process Group.") + @Schema(description = "The default FlowFile Expiration for this Process Group.") public String getDefaultFlowFileExpiration() { return defaultFlowFileExpiration; } @@ -181,7 +181,7 @@ public void setDefaultFlowFileExpiration(String defaultFlowFileExpiration) { this.defaultFlowFileExpiration = defaultFlowFileExpiration; } - @ApiModelProperty(value = "Default value used in this Process Group for the maximum number of objects that can be queued before back pressure is applied.") + @Schema(description = "Default value used in this Process Group for the maximum number of objects that can be queued before back pressure is applied.") public Long getDefaultBackPressureObjectThreshold() { return defaultBackPressureObjectThreshold; } @@ -190,7 +190,7 @@ public void setDefaultBackPressureObjectThreshold(final Long defaultBackPressure this.defaultBackPressureObjectThreshold = defaultBackPressureObjectThreshold; } - @ApiModelProperty(value = "Default value used in this Process Group for the maximum data size of objects that can be queued before back pressure is applied.") + @Schema(description = "Default value used in this Process Group for the maximum data size of objects that can be queued before back pressure is applied.") public String getDefaultBackPressureDataSizeThreshold() { return defaultBackPressureDataSizeThreshold; } @@ -199,7 +199,7 @@ public void setDefaultBackPressureDataSizeThreshold(final String defaultBackPres this.defaultBackPressureDataSizeThreshold = defaultBackPressureDataSizeThreshold; } - @ApiModelProperty(value = "The log file suffix for this Process Group for dedicated logging.") + @Schema(description = "The log file suffix for this Process Group for dedicated logging.") public String getLogFileSuffix() { return logFileSuffix; } @@ -208,7 +208,7 @@ public void setLogFileSuffix(final String logFileSuffix) { this.logFileSuffix = logFileSuffix; } - @ApiModelProperty("The Scheduled State of the Process Group, if the group is configured to use the Stateless Execution Engine. Otherwise, this value has no relevance.") + @Schema(description = "The Scheduled State of the Process Group, if the group is configured to use the Stateless Execution Engine. Otherwise, this value has no relevance.") public ScheduledState getScheduledState() { return scheduledState; } @@ -217,7 +217,7 @@ public void setScheduledState(final ScheduledState scheduledState) { this.scheduledState = scheduledState; } - @ApiModelProperty("The Execution Engine that should be used to run the components within the group.") + @Schema(description = "The Execution Engine that should be used to run the components within the group.") public ExecutionEngine getExecutionEngine() { return executionEngine; } @@ -226,7 +226,7 @@ public void setExecutionEngine(final ExecutionEngine executionEngine) { this.executionEngine = executionEngine; } - @ApiModelProperty("The maximum number of concurrent tasks that should be scheduled for this Process Group when using the Stateless Engine") + @Schema(description = "The maximum number of concurrent tasks that should be scheduled for this Process Group when using the Stateless Engine") public Integer getMaxConcurrentTasks() { return maxConcurrentTasks; } @@ -235,7 +235,7 @@ public void setMaxConcurrentTasks(final Integer maxConcurrentTasks) { this.maxConcurrentTasks = maxConcurrentTasks; } - @ApiModelProperty("The maximum amount of time that the flow is allows to run using the Stateless engine before it times out and is considered a failure") + @Schema(description = "The maximum amount of time that the flow is allows to run using the Stateless engine before it times out and is considered a failure") public String getStatelessFlowTimeout() { return statelessFlowTimeout; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessor.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessor.java index f716a9a2946de..266c6e9b97cf5 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessor.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedProcessor.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Map; import java.util.Set; @@ -43,7 +43,7 @@ public class VersionedProcessor extends VersionedConfigurableExtension { private String backoffMechanism; private String maxBackoffPeriod; - @ApiModelProperty("The frequency with which to schedule the processor. The format of the value will depend on th value of schedulingStrategy.") + @Schema(description = "The frequency with which to schedule the processor. The format of the value will depend on th value of schedulingStrategy.") public String getSchedulingPeriod() { return schedulingPeriod; } @@ -52,7 +52,7 @@ public void setSchedulingPeriod(String setSchedulingPeriod) { this.schedulingPeriod = setSchedulingPeriod; } - @ApiModelProperty("Indicates how the processor should be scheduled to run.") + @Schema(description = "Indicates how the processor should be scheduled to run.") public String getSchedulingStrategy() { return schedulingStrategy; } @@ -61,7 +61,7 @@ public void setSchedulingStrategy(String schedulingStrategy) { this.schedulingStrategy = schedulingStrategy; } - @ApiModelProperty("Indicates the node where the process will execute.") + @Schema(description = "Indicates the node where the process will execute.") public String getExecutionNode() { return executionNode; } @@ -70,7 +70,7 @@ public void setExecutionNode(String executionNode) { this.executionNode = executionNode; } - @ApiModelProperty("The amout of time that is used when the process penalizes a flowfile.") + @Schema(description = "The amout of time that is used when the process penalizes a flowfile.") public String getPenaltyDuration() { return penaltyDuration; } @@ -79,7 +79,7 @@ public void setPenaltyDuration(String penaltyDuration) { this.penaltyDuration = penaltyDuration; } - @ApiModelProperty("The amount of time that must elapse before this processor is scheduled again after yielding.") + @Schema(description = "The amount of time that must elapse before this processor is scheduled again after yielding.") public String getYieldDuration() { return yieldDuration; } @@ -88,7 +88,7 @@ public void setYieldDuration(String yieldDuration) { this.yieldDuration = yieldDuration; } - @ApiModelProperty("The level at which the processor will report bulletins.") + @Schema(description = "The level at which the processor will report bulletins.") public String getBulletinLevel() { return bulletinLevel; } @@ -97,7 +97,7 @@ public void setBulletinLevel(String bulletinLevel) { this.bulletinLevel = bulletinLevel; } - @ApiModelProperty("The number of tasks that should be concurrently schedule for the processor. If the processor doesn't allow parallol processing then any positive input will be ignored.") + @Schema(description = "The number of tasks that should be concurrently schedule for the processor. If the processor doesn't allow parallol processing then any positive input will be ignored.") public Integer getConcurrentlySchedulableTaskCount() { return concurrentlySchedulableTaskCount; } @@ -106,7 +106,7 @@ public void setConcurrentlySchedulableTaskCount(Integer concurrentlySchedulableT this.concurrentlySchedulableTaskCount = concurrentlySchedulableTaskCount; } - @ApiModelProperty("The annotation data for the processor used to relay configuration between a custom UI and the procesosr.") + @Schema(description = "The annotation data for the processor used to relay configuration between a custom UI and the procesosr.") public String getAnnotationData() { return annotationData; } @@ -116,7 +116,7 @@ public void setAnnotationData(String annotationData) { } - @ApiModelProperty("The names of all relationships that cause a flow file to be terminated if the relationship is not connected elsewhere. This property differs " + @Schema(description = "The names of all relationships that cause a flow file to be terminated if the relationship is not connected elsewhere. This property differs " + "from the 'isAutoTerminate' property of the RelationshipDTO in that the RelationshipDTO is meant to depict the current configuration, whereas this " + "property can be set in a DTO when updating a Processor in order to change which Relationships should be auto-terminated.") public Set getAutoTerminatedRelationships() { @@ -127,7 +127,7 @@ public void setAutoTerminatedRelationships(final Set autoTerminatedRelat this.autoTerminatedRelationships = autoTerminatedRelationships; } - @ApiModelProperty("The run duration for the processor in milliseconds.") + @Schema(description = "The run duration for the processor in milliseconds.") public Long getRunDurationMillis() { return runDurationMillis; } @@ -136,7 +136,7 @@ public void setRunDurationMillis(Long runDurationMillis) { this.runDurationMillis = runDurationMillis; } - @ApiModelProperty("Stylistic data for rendering in a UI") + @Schema(description = "Stylistic data for rendering in a UI") public Map getStyle() { return style; } @@ -145,7 +145,7 @@ public void setStyle(Map style) { this.style = style; } - @ApiModelProperty("The scheduled state of the component") + @Schema(description = "The scheduled state of the component") public ScheduledState getScheduledState() { return scheduledState; } @@ -159,9 +159,7 @@ public ComponentType getComponentType() { return ComponentType.PROCESSOR; } - @ApiModelProperty( - value = "Overall number of retries." - ) + @Schema(description = "Overall number of retries.") public Integer getRetryCount() { return retryCount; } @@ -170,9 +168,7 @@ public void setRetryCount(Integer retryCount) { this.retryCount = retryCount; } - @ApiModelProperty( - value = "All the relationships should be retried." - ) + @Schema(description = "All the relationships should be retried.") public Set getRetriedRelationships() { return retriedRelationships; } @@ -181,8 +177,8 @@ public void setRetriedRelationships(Set retriedRelationships) { this.retriedRelationships = retriedRelationships; } - @ApiModelProperty( - value = "Determines whether the FlowFile should be penalized or the processor should be yielded between retries.", + @Schema( + description = "Determines whether the FlowFile should be penalized or the processor should be yielded between retries.", allowableValues = "PENALIZE_FLOWFILE, YIELD_PROCESSOR" ) public String getBackoffMechanism() { @@ -193,9 +189,7 @@ public void setBackoffMechanism(String backoffMechanism) { this.backoffMechanism = backoffMechanism; } - @ApiModelProperty( - value = "Maximum amount of time to be waited during a retry period." - ) + @Schema(description = "Maximum amount of time to be waited during a retry period.") public String getMaxBackoffPeriod() { return maxBackoffPeriod; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPropertyDescriptor.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPropertyDescriptor.java index 25ded8cf545f4..15409351dcb4a 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPropertyDescriptor.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedPropertyDescriptor.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class VersionedPropertyDescriptor { private String name; @@ -27,7 +27,7 @@ public class VersionedPropertyDescriptor { private boolean dynamic; private VersionedResourceDefinition resourceDefinition; - @ApiModelProperty("The name of the property") + @Schema(description = "The name of the property") public String getName() { return name; } @@ -36,7 +36,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The display name of the property") + @Schema(description = "The display name of the property") public String getDisplayName() { return displayName; } @@ -45,7 +45,7 @@ public void setDisplayName(String displayName) { this.displayName = displayName; } - @ApiModelProperty("Whether or not the property provides the identifier of a Controller Service") + @Schema(description = "Whether or not the property provides the identifier of a Controller Service") public boolean getIdentifiesControllerService() { return identifiesControllerService; } @@ -54,7 +54,7 @@ public void setIdentifiesControllerService(boolean identifiesControllerService) this.identifiesControllerService = identifiesControllerService; } - @ApiModelProperty("Whether or not the property is considered sensitive") + @Schema(description = "Whether or not the property is considered sensitive") public boolean isSensitive() { return sensitive; } @@ -63,7 +63,7 @@ public void setSensitive(boolean sensitive) { this.sensitive = sensitive; } - @ApiModelProperty("Whether or not the property is user-defined") + @Schema(description = "Whether or not the property is user-defined") public boolean isDynamic() { return dynamic; } @@ -72,7 +72,7 @@ public void setDynamic(boolean dynamic) { this.dynamic = dynamic; } - @ApiModelProperty("Returns the Resource Definition that defines which type(s) of resource(s) this property references, if any") + @Schema(description = "Returns the Resource Definition that defines which type(s) of resource(s) this property references, if any") public VersionedResourceDefinition getResourceDefinition() { return resourceDefinition; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteGroupPort.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteGroupPort.java index 33b61b2efb9e0..777866a508dda 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteGroupPort.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteGroupPort.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Objects; @@ -30,7 +30,7 @@ public class VersionedRemoteGroupPort extends VersionedComponent { private String targetId; private ScheduledState scheduledState; - @ApiModelProperty("The number of task that may transmit flowfiles to the target port concurrently.") + @Schema(description = "The number of task that may transmit flowfiles to the target port concurrently.") public Integer getConcurrentlySchedulableTaskCount() { return concurrentlySchedulableTaskCount; } @@ -39,7 +39,7 @@ public void setConcurrentlySchedulableTaskCount(Integer concurrentlySchedulableT this.concurrentlySchedulableTaskCount = concurrentlySchedulableTaskCount; } - @ApiModelProperty("The id of the remote process group that the port resides in.") + @Schema(description = "The id of the remote process group that the port resides in.") public String getRemoteGroupId() { return remoteGroupId; } @@ -49,7 +49,7 @@ public void setRemoteGroupId(String groupId) { } - @ApiModelProperty("Whether the flowfiles are compressed when sent to the target port.") + @Schema(description = "Whether the flowfiles are compressed when sent to the target port.") public Boolean isUseCompression() { return useCompression; } @@ -58,7 +58,7 @@ public void setUseCompression(Boolean useCompression) { this.useCompression = useCompression; } - @ApiModelProperty("The batch settings for data transmission.") + @Schema(description = "The batch settings for data transmission.") public BatchSize getBatchSize() { return batchSize; } @@ -67,7 +67,7 @@ public void setBatchSize(BatchSize batchSize) { this.batchSize = batchSize; } - @ApiModelProperty("The ID of the port on the target NiFi instance") + @Schema(description = "The ID of the port on the target NiFi instance") public String getTargetId() { return targetId; } @@ -76,7 +76,7 @@ public void setTargetId(final String targetId) { this.targetId = targetId; } - @ApiModelProperty("The scheduled state of the component") + @Schema(description = "The scheduled state of the component") public ScheduledState getScheduledState() { return scheduledState; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteProcessGroup.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteProcessGroup.java index 9b11b469b2b95..53590ea1117fb 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteProcessGroup.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedRemoteProcessGroup.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Set; @@ -36,11 +36,9 @@ public class VersionedRemoteProcessGroup extends VersionedComponent { private Set inputPorts; private Set outputPorts; - - @ApiModelProperty( - value = "The target URIs of the remote process group." + - " If target uris is not set but target uri is set, then returns the single target uri." + - " If neither target uris nor target uri is set, then returns null.") + @Schema(description = "The target URIs of the remote process group. " + + "If target uris is not set but target uri is set, then returns the single target uri. " + + "If neither target uris nor target uri is set, then returns null.") public String getTargetUris() { return !isEmpty(targetUris) ? targetUris : null; @@ -54,7 +52,7 @@ public void setTargetUris(String targetUris) { this.targetUris = targetUris; } - @ApiModelProperty("The time period used for the timeout when communicating with the target.") + @Schema(description = "The time period used for the timeout when communicating with the target.") public String getCommunicationsTimeout() { return communicationsTimeout; } @@ -63,7 +61,7 @@ public void setCommunicationsTimeout(String communicationsTimeout) { this.communicationsTimeout = communicationsTimeout; } - @ApiModelProperty("When yielding, this amount of time must elapse before the remote process group is scheduled again.") + @Schema(description = "When yielding, this amount of time must elapse before the remote process group is scheduled again.") public String getYieldDuration() { return yieldDuration; } @@ -72,7 +70,7 @@ public void setYieldDuration(String yieldDuration) { this.yieldDuration = yieldDuration; } - @ApiModelProperty(value = "The Transport Protocol that is used for Site-to-Site communications", allowableValues = "RAW, HTTP") + @Schema(description = "The Transport Protocol that is used for Site-to-Site communications", allowableValues = "RAW, HTTP") public String getTransportProtocol() { return transportProtocol; } @@ -81,7 +79,7 @@ public void setTransportProtocol(String transportProtocol) { this.transportProtocol = transportProtocol; } - @ApiModelProperty("A Set of Input Ports that can be connected to, in order to send data to the remote NiFi instance") + @Schema(description = "A Set of Input Ports that can be connected to, in order to send data to the remote NiFi instance") public Set getInputPorts() { return inputPorts; } @@ -90,7 +88,7 @@ public void setInputPorts(Set inputPorts) { this.inputPorts = inputPorts; } - @ApiModelProperty("A Set of Output Ports that can be connected to, in order to pull data from the remote NiFi instance") + @Schema(description = "A Set of Output Ports that can be connected to, in order to pull data from the remote NiFi instance") public Set getOutputPorts() { return outputPorts; } @@ -100,7 +98,7 @@ public void setOutputPorts(Set outputPorts) { } - @ApiModelProperty("The local network interface to send/receive data. If not specified, any local address is used. If clustered, all nodes must have an interface with this identifier.") + @Schema(description = "The local network interface to send/receive data. If not specified, any local address is used. If clustered, all nodes must have an interface with this identifier.") public String getLocalNetworkInterface() { return localNetworkInterface; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTask.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTask.java index 4450cedf3f68c..6e9cc03d6fe13 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTask.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTask.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class VersionedReportingTask extends VersionedConfigurableExtension { @@ -26,7 +26,7 @@ public class VersionedReportingTask extends VersionedConfigurableExtension { private String schedulingPeriod; private String schedulingStrategy; - @ApiModelProperty(value = "The annotation for the reporting task. This is how the custom UI relays configuration to the reporting task.") + @Schema(description = "The annotation for the reporting task. This is how the custom UI relays configuration to the reporting task.") public String getAnnotationData() { return annotationData; } @@ -35,7 +35,7 @@ public void setAnnotationData(String annotationData) { this.annotationData = annotationData; } - @ApiModelProperty("The frequency with which to schedule the reporting task. The format of the value will depend on the value of schedulingStrategy.") + @Schema(description = "The frequency with which to schedule the reporting task. The format of the value will depend on the value of schedulingStrategy.") public String getSchedulingPeriod() { return schedulingPeriod; } @@ -44,7 +44,7 @@ public void setSchedulingPeriod(String setSchedulingPeriod) { this.schedulingPeriod = setSchedulingPeriod; } - @ApiModelProperty("Indicates scheduling strategy that should dictate how the reporting task is triggered.") + @Schema(description = "Indicates scheduling strategy that should dictate how the reporting task is triggered.") public String getSchedulingStrategy() { return schedulingStrategy; } @@ -58,7 +58,7 @@ public ComponentType getComponentType() { return ComponentType.REPORTING_TASK; } - @ApiModelProperty("Indicates the scheduled state for the Reporting Task") + @Schema(description = "Indicates the scheduled state for the Reporting Task") public ScheduledState getScheduledState() { return scheduledState; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java index 3da3f8c302d14..d1d7e538d5a0b 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedReportingTaskSnapshot.java @@ -16,18 +16,17 @@ */ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.List; -@ApiModel +@Schema public class VersionedReportingTaskSnapshot { private List reportingTasks; private List controllerServices; - @ApiModelProperty(value = "The controller services") + @Schema(description = "The controller services") public List getControllerServices() { return controllerServices; } @@ -36,7 +35,7 @@ public void setControllerServices(List controllerSer this.controllerServices = controllerServices; } - @ApiModelProperty(value = "The reporting tasks") + @Schema(description = "The reporting tasks") public List getReportingTasks() { return reportingTasks; } diff --git a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedResourceDefinition.java b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedResourceDefinition.java index 97c4e18210c91..a04e23bd1a53e 100644 --- a/nifi-api/src/main/java/org/apache/nifi/flow/VersionedResourceDefinition.java +++ b/nifi-api/src/main/java/org/apache/nifi/flow/VersionedResourceDefinition.java @@ -17,7 +17,7 @@ package org.apache.nifi.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.Set; @@ -25,7 +25,7 @@ public class VersionedResourceDefinition { private VersionedResourceCardinality cardinality; private Set resourceTypes; - @ApiModelProperty("The cardinality of the resource") + @Schema(description = "The cardinality of the resource") public VersionedResourceCardinality getCardinality() { return cardinality; } @@ -34,7 +34,7 @@ public void setCardinality(final VersionedResourceCardinality cardinality) { this.cardinality = cardinality; } - @ApiModelProperty("The types of resource that the Property Descriptor is allowed to reference") + @Schema(description = "The types of resource that the Property Descriptor is allowed to reference") public Set getResourceTypes() { return resourceTypes; } diff --git a/nifi-api/src/main/java/org/apache/nifi/logging/LogMessage.java b/nifi-api/src/main/java/org/apache/nifi/logging/LogMessage.java index 664bc60a1344c..bae8154bc3366 100644 --- a/nifi-api/src/main/java/org/apache/nifi/logging/LogMessage.java +++ b/nifi-api/src/main/java/org/apache/nifi/logging/LogMessage.java @@ -18,10 +18,8 @@ import java.io.PrintWriter; import java.io.StringWriter; -import java.sql.Date; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Locale; +import java.time.Instant; +import java.time.format.DateTimeFormatter; public class LogMessage { @@ -32,8 +30,9 @@ public class LogMessage { private final String flowFileUuid; private final Object[] objects; - public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; - public static final String TO_STRING_FORMAT = "%1$s %2$s - %3$s"; + private static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + private static final String TO_STRING_FORMAT = "%1$s %2$s - %3$s"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); public static class Builder { @@ -109,8 +108,7 @@ public Object[] getObjects() { @Override public String toString() { - final DateFormat dateFormat = new SimpleDateFormat(DATE_TIME_FORMAT, Locale.US); - final String formattedTime = dateFormat.format(new Date(time)); + final String formattedTime = DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(time)); String formattedMsg = String.format(TO_STRING_FORMAT, formattedTime, logLevel.toString(), message); if (throwable != null) { diff --git a/nifi-api/src/test/java/org/apache/nifi/components/EnumAllowableValue.java b/nifi-api/src/test/java/org/apache/nifi/components/EnumDescribedValue.java similarity index 93% rename from nifi-api/src/test/java/org/apache/nifi/components/EnumAllowableValue.java rename to nifi-api/src/test/java/org/apache/nifi/components/EnumDescribedValue.java index e09b9e827847a..1e4fef8c5f728 100644 --- a/nifi-api/src/test/java/org/apache/nifi/components/EnumAllowableValue.java +++ b/nifi-api/src/test/java/org/apache/nifi/components/EnumDescribedValue.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.components; -public enum EnumAllowableValue implements DescribedValue { +public enum EnumDescribedValue implements DescribedValue { GREEN { @Override diff --git a/nifi-api/src/test/java/org/apache/nifi/components/EnumNotDescribedValue.java b/nifi-api/src/test/java/org/apache/nifi/components/EnumNotDescribedValue.java new file mode 100644 index 0000000000000..a280c9c70c370 --- /dev/null +++ b/nifi-api/src/test/java/org/apache/nifi/components/EnumNotDescribedValue.java @@ -0,0 +1,21 @@ +/* + * 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. + */ +package org.apache.nifi.components; + +public enum EnumNotDescribedValue { + GREEN, RED, BLUE; +} diff --git a/nifi-api/src/test/java/org/apache/nifi/components/TestPropertyDescriptor.java b/nifi-api/src/test/java/org/apache/nifi/components/TestPropertyDescriptor.java index fcaa0f7a1f21d..c3288e8f5f521 100644 --- a/nifi-api/src/test/java/org/apache/nifi/components/TestPropertyDescriptor.java +++ b/nifi-api/src/test/java/org/apache/nifi/components/TestPropertyDescriptor.java @@ -20,17 +20,16 @@ import org.apache.nifi.components.resource.ResourceCardinality; import org.apache.nifi.components.resource.ResourceType; import org.apache.nifi.expression.ExpressionLanguageScope; -import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.Mockito; import java.util.Arrays; +import java.util.Comparator; import java.util.EnumSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -40,77 +39,180 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyString; -/** - * Regression test for issue NIFI-49, to ensure that if a Processor's Property's - * Default Value is not allowed, the Exception thrown should indicate what the - * default value is - */ public class TestPropertyDescriptor { - private static Builder invalidDescriptorBuilder; - private static Builder validDescriptorBuilder; private static final String DEFAULT_VALUE = "Default Value"; private static final String DEPENDENT_PROPERTY_NAME = "dependentProperty"; - @BeforeAll - public static void setUp() { - validDescriptorBuilder = new PropertyDescriptor.Builder().name("").allowableValues("Allowable Value", "Another Allowable Value").defaultValue("Allowable Value"); - invalidDescriptorBuilder = new PropertyDescriptor.Builder().name("").allowableValues("Allowable Value", "Another Allowable Value").defaultValue(DEFAULT_VALUE); - } - - @Test - void testExceptionThrownByDescriptorWithInvalidDefaultValue() { - IllegalStateException exception = assertThrows(IllegalStateException.class, () -> invalidDescriptorBuilder.build()); - assertTrue(exception.getMessage().contains("[" + DEFAULT_VALUE + "]") ); - } - - @Test - void testNoExceptionThrownByPropertyDescriptorWithValidDefaultValue() { - assertNotNull(validDescriptorBuilder.build()); + @Nested + class RegardingDefaultValue { + @Test + void supportsStringValues() { + final PropertyDescriptor descriptor = builder().defaultValue(DEFAULT_VALUE).build(); + + assertEquals(DEFAULT_VALUE, descriptor.getDefaultValue()); + } + + @Test + void supportsDescribedValuesValues() { + final PropertyDescriptor descriptor = builder().defaultValue(EnumDescribedValue.GREEN).build(); + + assertEquals(EnumDescribedValue.GREEN.getValue(), descriptor.getDefaultValue()); + } + + /** + * Regression test for issue NIFI-49, to ensure that if a Processor's Property's + * Default Value is not allowed, the Exception thrown should indicate what the default value is + */ + @Test + void throwsIllegalStateExceptionWhenDefaultValueNotInAllowableValues() { + IllegalStateException exception = assertThrows(IllegalStateException.class, () -> { + builder().allowableValues("NOT DEFAULT", "OTHER NOT DEFAULT").defaultValue(DEFAULT_VALUE).build(); + }); + assertTrue(exception.getMessage().contains("[" + DEFAULT_VALUE + "]")); + } + + @Test + void canBeCleared() { + final PropertyDescriptor descriptorWithDefault = builder().defaultValue(DEFAULT_VALUE).build(); + final PropertyDescriptor resetDescriptor = builder(descriptorWithDefault).clearDefaultValue().build(); + + assertNull(resetDescriptor.getDefaultValue()); + } } - @Test - void testDefaultValueWithDescribedValue() { - final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder() - .name("defaultDescribedValueDescriptor") - .defaultValue(EnumAllowableValue.GREEN) - .build(); + @Nested + class RegardingAllowableValues { - assertNotNull(propertyDescriptor); - assertEquals(EnumAllowableValue.GREEN.getValue(), propertyDescriptor.getDefaultValue()); - } + private static final Comparator allowableValueComparator = Comparator.comparing(AllowableValue::getValue); + private final List expectedMinimalAllowableValues = + List.of(new AllowableValue("GREEN"), new AllowableValue("RED"), new AllowableValue("BLUE")); + private final List expectedAllowableValuesWithDescription = + Arrays.stream(EnumDescribedValue.values()).map(AllowableValue::fromDescribedValue).toList(); - @Test - void testAllowableValuesWithEnumClass() { - final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder() - .name("enumAllowableValueDescriptor") - .allowableValues(EnumAllowableValue.class) - .build(); + @Test + void supportsStringVarArgValues() { + final List expected = expectedMinimalAllowableValues; - assertNotNull(propertyDescriptor); + final PropertyDescriptor descriptor = builder().allowableValues("GREEN", "RED", "BLUE").build(); + final List actual = descriptor.getAllowableValues(); - final List expectedAllowableValues = Arrays.stream(EnumAllowableValue.values()) - .map(enumValue -> new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription())) - .collect(Collectors.toList()); - assertEquals(expectedAllowableValues, propertyDescriptor.getAllowableValues()); - } + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } - @Test - void testAllowableValuesWithEnumSet() { - final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder() - .name("enumAllowableValueDescriptor") - .allowableValues(EnumSet.of( - EnumAllowableValue.GREEN, - EnumAllowableValue.BLUE - )) - .build(); + @Test + void supportsStringSetValues() { + final List expected = sort(expectedMinimalAllowableValues); - assertNotNull(propertyDescriptor); + final PropertyDescriptor descriptor = builder().allowableValues(Set.of("GREEN", "RED", "BLUE")).build(); + // the iteration order of sets is not guaranteed by all implementations, thus we unify the order here + final List actual = sort(descriptor.getAllowableValues()); - final List expectedAllowableValues = Stream.of(EnumAllowableValue.GREEN, EnumAllowableValue.BLUE) - .map(enumValue -> new AllowableValue(enumValue.getValue(), enumValue.getDisplayName(), enumValue.getDescription())) - .collect(Collectors.toList()); - assertEquals(expectedAllowableValues, propertyDescriptor.getAllowableValues()); + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + void supportsEnumArrayValues() { + final List expected = expectedMinimalAllowableValues; + + final PropertyDescriptor descriptor = builder().allowableValues(EnumNotDescribedValue.values()).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + @SuppressWarnings({"rawtypes", "unchecked"}) + void supportsDescribedValueEnumArrayValues() { + final List expected = expectedAllowableValuesWithDescription; + + final Enum[] enumArray = EnumDescribedValue.values(); + final PropertyDescriptor descriptor = builder().allowableValues(enumArray).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + void supportsEnumClassValues() { + final List expected = expectedMinimalAllowableValues; + + final PropertyDescriptor descriptor = builder().allowableValues(EnumNotDescribedValue.class).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + void supportsDescribedValueEnumClassValues() { + final List expected = expectedAllowableValuesWithDescription; + + final PropertyDescriptor descriptor = builder().allowableValues(EnumDescribedValue.class).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + void supportsEnumSetValues() { + final List expected = expectedMinimalAllowableValues; + + final PropertyDescriptor descriptor = builder().allowableValues(EnumSet.allOf(EnumNotDescribedValue.class)).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + void supportsDescribedValueEnumSetValues() { + final List expected = expectedAllowableValuesWithDescription; + + final PropertyDescriptor descriptor = builder().allowableValues(EnumSet.allOf(EnumDescribedValue.class)).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + @Test + void supportsDescribedValueVarArgValues() { + final List expected = expectedAllowableValuesWithDescription; + + final PropertyDescriptor descriptor = builder() + .allowableValues(EnumDescribedValue.GREEN, EnumDescribedValue.RED, EnumDescribedValue.BLUE).build(); + final List actual = descriptor.getAllowableValues(); + + assertEquals(expected, actual); // equals only compares getValue() + assertEquals(displayNamesOf(expected), displayNamesOf(actual)); + assertEquals(descriptionsOf(expected), descriptionsOf(actual)); + } + + private List sort(final List allowableValues) { + return allowableValues.stream().sorted(allowableValueComparator).toList(); + } + + private List displayNamesOf(final List allowableValues) { + return allowableValues.stream().map(AllowableValue::getDisplayName).toList(); + } + + private List descriptionsOf(final List allowableValues) { + return allowableValues.stream().map(AllowableValue::getDescription).toList(); + } } @Test @@ -121,7 +223,7 @@ void testDependsOnWithEnumValue() { final PropertyDescriptor propertyDescriptor = new PropertyDescriptor.Builder() .name("enumDependsOnDescriptor") - .dependsOn(dependentPropertyDescriptor, EnumAllowableValue.RED) + .dependsOn(dependentPropertyDescriptor, EnumDescribedValue.RED) .build(); assertNotNull(propertyDescriptor); @@ -133,17 +235,17 @@ void testDependsOnWithEnumValue() { final Set dependentValues = dependency.getDependentValues(); assertEquals(1, dependentValues.size()); final String dependentValue = dependentValues.iterator().next(); - assertEquals(EnumAllowableValue.RED.getValue(), dependentValue); + assertEquals(EnumDescribedValue.RED.getValue(), dependentValue); } @Test void testExternalResourceIgnoredIfELWithAttributesPresent() { final PropertyDescriptor descriptor = new PropertyDescriptor.Builder() - .name("dir") - .identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .required(false) - .build(); + .name("dir") + .identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .required(false) + .build(); final ValidationContext validationContext = Mockito.mock(ValidationContext.class); Mockito.when(validationContext.isExpressionLanguagePresent(anyString())).thenReturn(true); @@ -159,11 +261,11 @@ void testExternalResourceIgnoredIfELWithAttributesPresent() { @Test void testExternalResourceConsideredIfELVarRegistryPresent() { final PropertyDescriptor descriptor = new PropertyDescriptor.Builder() - .name("dir") - .identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE, ResourceType.DIRECTORY) - .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .required(false) - .build(); + .name("dir") + .identifiesExternalResource(ResourceCardinality.SINGLE, ResourceType.FILE, ResourceType.DIRECTORY) + .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) + .required(false) + .build(); final AtomicReference variable = new AtomicReference<>("__my_var__"); final ValidationContext validationContext = Mockito.mock(ValidationContext.class); @@ -190,9 +292,9 @@ void testExternalResourceConsideredIfELVarRegistryPresent() { // Consider if Expression Language is not supported. Mockito.when(validationContext.isExpressionLanguageSupported(anyString())).thenReturn(false); final PropertyDescriptor withElNotAllowed = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(descriptor) - .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .build(); + .fromPropertyDescriptor(descriptor) + .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .build(); // Expression will not be evaluated, so the directory being looked at will literally be ${TestPropertyDescriptor.Var1} assertFalse(withElNotAllowed.validate("${TestPropertyDescriptor.Var1}", validationContext).isValid()); @@ -232,4 +334,12 @@ void testClearingValues() { assertTrue(pd2.getDependencies().isEmpty()); assertNull(pd2.getAllowableValues()); } + + private Builder builder() { + return new PropertyDescriptor.Builder().name("propertyName"); + } + + private Builder builder(final PropertyDescriptor propertyDescriptor) { + return new PropertyDescriptor.Builder().fromPropertyDescriptor(propertyDescriptor); + } } diff --git a/nifi-assembly/NOTICE b/nifi-assembly/NOTICE index 65553d8b0d522..c8ac921909379 100644 --- a/nifi-assembly/NOTICE +++ b/nifi-assembly/NOTICE @@ -43,7 +43,7 @@ This includes derived works from the Apache Hive (ASLv2 licensed) project (https This includes derived works from the Apache Software License V2 library Jolt (https://github.com/bazaarvoice/jolt) Copyright 2013-2014 Bazaarvoice, Inc The derived work is adapted from com.bazaarvoice.jolt.chainr.ChainrBuilder.java, com.bazaarvoice.jolt.chainr.spec.ChainrSpec.java, - com.bazaarvoice.jolt.chainr.spec.ChainrEntry.java and can be found in the org.apache.nifi.processors.standard.util.jolt.TransformFactory.java class. + com.bazaarvoice.jolt.chainr.spec.ChainrEntry.java and can be found in the org.apache.nifi.processors.jolt.TransformFactory.java class. This includes derived works from Elastic Logstash (https://github.com/elastic/logstash/tree/v1.4.0/) and modified by Anthony Corbacho, and contributors available under an Apache Software License V2. diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml index 630807bfe7873..ca2e987c2bd96 100644 --- a/nifi-assembly/pom.xml +++ b/nifi-assembly/pom.xml @@ -98,16 +98,6 @@ language governing permissions and limitations under the License. --> - - jakarta.servlet - jakarta.servlet-api - compile - - - org.eclipse.jetty.toolchain - jetty-schemas - compile - ch.qos.logback logback-classic @@ -788,7 +778,7 @@ language governing permissions and limitations under the License. --> org.apache.nifi - nifi-jolt-record-nar + nifi-jolt-nar 2.0.0-SNAPSHOT nar diff --git a/nifi-assembly/src/main/assembly/core.xml b/nifi-assembly/src/main/assembly/core.xml index d18c9c0c3f567..0ab9a38420275 100644 --- a/nifi-assembly/src/main/assembly/core.xml +++ b/nifi-assembly/src/main/assembly/core.xml @@ -29,9 +29,6 @@ org.slf4j:jul-to-slf4j ch.qos.logback:logback-classic ch.qos.logback:logback-core - - jakarta.servlet:jakarta.servlet-api - org.eclipse.jetty.toolchain:jetty-schemas org.apache.nifi:nifi-api org.apache.nifi:nifi-framework-api diff --git a/nifi-code-coverage/pom.xml b/nifi-code-coverage/pom.xml index 0c8b891d5dc77..b0904b5770f68 100644 --- a/nifi-code-coverage/pom.xml +++ b/nifi-code-coverage/pom.xml @@ -30,6 +30,7 @@ 1.10.14 1.6.0 1.24.0 + 2.12.0 @@ -108,6 +109,22 @@ core-io 1.7.24 + + + org.apache.sshd + sshd-core + ${org.apache.sshd.version} + + + org.apache.sshd + sshd-sftp + ${org.apache.sshd.version} + + + org.apache.sshd + sshd-osgi + ${org.apache.sshd.version} + @@ -1002,6 +1019,11 @@ nifi-event-transport 2.0.0-SNAPSHOT + + org.apache.nifi + nifi-file-transfer + 2.0.0-SNAPSHOT + org.apache.nifi nifi-hadoop-utils @@ -1239,7 +1261,7 @@ org.apache.nifi - nifi-jolt-record-processors + nifi-jolt-processors 2.0.0-SNAPSHOT @@ -1547,7 +1569,7 @@ org.apache.nifi - nifi-standard-utils + nifi-jolt-utils 2.0.0-SNAPSHOT diff --git a/nifi-commons/nifi-expression-language/pom.xml b/nifi-commons/nifi-expression-language/pom.xml index 41f2c129c0441..4486a1695904b 100644 --- a/nifi-commons/nifi-expression-language/pom.xml +++ b/nifi-commons/nifi-expression-language/pom.xml @@ -114,7 +114,6 @@ com.jayway.jsonpath json-path - 2.8.0 com.fasterxml.jackson.core diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPropertyValue.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPropertyValue.java index 142ba945bc8ce..2ff6ffc64e6d6 100644 --- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPropertyValue.java +++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPropertyValue.java @@ -237,13 +237,17 @@ public ResourceReferences asResources() { } @Override - public & DescribedValue> E asDescribedValue(Class enumType) throws IllegalArgumentException { + public > E asAllowableValue(Class enumType) throws IllegalArgumentException { if (rawValue == null) { return null; } for (E enumConstant : enumType.getEnumConstants()) { - if (enumConstant.getValue().equals(rawValue)) { + if (enumConstant instanceof DescribedValue describedValue) { + if (describedValue.getValue().equals(rawValue)) { + return enumConstant; + } + } else if (enumConstant.name().equals(rawValue)) { return enumConstant; } } diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java index dd8ddcf700f49..41be112c2fe96 100644 --- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java +++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java @@ -326,6 +326,9 @@ public class NiFiProperties extends ApplicationProperties { public static final String PYTHON_CONTROLLER_DEBUGPY_HOST = "nifi.python.controller.debugpy.host"; public static final String PYTHON_CONTROLLER_DEBUGPY_LOGS_DIR = "nifi.python.controller.debugpy.logs.directory"; + // kubernetes properties + public static final String CLUSTER_LEADER_ELECTION_KUBERNETES_LEASE_PREFIX = "nifi.cluster.leader.election.kubernetes.lease.prefix"; + public static final String DEFAULT_PYTHON_WORKING_DIRECTORY = "./work/python"; // automatic diagnostic defaults diff --git a/nifi-commons/nifi-property-protection-azure/pom.xml b/nifi-commons/nifi-property-protection-azure/pom.xml index 0a65b8f8dd416..c641939d4df78 100644 --- a/nifi-commons/nifi-property-protection-azure/pom.xml +++ b/nifi-commons/nifi-property-protection-azure/pom.xml @@ -26,7 +26,7 @@ com.azure azure-sdk-bom - 1.2.18 + 1.2.19 import pom diff --git a/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java b/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java index 1641bc14f9940..70f94486b9b0e 100644 --- a/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java +++ b/nifi-commons/nifi-property-protection-cipher/src/main/java/org/apache/nifi/properties/AesGcmSensitivePropertyProvider.java @@ -39,7 +39,7 @@ /** * Sensitive Property Provider implementation using AES-GCM with configurable key sizes */ -class AesGcmSensitivePropertyProvider implements SensitivePropertyProvider { +public class AesGcmSensitivePropertyProvider implements SensitivePropertyProvider { private static final String ALGORITHM = "AES/GCM/NoPadding"; private static final String SECRET_KEY_ALGORITHM = "AES"; private static final String DELIMITER = "||"; // "|" is not a valid Base64 character, so ensured not to be present in cipher text diff --git a/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/Format.java b/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/Format.java index 6c64b71646efb..b621f3dd5823d 100644 --- a/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/Format.java +++ b/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/Format.java @@ -21,10 +21,14 @@ import org.apache.nifi.record.path.StandardFieldValue; import org.apache.nifi.record.path.paths.RecordPathSegment; import org.apache.nifi.record.path.util.RecordPathUtils; -import org.apache.nifi.serialization.record.util.DataTypeUtils; import org.apache.nifi.util.StringUtils; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; +import java.util.TimeZone; import java.util.stream.Stream; public class Format extends RecordPathSegment { @@ -52,22 +56,37 @@ public Stream evaluate(final RecordPathEvaluationContext context) { final Stream fieldValues = recordPath.evaluate(context); return fieldValues.filter(fv -> fv.getValue() != null) .map(fv -> { - final java.text.DateFormat dateFormat = getDateFormat(this.dateFormat, this.timeZoneID, context); - if (dateFormat == null) { + final DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(this.dateFormat, this.timeZoneID, context); + if (dateTimeFormatter == null) { return fv; } - if (!(fv.getValue() instanceof Date) && !(fv.getValue() instanceof Number)) { + final Object fieldValue = fv.getValue(); + + final Instant instant; + if (fieldValue instanceof Date dateField) { + instant = Instant.ofEpochMilli(dateField.getTime()); + } else if (fieldValue instanceof Number numberField) { + instant = Instant.ofEpochMilli(numberField.longValue()); + } else { return fv; } - final Date dateValue = DataTypeUtils.toDate(fv.getValue(), null, fv.getField().getFieldName()); - final String formatted = dateFormat.format(dateValue); + final ZoneId zoneId; + if (timeZoneID == null) { + zoneId = ZoneId.systemDefault(); + } else { + final String timeZoneId = RecordPathUtils.getFirstStringValue(timeZoneID, context); + zoneId = TimeZone.getTimeZone(timeZoneId).toZoneId(); + } + + final ZonedDateTime dateTime = instant.atZone(zoneId); + final String formatted = dateTimeFormatter.format(dateTime); return new StandardFieldValue(formatted, fv.getField(), fv.getParent().orElse(null)); }); } - private java.text.DateFormat getDateFormat(final RecordPathSegment dateFormatSegment, final RecordPathSegment timeZoneID, final RecordPathEvaluationContext context) { + private DateTimeFormatter getDateTimeFormatter(final RecordPathSegment dateFormatSegment, final RecordPathSegment timeZoneID, final RecordPathEvaluationContext context) { final String dateFormatString = RecordPathUtils.getFirstStringValue(dateFormatSegment, context); if (StringUtils.isEmpty(dateFormatString)) { return null; @@ -75,13 +94,14 @@ private java.text.DateFormat getDateFormat(final RecordPathSegment dateFormatSeg try { if (timeZoneID == null) { - return DataTypeUtils.getDateFormat(dateFormatString); + return DateTimeFormatter.ofPattern(dateFormatString); } else { final String timeZoneStr = RecordPathUtils.getFirstStringValue(timeZoneID, context); if (StringUtils.isEmpty(timeZoneStr)) { return null; } - return DataTypeUtils.getDateFormat(dateFormatString, timeZoneStr); + final ZoneId zoneId = TimeZone.getTimeZone(timeZoneStr).toZoneId(); + return DateTimeFormatter.ofPattern(dateFormatString).withZone(zoneId); } } catch (final Exception e) { return null; diff --git a/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/ToDate.java b/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/ToDate.java index 561f73ee3f1a2..6637cc4079e9a 100644 --- a/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/ToDate.java +++ b/nifi-commons/nifi-record-path/src/main/java/org/apache/nifi/record/path/functions/ToDate.java @@ -21,10 +21,16 @@ import org.apache.nifi.record.path.StandardFieldValue; import org.apache.nifi.record.path.paths.RecordPathSegment; import org.apache.nifi.record.path.util.RecordPathUtils; -import org.apache.nifi.serialization.record.util.DataTypeUtils; import org.apache.nifi.util.StringUtils; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; import java.util.Date; +import java.util.TimeZone; import java.util.stream.Stream; public class ToDate extends RecordPathSegment { @@ -53,28 +59,69 @@ public Stream evaluate(RecordPathEvaluationContext context) { return fieldValues.filter(fv -> fv.getValue() != null) .map(fv -> { - if (!(fv.getValue() instanceof String)) { + final Object fieldValue = fv.getValue(); + if (!(fieldValue instanceof String)) { return fv; } - final java.text.DateFormat dateFormat = getDateFormat(this.dateFormat, this.timeZoneID, context); + final DateTimeFormatter dateTimeFormatter = getDateTimeFormatter(dateFormat, context); final Date dateValue; try { - dateValue = DataTypeUtils.toDate(fv.getValue(), () -> dateFormat, fv.getField().getFieldName()); + final TemporalAccessor parsed = dateTimeFormatter.parse(fieldValue.toString()); + + int year = 0; + if (parsed.isSupported(ChronoField.YEAR_OF_ERA)) { + year = parsed.get(ChronoField.YEAR_OF_ERA); + } + + int month = 0; + if (parsed.isSupported(ChronoField.MONTH_OF_YEAR)) { + month = parsed.get(ChronoField.MONTH_OF_YEAR); + } + + int day = 0; + if (parsed.isSupported(ChronoField.DAY_OF_MONTH)) { + day = parsed.get(ChronoField.DAY_OF_MONTH); + } + + int hour = 0; + if (parsed.isSupported(ChronoField.HOUR_OF_DAY)) { + hour = parsed.get(ChronoField.HOUR_OF_DAY); + } + + int minute = 0; + if (parsed.isSupported(ChronoField.MINUTE_OF_HOUR)) { + minute = parsed.get(ChronoField.MINUTE_OF_HOUR); + } + + int second = 0; + if (parsed.isSupported(ChronoField.SECOND_OF_MINUTE)) { + second = parsed.get(ChronoField.SECOND_OF_MINUTE); + } + + int nano = 0; + if (parsed.isSupported(ChronoField.MILLI_OF_SECOND)) { + nano = parsed.get(ChronoField.NANO_OF_SECOND); + } + + ZoneId zoneId = getZoneId(context); + if (zoneId == null) { + zoneId = ZoneId.systemDefault(); + } + + final ZonedDateTime zonedDateTime = ZonedDateTime.of(year, month, day, hour, minute, second, nano, zoneId); + final Instant instant = zonedDateTime.toInstant(); + dateValue = Date.from(instant); } catch (final Exception e) { return fv; } - if (dateValue == null) { - return fv; - } - return new StandardFieldValue(dateValue, fv.getField(), fv.getParent().orElse(null)); }); } - private java.text.DateFormat getDateFormat(final RecordPathSegment dateFormatSegment, final RecordPathSegment timeZoneID, final RecordPathEvaluationContext context) { + private DateTimeFormatter getDateTimeFormatter(final RecordPathSegment dateFormatSegment, final RecordPathEvaluationContext context) { if (dateFormatSegment == null) { return null; } @@ -85,18 +132,31 @@ private java.text.DateFormat getDateFormat(final RecordPathSegment dateFormatSeg } try { - if (timeZoneID == null) { - return DataTypeUtils.getDateFormat(dateFormatString); - } else { - final String timeZoneStr = RecordPathUtils.getFirstStringValue(timeZoneID, context); - if (StringUtils.isEmpty(timeZoneStr)) { - return null; - } - return DataTypeUtils.getDateFormat(dateFormatString, timeZoneStr); + final ZoneId zoneId = getZoneId(context); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormatString); + if (zoneId != null) { + formatter.withZone(zoneId); } + return formatter; } catch (final Exception e) { return null; } } + private ZoneId getZoneId(final RecordPathEvaluationContext context) { + final ZoneId zoneId; + + if (timeZoneID == null) { + zoneId = null; + } else { + final String timeZoneStr = RecordPathUtils.getFirstStringValue(timeZoneID, context); + if (StringUtils.isEmpty(timeZoneStr)) { + zoneId = null; + } else { + zoneId = TimeZone.getTimeZone(timeZoneStr).toZoneId(); + } + } + + return zoneId; + } } diff --git a/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java b/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java index 8de0e9330a6a1..2b6341124c399 100644 --- a/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java +++ b/nifi-commons/nifi-record-path/src/test/java/org/apache/nifi/record/path/TestRecordPath.java @@ -20,8 +20,6 @@ import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.StandardCharsets; import java.sql.Date; -import java.text.DateFormat; -import java.text.ParseException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -55,6 +53,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -86,10 +85,10 @@ public static void setSystemTimezone() { @Test public void testCompile() { - System.out.println(RecordPath.compile("/person/name/last")); - System.out.println(RecordPath.compile("/person[2]")); - System.out.println(RecordPath.compile("//person[2]")); - System.out.println(RecordPath.compile("/person/child[1]//sibling/name")); + RecordPath.compile("/person/name/last"); + RecordPath.compile("/person[2]"); + RecordPath.compile("//person[2]"); + RecordPath.compile("/person/child[1]//sibling/name"); // contains is a 'filter function' so can be used as the predicate RecordPath.compile("/name[contains(., 'hello')]"); @@ -1461,20 +1460,22 @@ public void testToDateFromString() { values.put("date", "2017-10-20T11:00:00Z"); final Record record = new MapRecord(schema, values); - assertTrue(RecordPath.compile("toDate(/date, \"yyyy-MM-dd'T'HH:mm:ss'Z'\")").evaluate(record).getSelectedFields().findFirst().get().getValue() instanceof Date); - assertTrue(RecordPath.compile("toDate(/date, \"yyyy-MM-dd'T'HH:mm:ss'Z'\", \"GMT+8:00\")").evaluate(record).getSelectedFields().findFirst().get().getValue() instanceof Date); + final Object evaluated = RecordPath.compile("toDate(/date, \"yyyy-MM-dd'T'HH:mm:ss'Z'\")").evaluate(record).getSelectedFields().findFirst().get().getValue(); + assertInstanceOf(java.util.Date.class, evaluated); + + final Object evaluatedTimeZone = RecordPath.compile("toDate(/date, \"yyyy-MM-dd'T'HH:mm:ss'Z'\", \"GMT+8:00\")").evaluate(record).getSelectedFields().findFirst().get().getValue(); + assertInstanceOf(java.util.Date.class, evaluatedTimeZone); } @Test - public void testToDateFromLong() throws ParseException { + public void testToDateFromLong() { final List fields = new ArrayList<>(); fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); fields.add(new RecordField("date", RecordFieldType.LONG.getDataType())); final RecordSchema schema = new SimpleRecordSchema(fields); - final DateFormat dateFormat = DataTypeUtils.getDateFormat("yyyy-MM-dd"); - final long dateValue = dateFormat.parse("2017-10-20T11:00:00Z").getTime(); + final long dateValue = 0L; final Map values = new HashMap<>(); values.put("id", 48); @@ -1540,10 +1541,10 @@ public void testFormatDateFromString() { assertEquals(adjustedDateTime, fieldValue3.getValue()); final FieldValue fieldValueUnchanged = RecordPath.compile("format( toDate(/date, \"yyyy-MM-dd'T'HH:mm:ss\"), 'INVALID' )").evaluate(record).getSelectedFields().findFirst().get(); - assertEquals(localDateFormatted, fieldValueUnchanged.getValue().toString()); + assertInstanceOf(java.util.Date.class, fieldValueUnchanged.getValue()); final FieldValue fieldValueUnchanged2 = RecordPath.compile("format( toDate(/date, \"yyyy-MM-dd'T'HH:mm:ss\"), 'INVALID' , 'INVALID')") .evaluate(record).getSelectedFields().findFirst().get(); - assertEquals(localDateFormatted, fieldValueUnchanged2.getValue().toString()); + assertInstanceOf(java.util.Date.class, fieldValueUnchanged2.getValue()); } @Test diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/MapRecord.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/MapRecord.java index 2ba5c2607fc0d..1ab6539297675 100644 --- a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/MapRecord.java +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/MapRecord.java @@ -19,6 +19,8 @@ import org.apache.nifi.serialization.SchemaValidationException; import org.apache.nifi.serialization.SimpleRecordSchema; +import org.apache.nifi.serialization.record.field.FieldConverter; +import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; import org.apache.nifi.serialization.record.type.ArrayDataType; import org.apache.nifi.serialization.record.type.ChoiceDataType; import org.apache.nifi.serialization.record.type.MapDataType; @@ -29,7 +31,7 @@ import org.slf4j.LoggerFactory; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -42,7 +44,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.Supplier; public class MapRecord implements Record { private static final Logger logger = LoggerFactory.getLogger(MapRecord.class); @@ -225,7 +226,8 @@ public String getAsString(final String fieldName) { return convertToString(getValue(fieldName), dataTypeOption.get().getFormat()); } - return DataTypeUtils.toString(getValue(fieldName), (Supplier) null); + final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class); + return converter.convertField(getValue(fieldName), Optional.empty(), fieldName); } @Override @@ -278,7 +280,9 @@ public Boolean getAsBoolean(final String fieldName) { @Override public Date getAsDate(final String fieldName, final String format) { - return DataTypeUtils.toDate(getValue(fieldName), () -> DataTypeUtils.getDateFormat(format), fieldName); + final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDate.class); + final LocalDate localDate = converter.convertField(getValue(fieldName), Optional.ofNullable(format), fieldName); + return localDate == null ? null : java.sql.Date.valueOf(localDate); } @Override diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/DateTimeFormatterRegistry.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/DateTimeFormatterRegistry.java new file mode 100644 index 0000000000000..27fba13784381 --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/DateTimeFormatterRegistry.java @@ -0,0 +1,36 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Caching Registry containing DateTimeFormatter objects for internal use with Field Converters + */ +class DateTimeFormatterRegistry { + private static final Map FORMATTERS = new ConcurrentHashMap<>(); + + static DateTimeFormatter getDateTimeFormatter(final String pattern) { + Objects.requireNonNull(pattern, "Pattern required"); + final DateTimeFormatter formatter = FORMATTERS.computeIfAbsent(pattern, DateTimeFormatter::ofPattern); + FORMATTERS.putIfAbsent(pattern, formatter); + return formatter; + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/FieldConversionException.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/FieldConversionException.java new file mode 100644 index 0000000000000..8570a6f3ea93b --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/FieldConversionException.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +/** + * Field Conversion Exception with standard properties + */ +public class FieldConversionException extends IllegalTypeConversionException { + + protected FieldConversionException(final Class outputFieldType, final Object field, final String fieldName) { + super("Conversion not supported for [%s] named [%s] to [%s]".formatted(field, fieldName, outputFieldType.getName())); + } + + protected FieldConversionException(final Class outputFieldType, final Object field, final String fieldName, final Throwable cause) { + super("Conversion failed for [%s] named [%s] to [%s] [%s] %s".formatted(field, fieldName, outputFieldType.getName(), cause.getClass().getName(), cause.getMessage())); + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/FieldConverterRegistry.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/FieldConverterRegistry.java new file mode 100644 index 0000000000000..42f2af900c33c --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/FieldConverterRegistry.java @@ -0,0 +1,31 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +/** + * Registry for abstracting access to Field Converter implementations + */ +public interface FieldConverterRegistry { + /** + * Get registered Field Converter using specified Output Field Type Class + * + * @param outputFieldType Output Field Type Class + * @return Field Converter from Object to Output Field Type + * @param Output Field Type + */ + FieldConverter getFieldConverter(Class outputFieldType); +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalDateFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalDateFieldConverter.java new file mode 100644 index 0000000000000..61e3a9b86d6ad --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalDateFieldConverter.java @@ -0,0 +1,91 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Optional; + +/** + * Convert Object to java.time.LocalDate using instanceof evaluation and optional format pattern for DateTimeFormatter + */ +class ObjectLocalDateFieldConverter implements FieldConverter { + /** + * Convert Object field to java.sql.Timestamp using optional format supported in DateTimeFormatter + * + * @param field Field can be null or a supported input type + * @param pattern Format pattern optional for parsing + * @param name Field name for tracking + * @return Timestamp or null when input field is null or empty string + * @throws IllegalTypeConversionException Thrown on parsing failures or unsupported types of input fields + */ + @Override + public LocalDate convertField(final Object field, final Optional pattern, final String name) { + if (field == null) { + return null; + } + if (field instanceof LocalDate) { + return (LocalDate) field; + } + if (field instanceof java.sql.Date date) { + return date.toLocalDate(); + } + if (field instanceof java.util.Date date) { + final Instant instant = date.toInstant(); + return ofInstant(instant); + } + if (field instanceof Number) { + final Number number = (Number) field; + final Instant instant = Instant.ofEpochMilli(number.longValue()); + return ofInstant(instant); + } + if (field instanceof String) { + final String string = field.toString().trim(); + if (string.isEmpty()) { + return null; + } + + if (pattern.isPresent()) { + final DateTimeFormatter formatter = DateTimeFormatterRegistry.getDateTimeFormatter(pattern.get()); + try { + return LocalDate.parse(string, formatter); + } catch (final DateTimeParseException e) { + throw new FieldConversionException(LocalDate.class, field, name, e); + } + } else { + try { + final long number = Long.parseLong(string); + final Instant instant = Instant.ofEpochMilli(number); + return ofInstant(instant); + } catch (final NumberFormatException e) { + throw new FieldConversionException(LocalDate.class, field, name, e); + } + } + } + + throw new FieldConversionException(LocalDate.class, field, name); + } + + private LocalDate ofInstant(final Instant instant) { + return LocalDate.ofInstant(instant, ZoneId.systemDefault()); + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalDateTimeFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalDateTimeFieldConverter.java new file mode 100644 index 0000000000000..860f0ebf4d935 --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalDateTimeFieldConverter.java @@ -0,0 +1,89 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Date; +import java.util.Optional; + +/** + * Convert Object to java.time.LocalDateTime using instanceof evaluation and optional format pattern for DateTimeFormatter + */ +class ObjectLocalDateTimeFieldConverter implements FieldConverter { + /** + * Convert Object field to java.sql.Timestamp using optional format supported in DateTimeFormatter + * + * @param field Field can be null or a supported input type + * @param pattern Format pattern optional for parsing + * @param name Field name for tracking + * @return Timestamp or null when input field is null or empty string + * @throws IllegalTypeConversionException Thrown on parsing failures or unsupported types of input fields + */ + @Override + public LocalDateTime convertField(final Object field, final Optional pattern, final String name) { + if (field == null) { + return null; + } + if (field instanceof LocalDateTime) { + return (LocalDateTime) field; + } + if (field instanceof Date date) { + final Instant instant = Instant.ofEpochMilli(date.getTime()); + return ofInstant(instant); + } + if (field instanceof Number) { + final Number number = (Number) field; + final Instant instant = Instant.ofEpochMilli(number.longValue()); + return ofInstant(instant); + } + if (field instanceof String) { + final String string = field.toString().trim(); + if (string.isEmpty()) { + return null; + } + + if (pattern.isPresent()) { + final DateTimeFormatter formatter = DateTimeFormatterRegistry.getDateTimeFormatter(pattern.get()); + try { + return LocalDateTime.parse(string, formatter); + } catch (final DateTimeParseException e) { + throw new FieldConversionException(LocalDateTime.class, field, name, e); + } + } else { + try { + final long number = Long.parseLong(string); + final Instant instant = Instant.ofEpochMilli(number); + return ofInstant(instant); + } catch (final NumberFormatException e) { + throw new FieldConversionException(LocalDateTime.class, field, name, e); + } + } + } + + throw new FieldConversionException(LocalDateTime.class, field, name); + } + + private LocalDateTime ofInstant(final Instant instant) { + return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalTimeFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalTimeFieldConverter.java new file mode 100644 index 0000000000000..b93984138ac4b --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectLocalTimeFieldConverter.java @@ -0,0 +1,97 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +import java.sql.Time; +import java.time.Instant; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Date; +import java.util.Optional; + +/** + * Convert Object to java.time.LocalTime using instanceof evaluation and optional format pattern for DateTimeFormatter + */ +class ObjectLocalTimeFieldConverter implements FieldConverter { + /** + * Convert Object field to java.time.LocalTime using optional format supported in DateTimeFormatter + * + * @param field Field can be null or a supported input type + * @param pattern Format pattern optional for parsing + * @param name Field name for tracking + * @return LocalTime or null when input field is null or empty string + * @throws IllegalTypeConversionException Thrown on parsing failures or unsupported types of input fields + */ + @Override + public LocalTime convertField(final Object field, final Optional pattern, final String name) { + if (field == null) { + return null; + } + if (field instanceof LocalTime) { + return (LocalTime) field; + } + if (field instanceof Time time) { + // Convert to Instant preserving millisecond precision + final long epochMilli = time.getTime(); + final Instant instant = Instant.ofEpochMilli(epochMilli); + return LocalTime.ofInstant(instant, ZoneId.systemDefault()); + } + if (field instanceof Date date) { + return ofInstant(Instant.ofEpochMilli(date.getTime())); + } + if (field instanceof Number) { + final Number number = (Number) field; + final Instant instant = Instant.ofEpochMilli(number.longValue()); + return ofInstant(instant); + } + if (field instanceof String) { + final String string = field.toString().trim(); + if (string.isEmpty()) { + return null; + } + + if (pattern.isPresent()) { + final DateTimeFormatter formatter = DateTimeFormatterRegistry.getDateTimeFormatter(pattern.get()); + try { + return LocalTime.parse(string, formatter); + } catch (final DateTimeParseException e) { + throw new FieldConversionException(LocalTime.class, field, name, e); + } + } else { + try { + final long number = Long.parseLong(string); + final Instant instant = Instant.ofEpochMilli(number); + return ofInstant(instant); + } catch (final NumberFormatException e) { + throw new FieldConversionException(LocalTime.class, field, name, e); + } + } + } + + throw new FieldConversionException(LocalTime.class, field, name); + } + + private LocalTime ofInstant(final Instant instant) { + final ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault()); + return zonedDateTime.toLocalTime(); + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectOffsetDateTimeFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectOffsetDateTimeFieldConverter.java new file mode 100644 index 0000000000000..390e41e3a76db --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectOffsetDateTimeFieldConverter.java @@ -0,0 +1,89 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Date; +import java.util.Optional; + +/** + * Convert Object to java.time.OffsetDateTime using instanceof evaluation and optional format pattern for DateTimeFormatter + */ +class ObjectOffsetDateTimeFieldConverter implements FieldConverter { + /** + * Convert Object field to java.time.OffsetDateTime using optional format supported in DateTimeFormatter + * + * @param field Field can be null or a supported input type + * @param pattern Format pattern optional for parsing + * @param name Field name for tracking + * @return OffsetDateTime or null when input field is null or empty string + * @throws IllegalTypeConversionException Thrown on parsing failures or unsupported types of input fields + */ + @Override + public OffsetDateTime convertField(final Object field, final Optional pattern, final String name) { + if (field == null) { + return null; + } + if (field instanceof OffsetDateTime) { + return (OffsetDateTime) field; + } + if (field instanceof Date date) { + final Instant instant = date.toInstant(); + return ofInstant(instant); + } + if (field instanceof Number) { + final Number number = (Number) field; + final Instant instant = Instant.ofEpochMilli(number.longValue()); + return ofInstant(instant); + } + if (field instanceof String) { + final String string = field.toString().trim(); + if (string.isEmpty()) { + return null; + } + + if (pattern.isPresent()) { + final DateTimeFormatter formatter = DateTimeFormatterRegistry.getDateTimeFormatter(pattern.get()); + try { + return OffsetDateTime.parse(string, formatter); + } catch (final DateTimeParseException e) { + throw new FieldConversionException(OffsetDateTime.class, field, name, e); + } + } else { + try { + final long number = Long.parseLong(string); + final Instant instant = Instant.ofEpochMilli(number); + return ofInstant(instant); + } catch (final NumberFormatException e) { + throw new FieldConversionException(OffsetDateTime.class, field, name, e); + } + } + } + + throw new FieldConversionException(OffsetDateTime.class, field, name); + } + + private OffsetDateTime ofInstant(final Instant instant) { + return OffsetDateTime.ofInstant(instant, ZoneId.systemDefault()); + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectStringFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectStringFieldConverter.java new file mode 100644 index 0000000000000..717b81f93e93d --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectStringFieldConverter.java @@ -0,0 +1,99 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.sql.Clob; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Convert Object to String using instanceof evaluation and optional format pattern for DateTimeFormatter + */ +class ObjectStringFieldConverter implements FieldConverter { + private static final Map FORMATTERS = new ConcurrentHashMap<>(); + + /** + * Convert Object field to String using optional format supported in DateTimeFormatter + * + * @param field Field can be null or a supported input type + * @param pattern Format pattern optional for parsing + * @param name Field name for tracking + * @return String or null when input field is null or empty string + * @throws IllegalTypeConversionException Thrown on parsing failures or unsupported types of input fields + */ + @Override + public String convertField(final Object field, final Optional pattern, final String name) { + if (field == null) { + return null; + } + if (field instanceof String) { + return field.toString(); + } + if (field instanceof java.sql.Timestamp timestamp) { + if (pattern.isEmpty()) { + return Long.toString(timestamp.getTime()); + } + final DateTimeFormatter formatter = DateTimeFormatterRegistry.getDateTimeFormatter(pattern.get()); + final LocalDateTime localDateTime = timestamp.toLocalDateTime(); + return formatter.format(localDateTime); + } + if (field instanceof java.util.Date date) { + if (pattern.isEmpty()) { + return Long.toString(date.getTime()); + } + final DateTimeFormatter formatter = DateTimeFormatterRegistry.getDateTimeFormatter(pattern.get()); + // java.sql.Date and java.sql.Time do not support toInstant() + final Instant instant = Instant.ofEpochMilli(date.getTime()); + final ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault()); + return formatter.format(dateTime); + } + if (field instanceof byte[] bytes) { + return new String(bytes, StandardCharsets.UTF_16); + } + if (field instanceof Byte[] bytes) { + final byte[] converted = new byte[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + converted[i] = bytes[i]; + } + return new String(converted, StandardCharsets.UTF_16); + } + if (field instanceof Clob clob) { + final StringBuilder builder = new StringBuilder(); + final char[] buffer = new char[32768]; + try (Reader reader = clob.getCharacterStream()) { + int charsRead; + while ((charsRead = reader.read(buffer)) != -1) { + builder.append(buffer, 0, charsRead); + } + return builder.toString(); + } catch (final Exception e) { + throw new FieldConversionException(String.class, field, name, e); + } + } + return field.toString(); + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimeFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimeFieldConverter.java new file mode 100644 index 0000000000000..9373f43c4a131 --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimeFieldConverter.java @@ -0,0 +1,57 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; + +import java.sql.Time; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Optional; + +/** + * Convert Object to java.sql.Time using instanceof evaluation and optional format pattern for DateTimeFormatter + */ +class ObjectTimeFieldConverter implements FieldConverter { + private static final ObjectLocalTimeFieldConverter CONVERTER = new ObjectLocalTimeFieldConverter(); + + /** + * Convert Object field to java.sql.Time using optional format supported in DateTimeFormatter + * + * @param field Field can be null or a supported input type + * @param pattern Format pattern optional for parsing + * @param name Field name for tracking + * @return Timestamp or null when input field is null or empty string + * @throws IllegalTypeConversionException Thrown on parsing failures or unsupported types of input fields + */ + @Override + public Time convertField(final Object field, final Optional pattern, final String name) { + final LocalTime localTime = CONVERTER.convertField(field, pattern, name); + + final Time time; + if (localTime == null) { + time = null; + } else { + final ZonedDateTime zonedDateTime = localTime.atDate(LocalDate.ofEpochDay(0)).atZone(ZoneId.systemDefault()); + final long epochMilli = zonedDateTime.toInstant().toEpochMilli(); + time = new Time(epochMilli); + } + return time; + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverter.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverter.java index a624845c09d91..aa8f5b48b2301 100644 --- a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverter.java +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverter.java @@ -20,15 +20,14 @@ import java.sql.Timestamp; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeParseException; -import java.util.Date; import java.util.Optional; /** * Convert Object to java.sql.Timestamp using instanceof evaluation and optional format pattern for DateTimeFormatter */ -public class ObjectTimestampFieldConverter implements FieldConverter { +class ObjectTimestampFieldConverter implements FieldConverter { + private static final ObjectLocalDateTimeFieldConverter CONVERTER = new ObjectLocalDateTimeFieldConverter(); + /** * Convert Object field to java.sql.Timestamp using optional format supported in DateTimeFormatter * @@ -40,47 +39,7 @@ public class ObjectTimestampFieldConverter implements FieldConverter pattern, final String name) { - if (field == null) { - return null; - } - if (field instanceof Timestamp) { - return (Timestamp) field; - } - if (field instanceof Date) { - final Date date = (Date) field; - return new Timestamp(date.getTime()); - } - if (field instanceof Number) { - final Number number = (Number) field; - return new Timestamp(number.longValue()); - } - if (field instanceof String) { - final String string = field.toString().trim(); - if (string.isEmpty()) { - return null; - } - - if (pattern.isPresent()) { - final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern.get()); - try { - final LocalDateTime localDateTime = LocalDateTime.parse(string, formatter); - return Timestamp.valueOf(localDateTime); - } catch (final DateTimeParseException e) { - final String message = String.format("Convert Field Name [%s] Value [%s] to Timestamp LocalDateTime parsing failed: %s", name, field, e.getMessage()); - throw new IllegalTypeConversionException(message); - } - } else { - try { - final long number = Long.parseLong(string); - return new Timestamp(number); - } catch (final NumberFormatException e) { - final String message = String.format("Convert Field Name [%s] Value [%s] to Timestamp Long parsing failed: %s", name, field, e.getMessage()); - throw new IllegalTypeConversionException(message); - } - } - } - - final String message = String.format("Convert Field Name [%s] Value [%s] Class [%s] to Timestamp not supported", name, field, field.getClass()); - throw new IllegalTypeConversionException(message); + final LocalDateTime localDateTime = CONVERTER.convertField(field, pattern, name); + return localDateTime == null ? null : Timestamp.valueOf(localDateTime); } } diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/StandardFieldConverterRegistry.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/StandardFieldConverterRegistry.java new file mode 100644 index 0000000000000..c959a4d73e5f5 --- /dev/null +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/field/StandardFieldConverterRegistry.java @@ -0,0 +1,74 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import java.sql.Time; +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.util.Map; +import java.util.Objects; + +public class StandardFieldConverterRegistry implements FieldConverterRegistry { + private static final Map, FieldConverter> FIELD_CONVERTERS = Map.of( + Time.class, new ObjectTimeFieldConverter(), + Timestamp.class, new ObjectTimestampFieldConverter(), + LocalDate.class, new ObjectLocalDateFieldConverter(), + LocalDateTime.class, new ObjectLocalDateTimeFieldConverter(), + LocalTime.class, new ObjectLocalTimeFieldConverter(), + OffsetDateTime.class, new ObjectOffsetDateTimeFieldConverter(), + String.class, new ObjectStringFieldConverter() + ); + + private static final StandardFieldConverterRegistry REGISTRY = new StandardFieldConverterRegistry(); + + private StandardFieldConverterRegistry() { + + } + + /** + * Get Field Converter Registry instance for access to configured Field Converters + * + * @return Field Converter Registry + */ + public static FieldConverterRegistry getRegistry() { + return REGISTRY; + } + + /** + * Get Field Converter for specified output field type class + * + * @param outputFieldType Output Field Type Class + * @return Field Converter + * @param Output Field Type + * @throws IllegalArgumentException Thrown when Field Converter not found for Output Field Type + */ + @SuppressWarnings("unchecked") + @Override + public FieldConverter getFieldConverter(final Class outputFieldType) { + Objects.requireNonNull(outputFieldType, "Output Field Type required"); + + final FieldConverter fieldConverter = FIELD_CONVERTERS.get(outputFieldType); + if (fieldConverter == null) { + throw new IllegalArgumentException("Field Converter not found for Output Field Type [%s]".formatted(outputFieldType)); + } + + return (FieldConverter) fieldConverter; + } +} diff --git a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java index 1d249eebd8a03..cebf33428b563 100644 --- a/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java +++ b/nifi-commons/nifi-record/src/main/java/org/apache/nifi/serialization/record/util/DataTypeUtils.java @@ -24,6 +24,8 @@ import org.apache.nifi.serialization.record.RecordField; import org.apache.nifi.serialization.record.RecordFieldType; import org.apache.nifi.serialization.record.RecordSchema; +import org.apache.nifi.serialization.record.field.FieldConverter; +import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; import org.apache.nifi.serialization.record.type.ArrayDataType; import org.apache.nifi.serialization.record.type.ChoiceDataType; import org.apache.nifi.serialization.record.type.DecimalDataType; @@ -48,14 +50,13 @@ import java.sql.Timestamp; import java.sql.Types; import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -71,14 +72,12 @@ import java.util.Optional; import java.util.Queue; import java.util.Set; -import java.util.TimeZone; import java.util.UUID; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Pattern; - public class DataTypeUtils { private static final Logger logger = LoggerFactory.getLogger(DataTypeUtils.class); @@ -113,9 +112,9 @@ public class DataTypeUtils { private static final Pattern FLOATING_POINT_PATTERN = Pattern.compile(doubleRegex); private static final Pattern DECIMAL_PATTERN = Pattern.compile(decimalRegex); - private static final Supplier DEFAULT_DATE_FORMAT = () -> getDateFormat(RecordFieldType.DATE.getDefaultFormat()); - private static final Supplier DEFAULT_TIME_FORMAT = () -> getDateFormat(RecordFieldType.TIME.getDefaultFormat()); - private static final Supplier DEFAULT_TIMESTAMP_FORMAT = () -> getDateFormat(RecordFieldType.TIMESTAMP.getDefaultFormat()); + private static final Optional DEFAULT_DATE_FORMAT = Optional.of(RecordFieldType.DATE.getDefaultFormat()); + private static final Optional DEFAULT_TIME_FORMAT = Optional.of(RecordFieldType.TIME.getDefaultFormat()); + private static final Optional DEFAULT_TIMESTAMP_FORMAT = Optional.of(RecordFieldType.TIMESTAMP.getDefaultFormat()); private static final int FLOAT_SIGNIFICAND_PRECISION = 24; // As specified in IEEE 754 binary32 private static final int DOUBLE_SIGNIFICAND_PRECISION = 53; // As specified in IEEE 754 binary64 @@ -154,27 +153,40 @@ public static Object convertType(final Object value, final DataType dataType, fi return convertType(value, dataType, DEFAULT_DATE_FORMAT, DEFAULT_TIME_FORMAT, DEFAULT_TIMESTAMP_FORMAT, fieldName, charset); } - public static DateFormat getDateFormat(final RecordFieldType fieldType, final Supplier dateFormat, - final Supplier timeFormat, final Supplier timestampFormat) { + private static String getDateFormat(final RecordFieldType fieldType, final Optional dateFormat, + final Optional timeFormat, final Optional timestampFormat) { switch (fieldType) { case DATE: - return dateFormat.get(); + return dateFormat.orElse(null); case TIME: - return timeFormat.get(); + return timeFormat.orElse(null); case TIMESTAMP: - return timestampFormat.get(); + return timestampFormat.orElse(null); } return null; } - public static Object convertType(final Object value, final DataType dataType, final Supplier dateFormat, final Supplier timeFormat, - final Supplier timestampFormat, final String fieldName) { + public static Object convertType( + final Object value, + final DataType dataType, + final Optional dateFormat, + final Optional timeFormat, + final Optional timestampFormat, + final String fieldName + ) { return convertType(value, dataType, dateFormat, timeFormat, timestampFormat, fieldName, StandardCharsets.UTF_8); } - public static Object convertType(final Object value, final DataType dataType, final Supplier dateFormat, final Supplier timeFormat, - final Supplier timestampFormat, final String fieldName, final Charset charset) { + public static Object convertType( + final Object value, + final DataType dataType, + final Optional dateFormat, + final Optional timeFormat, + final Optional timestampFormat, + final String fieldName, + final Charset charset + ) { if (value == null) { return null; @@ -190,7 +202,9 @@ public static Object convertType(final Object value, final DataType dataType, fi case CHAR: return toCharacter(value, fieldName); case DATE: - return convertTypeToDate(value, dateFormat, fieldName); + final FieldConverter localDateConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDate.class); + final LocalDate localDate = localDateConverter.convertField(value, dateFormat, fieldName); + return localDate == null ? null : Date.valueOf(localDate); case DECIMAL: return toBigDecimal(value, fieldName); case DOUBLE: @@ -206,11 +220,15 @@ public static Object convertType(final Object value, final DataType dataType, fi case ENUM: return toEnum(value, (EnumDataType) dataType, fieldName); case STRING: - return toString(value, () -> getDateFormat(dataType.getFieldType(), dateFormat, timeFormat, timestampFormat), charset); + final FieldConverter stringConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class); + final String pattern = getDateFormat(dataType.getFieldType(), dateFormat, timeFormat, timestampFormat); + return stringConverter.convertField(value, Optional.ofNullable(pattern), fieldName); case TIME: - return toTime(value, timeFormat, fieldName); + final FieldConverter timeConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Time.class); + return timeConverter.convertField(value, timeFormat, fieldName); case TIMESTAMP: - return toTimestamp(value, timestampFormat, fieldName); + final FieldConverter timestampConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Timestamp.class); + return timestampConverter.convertField(value, timestampFormat, fieldName); case UUID: return toUUID(value); case ARRAY: @@ -226,7 +244,7 @@ public static Object convertType(final Object value, final DataType dataType, fi final DataType chosenDataType = chooseDataType(value, choiceDataType); if (chosenDataType == null) { throw new IllegalTypeConversionException("Cannot convert value [" + value + "] of type " + value.getClass() - + " for field " + fieldName + " to any of the following available Sub-Types for a Choice: " + choiceDataType.getPossibleSubTypes()); + + " for field " + fieldName + " to any of the following available Sub-Types for a Choice: " + choiceDataType.getPossibleSubTypes()); } return convertType(value, chosenDataType, fieldName, charset); @@ -938,12 +956,7 @@ public static boolean isMapTypeCompatible(final Object value) { return value != null && (value instanceof Map || value instanceof MapRecord); } - - public static String toString(final Object value, final Supplier format) { - return toString(value, format, StandardCharsets.UTF_8); - } - - public static String toString(final Object value, final Supplier format, final Charset charset) { + private static String toString(final Object value, final Supplier format, final Charset charset) { if (value == null) { return null; } @@ -1029,17 +1042,18 @@ public static String toString(final Object value, final String format, final Cha return String.valueOf(((java.util.Date) value).getTime()); } + final FieldConverter fieldConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class); if (value instanceof java.sql.Date) { - return getDateFormat(format).format((java.util.Date) value); + return fieldConverter.convertField(value, Optional.of(format), null); } if (value instanceof java.sql.Time) { - return getDateFormat(format).format((java.util.Date) value); + return fieldConverter.convertField(value, Optional.of(format), null); } if (value instanceof java.sql.Timestamp) { - return getDateFormat(format).format((java.util.Date) value); + return fieldConverter.convertField(value, Optional.of(format), null); } if (value instanceof java.util.Date) { - return getDateFormat(format).format((java.util.Date) value); + return fieldConverter.convertField(value, Optional.of(format), null); } if (value instanceof Blob) { Blob blob = (Blob) value; @@ -1096,178 +1110,6 @@ private static Object toEnum(Object value, EnumDataType dataType, String fieldNa throw new IllegalTypeConversionException("Cannot convert value " + value + " of type " + dataType + " for field " + fieldName); } - public static java.sql.Date toDate(final Object value, final Supplier format, final String fieldName) { - if (value == null) { - return null; - } - - if (value instanceof Date) { - return (Date) value; - } - - if (value instanceof java.util.Date) { - java.util.Date _temp = (java.util.Date)value; - return new Date(_temp.getTime()); - } - - if (value instanceof Number) { - final long longValue = ((Number) value).longValue(); - return new Date(longValue); - } - - if (value instanceof String) { - try { - final String string = ((String) value).trim(); - if (string.isEmpty()) { - return null; - } - - if (format == null) { - return new Date(Long.parseLong(string)); - } - - final DateFormat dateFormat = format.get(); - if (dateFormat == null) { - return new Date(Long.parseLong(string)); - } - final java.util.Date utilDate = dateFormat.parse(string); - return new Date(utilDate.getTime()); - } catch (final ParseException | NumberFormatException e) { - throw new IllegalTypeConversionException("Could not convert value [" + value - + "] of type java.lang.String to Date because the value is not in the expected date format: " + format + " for field " + fieldName); - } - } - - throw new IllegalTypeConversionException("Cannot convert value [" + value + "] of type " + value.getClass() + " to Date for field " + fieldName); - } - - /** - * Get Date Time Formatter using Zone Identifier - * - * @param pattern Date Format Pattern - * @param zoneId Time Zone Identifier - * @return Date Time Formatter or null when provided pattern is null - */ - public static DateTimeFormatter getDateTimeFormatter(final String pattern, final ZoneId zoneId) { - if (pattern == null || zoneId == null) { - return null; - } - return DateTimeFormatter.ofPattern(pattern).withZone(zoneId); - } - - /** - * Convert value to Local Date with support for conversion from numbers or formatted strings - * - * @param value Value to be converted - * @param formatter Supplier for Date Time Formatter can be null when string parsing is not necessary - * @param fieldName Field Name for value to be converted - * @return Local Date or null when value to be converted is null - * @throws IllegalTypeConversionException Thrown when conversion from string fails or unsupported value provided - */ - public static LocalDate toLocalDate(final Object value, final Supplier formatter, final String fieldName) { - LocalDate localDate; - - if (value == null) { - return null; - } else if (value instanceof LocalDate) { - localDate = (LocalDate) value; - } else if (value instanceof java.sql.Date) { - final java.sql.Date date = (java.sql.Date) value; - localDate = date.toLocalDate(); - } else if (value instanceof java.util.Date) { - final java.util.Date date = (java.util.Date) value; - localDate = parseLocalDateEpochMillis(date.getTime()); - } else if (value instanceof Number) { - final long epochMillis = ((Number) value).longValue(); - localDate = parseLocalDateEpochMillis(epochMillis); - } else if (value instanceof String) { - try { - localDate = parseLocalDate((String) value, formatter); - } catch (final RuntimeException e) { - final String message = String.format("Failed Conversion of Field [%s] from String [%s] to LocalDate", fieldName, value); - throw new IllegalTypeConversionException(message, e); - } - } else { - final String message = String.format("Failed Conversion of Field [%s] from Value [%s] Type [%s] to LocalDate", fieldName, value, value.getClass()); - throw new IllegalTypeConversionException(message); - } - - return localDate; - } - - /** - * Convert value to java.sql.Date using java.time.LocalDate parsing and conversion from DateFormat to DateTimeFormatter - * - * Transitional method supporting conversion from legacy java.text.DateFormat to java.time.DateTimeFormatter - * - * @param value Value object to be converted - * @param format Supplier function for java.text.DateFormat when necessary for parsing - * @param fieldName Field name being parsed - * @return java.sql.Date or null when value is null - */ - private static Date convertTypeToDate(final Object value, final Supplier format, final String fieldName) { - if (value == null) { - return null; - } else { - final LocalDate localDate = toLocalDate(value, () -> { - final SimpleDateFormat dateFormat = (SimpleDateFormat) format.get(); - return dateFormat == null ? null : DateTimeFormatter.ofPattern(dateFormat.toPattern()); - }, fieldName); - return Date.valueOf(localDate); - } - } - - /** - * Parse Local Date from String using Date Time Formatter when supplied - * - * @param value String not null containing either formatted string or number of epoch milliseconds - * @param formatter Supplier for Date Time Formatter - * @return Local Date or null when provided value is empty - */ - private static LocalDate parseLocalDate(final String value, final Supplier formatter) { - LocalDate localDate = null; - - final String normalized = value.trim(); - if (!normalized.isEmpty()) { - if (formatter == null) { - localDate = parseLocalDateEpochMillis(normalized); - } else { - final DateTimeFormatter dateTimeFormatter = formatter.get(); - if (dateTimeFormatter == null) { - localDate = parseLocalDateEpochMillis(normalized); - } else { - localDate = LocalDate.parse(normalized, dateTimeFormatter); - } - } - } - - return localDate; - } - - - /** - * Parse Local Date from string expected to contain number of epoch milliseconds - * - * @param number Number string expected to contain epoch milliseconds - * @return Local Date converted from epoch milliseconds - */ - private static LocalDate parseLocalDateEpochMillis(final String number) { - final long epochMillis = Long.parseLong(number); - return parseLocalDateEpochMillis(epochMillis); - } - - /** - * Parse Local Date from epoch milliseconds using System Default Zone Offset - * - * @param epochMillis Epoch milliseconds - * @return Local Date converted from epoch milliseconds - */ - private static LocalDate parseLocalDateEpochMillis(final long epochMillis) { - final Instant instant = Instant.ofEpochMilli(epochMillis); - final ZonedDateTime zonedDateTime = instant.atZone(ZoneOffset.systemDefault()); - return zonedDateTime.toLocalDate(); - } - /** * Converts a java.sql.Date object in local time zone (typically coming from a java.sql.ResultSet and having 00:00:00 time part) * to UTC normalized form (storing the epoch corresponding to the UTC time with the same date/time as the input). @@ -1296,9 +1138,9 @@ public static boolean isDateTypeCompatible(final Object value, final String form } try { - getDateFormat(format).parse((String) value); + DateTimeFormatter.ofPattern(format).parse(value.toString()); return true; - } catch (final ParseException e) { + } catch (final DateTimeParseException e) { return false; } } @@ -1320,147 +1162,14 @@ private static boolean isInteger(final String value) { return true; } - public static Time toTime(final Object value, final Supplier format, final String fieldName) { - if (value == null) { - return null; - } - - if (value instanceof Time) { - return (Time) value; - } - - if (value instanceof Number) { - final long longValue = ((Number) value).longValue(); - return new Time(longValue); - } - - if (value instanceof String) { - try { - final String string = ((String) value).trim(); - if (string.isEmpty()) { - return null; - } - - if (format == null) { - return new Time(Long.parseLong(string)); - } - - final DateFormat dateFormat = format.get(); - if (dateFormat == null) { - return new Time(Long.parseLong(string)); - } - final java.util.Date utilDate = dateFormat.parse(string); - return new Time(utilDate.getTime()); - } catch (final ParseException e) { - throw new IllegalTypeConversionException("Could not convert value [" + value - + "] of type java.lang.String to Time for field " + fieldName + " because the value is not in the expected date format: " + format); - } - } - - throw new IllegalTypeConversionException("Cannot convert value [" + value + "] of type " + value.getClass() + " to Time for field " + fieldName); - } - - /** - * Get Date Format using default Local Time Zone - * - * @param pattern Date Format Pattern used for new SimpleDateFormat() - * @return Date Format or null when pattern not provided - */ - public static DateFormat getDateFormat(final String pattern) { - if (pattern == null) { - return null; - } - return getDateFormat(pattern, TimeZone.getDefault()); - } - - /** - * Get Date Format using specified Time Zone to adjust Date during processing - * - * @param pattern Date Format Pattern used for new SimpleDateFormat() - * @param timeZoneId Time Zone Identifier used for TimeZone.getTimeZone() - * @return Date Format or null when input parameters not provided - */ - public static DateFormat getDateFormat(final String pattern, final String timeZoneId) { - if (pattern == null || timeZoneId == null) { - return null; - } - return getDateFormat(pattern, TimeZone.getTimeZone(timeZoneId)); - } - - private static DateFormat getDateFormat(final String pattern, final TimeZone timeZone) { - if (pattern == null) { - return null; - } - final DateFormat dateFormat = new SimpleDateFormat(pattern); - dateFormat.setTimeZone(timeZone); - return dateFormat; - } - public static boolean isTimeTypeCompatible(final Object value, final String format) { return isDateTypeCompatible(value, format); } - public static Timestamp toTimestamp(final Object value, final Supplier format, final String fieldName) { - if (value == null) { - return null; - } - - if (value instanceof Timestamp) { - return (Timestamp) value; - } - - if (value instanceof java.util.Date) { - return new Timestamp(((java.util.Date)value).getTime()); - } - - if (value instanceof Number) { - final long longValue = ((Number) value).longValue(); - return new Timestamp(longValue); - } - - if (value instanceof String) { - final String string = ((String) value).trim(); - if (string.isEmpty()) { - return null; - } - - try { - if (format == null) { - return new Timestamp(Long.parseLong(string)); - } - - final DateFormat dateFormat = format.get(); - if (dateFormat == null) { - return new Timestamp(Long.parseLong(string)); - } - - final java.util.Date utilDate = dateFormat.parse(string); - return new Timestamp(utilDate.getTime()); - } catch (final ParseException e) { - final DateFormat dateFormat = format.get(); - final String formatDescription; - if (dateFormat == null) { - formatDescription = "Numeric"; - } else if (dateFormat instanceof SimpleDateFormat) { - formatDescription = ((SimpleDateFormat) dateFormat).toPattern(); - } else { - formatDescription = dateFormat.toString(); - } - - throw new IllegalTypeConversionException("Could not convert value [" + value - + "] of type java.lang.String to Timestamp for field " + fieldName + " because the value is not in the expected date format: " - + formatDescription); - } - } - - throw new IllegalTypeConversionException("Cannot convert value [" + value + "] of type " + value.getClass() + " to Timestamp for field " + fieldName); - } - public static boolean isTimestampTypeCompatible(final Object value, final String format) { return isDateTypeCompatible(value, format); } - public static BigInteger toBigInt(final Object value, final String fieldName) { if (value == null) { return null; diff --git a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/ResultSetRecordSetTest.java b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/ResultSetRecordSetTest.java index b1c272cdf6fd9..fa594a85a6dbf 100644 --- a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/ResultSetRecordSetTest.java +++ b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/ResultSetRecordSetTest.java @@ -19,7 +19,6 @@ import org.apache.nifi.serialization.SimpleRecordSchema; import org.apache.nifi.serialization.record.type.ArrayDataType; import org.apache.nifi.serialization.record.type.DecimalDataType; -import org.apache.nifi.serialization.record.util.DataTypeUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -265,7 +264,6 @@ public void testCreateSchemaWhenOtherTypeWithoutSchema() throws SQLException { @Test public void testCreateRecord() throws SQLException { - // given final RecordSchema recordSchema = givenRecordSchema(COLUMNS); LocalDate testDate = LocalDate.of(2021, 1, 26); @@ -311,11 +309,9 @@ public void testCreateRecord() throws SQLException { when(resultSet.getObject(COLUMN_NAME_BIG_DECIMAL_4)).thenReturn(bigDecimal4Value); when(resultSet.getObject(COLUMN_NAME_BIG_DECIMAL_5)).thenReturn(bigDecimal5Value); - // when ResultSetRecordSet testSubject = new ResultSetRecordSet(resultSet, recordSchema); Record record = testSubject.createRecord(resultSet); - // then assertEquals(varcharValue, record.getAsString(COLUMN_NAME_VARCHAR)); assertEquals(bigintValue, record.getAsLong(COLUMN_NAME_BIGINT)); assertEquals(rowidValue, record.getAsLong(COLUMN_NAME_ROWID)); @@ -324,7 +320,8 @@ public void testCreateRecord() throws SQLException { assertEquals(charValue, record.getValue(COLUMN_NAME_CHAR)); assertEquals(dateValue, record.getAsDate(COLUMN_NAME_DATE, null)); - assertEquals(timestampValue, DataTypeUtils.toTimestamp(record.getValue(COLUMN_NAME_TIMESTAMP), null, COLUMN_NAME_TIMESTAMP)); + final Object timestampObject = record.getValue(COLUMN_NAME_TIMESTAMP); + assertEquals(timestampValue, timestampObject); assertEquals(integerValue, record.getAsInt(COLUMN_NAME_INTEGER)); assertEquals(doubleValue, record.getAsDouble(COLUMN_NAME_DOUBLE)); diff --git a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/TestDataTypeUtils.java b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/TestDataTypeUtils.java index 7b11fd38bc4de..bfe26859b086e 100644 --- a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/TestDataTypeUtils.java +++ b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/TestDataTypeUtils.java @@ -29,17 +29,11 @@ import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.sql.Date; -import java.sql.Timestamp; import java.sql.Types; -import java.text.DateFormat; import java.time.Instant; -import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.LocalTime; import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -49,7 +43,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.DoubleAdder; @@ -66,8 +59,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class TestDataTypeUtils { - private static final ZoneId SYSTEM_DEFAULT_ZONE_ID = ZoneOffset.systemDefault(); - private static final String ISO_8601_YEAR_MONTH_DAY = "2000-01-01"; private static final String CUSTOM_MONTH_DAY_YEAR = "01-01-2000"; @@ -76,45 +67,12 @@ public class TestDataTypeUtils { private static final String DATE_FIELD = "date"; - /** - * This is a unit test to verify conversion java Date objects to Timestamps. Support for this was - * required in order to help the MongoDB packages handle date/time logical types in the Record API. - */ - @Test - public void testDateToTimestamp() { - java.util.Date date = new java.util.Date(); - Timestamp ts = DataTypeUtils.toTimestamp(date, null, null); - - assertNotNull(ts); - assertEquals(ts.getTime(), date.getTime(), "Times didn't match"); - - java.sql.Date sDate = new java.sql.Date(date.getTime()); - ts = DataTypeUtils.toTimestamp(date, null, null); - assertNotNull(ts); - assertEquals(ts.getTime(), sDate.getTime(), "Times didn't match"); - } - @Test public void testIntDoubleWiderType() { assertEquals(Optional.of(RecordFieldType.DOUBLE.getDataType()), DataTypeUtils.getWiderType(RecordFieldType.INT.getDataType(), RecordFieldType.DOUBLE.getDataType())); assertEquals(Optional.of(RecordFieldType.DOUBLE.getDataType()), DataTypeUtils.getWiderType(RecordFieldType.DOUBLE.getDataType(), RecordFieldType.INT.getDataType())); } - /* - * This was a bug in NiFi 1.8 where converting from a Timestamp to a Date with the record path API - * would throw an exception. - */ - @Test - public void testTimestampToDate() { - java.util.Date date = new java.util.Date(); - Timestamp ts = DataTypeUtils.toTimestamp(date, null, null); - assertNotNull(ts); - - java.sql.Date output = DataTypeUtils.toDate(ts, null, null); - assertNotNull(output); - assertEquals(output.getTime(), ts.getTime(), "Timestamps didn't match"); - } - @Test public void testConvertRecordMapToJavaMap() { assertNull(DataTypeUtils.convertRecordMapToJavaMap(null, null)); @@ -1063,61 +1021,15 @@ public void testConvertTypeStringToDateDefaultTimeZoneFormat() { assertEquals(ISO_8601_YEAR_MONTH_DAY, converted.toString()); } - /** - * Convert String to java.sql.Date using custom pattern DateFormat with configured GMT Time Zone - */ - @Test - public void testConvertTypeStringToDateConfiguredTimeZoneFormat() { - final DateFormat dateFormat = DataTypeUtils.getDateFormat(CUSTOM_MONTH_DAY_YEAR_PATTERN, "GMT"); - final Object converted = DataTypeUtils.convertType(CUSTOM_MONTH_DAY_YEAR, RecordFieldType.DATE.getDataType(), () -> dateFormat, null, null,"date"); - assertTrue(converted instanceof java.sql.Date, "Converted value is not java.sql.Date"); - assertEquals(ISO_8601_YEAR_MONTH_DAY, converted.toString()); - } - /** * Convert String to java.sql.Date using custom pattern DateFormat with system default Time Zone */ @Test public void testConvertTypeStringToDateConfiguredSystemDefaultTimeZoneFormat() { - final DateFormat dateFormat = DataTypeUtils.getDateFormat(CUSTOM_MONTH_DAY_YEAR_PATTERN, TimeZone.getDefault().getID()); - final Object converted = DataTypeUtils.convertType(CUSTOM_MONTH_DAY_YEAR, RecordFieldType.DATE.getDataType(), () -> dateFormat, null, null,"date"); + final Object converted = DataTypeUtils.convertType( + CUSTOM_MONTH_DAY_YEAR, RecordFieldType.DATE.getDataType(), Optional.of(CUSTOM_MONTH_DAY_YEAR_PATTERN), Optional.empty(), Optional.empty(),"date" + ); assertTrue(converted instanceof java.sql.Date, "Converted value is not java.sql.Date"); assertEquals(ISO_8601_YEAR_MONTH_DAY, converted.toString()); } - - @Test - public void testToLocalDateFromString() { - assertToLocalDateEquals(ISO_8601_YEAR_MONTH_DAY, ISO_8601_YEAR_MONTH_DAY); - } - - @Test - public void testToLocalDateFromSqlDate() { - assertToLocalDateEquals(ISO_8601_YEAR_MONTH_DAY, java.sql.Date.valueOf(ISO_8601_YEAR_MONTH_DAY)); - } - - @Test - public void testToLocalDateFromUtilDate() { - final LocalDate localDate = LocalDate.parse(ISO_8601_YEAR_MONTH_DAY); - final long epochMillis = toEpochMilliSystemDefaultZone(localDate); - assertToLocalDateEquals(ISO_8601_YEAR_MONTH_DAY, new java.util.Date(epochMillis)); - } - - @Test - public void testToLocalDateFromNumberEpochMillis() { - final LocalDate localDate = LocalDate.parse(ISO_8601_YEAR_MONTH_DAY); - final long epochMillis = toEpochMilliSystemDefaultZone(localDate); - assertToLocalDateEquals(ISO_8601_YEAR_MONTH_DAY, epochMillis); - } - - private long toEpochMilliSystemDefaultZone(final LocalDate localDate) { - final LocalTime localTime = LocalTime.of(0, 0); - final Instant instantSystemDefaultZone = ZonedDateTime.of(localDate, localTime, SYSTEM_DEFAULT_ZONE_ID).toInstant(); - return instantSystemDefaultZone.toEpochMilli(); - } - - private void assertToLocalDateEquals(final String expected, final Object value) { - final DateTimeFormatter systemDefaultZoneFormatter = DataTypeUtils.getDateTimeFormatter(RecordFieldType.DATE.getDefaultFormat(), SYSTEM_DEFAULT_ZONE_ID); - final LocalDate localDate = DataTypeUtils.toLocalDate(value, () -> systemDefaultZoneFormatter, DATE_FIELD); - assertEquals(expected, localDate.toString(), String.format("Value Class [%s] to LocalDate not matched", value.getClass())); - } } diff --git a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectOffsetDateTimeFieldConverterTest.java b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectOffsetDateTimeFieldConverterTest.java new file mode 100644 index 0000000000000..9f75195505eed --- /dev/null +++ b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectOffsetDateTimeFieldConverterTest.java @@ -0,0 +1,117 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.RecordFieldType; +import org.junit.jupiter.api.Test; + +import java.sql.Timestamp; +import java.time.OffsetDateTime; +import java.util.Date; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ObjectOffsetDateTimeFieldConverterTest { + private static final ObjectOffsetDateTimeFieldConverter CONVERTER = new ObjectOffsetDateTimeFieldConverter(); + + private static final String DEFAULT_PATTERN = RecordFieldType.TIMESTAMP.getDefaultFormat(); + + private static final String FIELD_NAME = OffsetDateTime.class.getSimpleName(); + + private static final String EMPTY = ""; + + private static final String DATE_TIME_DEFAULT = "2000-01-01 12:00:00"; + + private static final String OFFSET_DATE_TIME_DEFAULT = "2000-01-01T12:30:45Z"; + + private static final String OFFSET_DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssX"; + + private static final String NANOSECONDS_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSSX"; + + private static final String DATE_TIME_NANOSECONDS = "2000-01-01T12:00:00.123456789Z"; + + @Test + public void testConvertFieldNull() { + final OffsetDateTime offsetDateTime = CONVERTER.convertField(null, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertNull(offsetDateTime); + } + + @Test + public void testConvertFieldTimestamp() { + final Timestamp field = new Timestamp(System.currentTimeMillis()); + final OffsetDateTime offsetDateTime = CONVERTER.convertField(field, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertEquals(field.getTime(), offsetDateTime.toInstant().toEpochMilli()); + } + + @Test + public void testConvertFieldDate() { + final Date field = new Date(); + final OffsetDateTime offsetDateTime = CONVERTER.convertField(field, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertEquals(field.getTime(), offsetDateTime.toInstant().toEpochMilli()); + } + + @Test + public void testConvertFieldLong() { + final long field = System.currentTimeMillis(); + final OffsetDateTime offsetDateTime = CONVERTER.convertField(field, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertEquals(field, offsetDateTime.toInstant().toEpochMilli()); + } + + @Test + public void testConvertFieldStringEmpty() { + final OffsetDateTime offsetDateTime = CONVERTER.convertField(EMPTY, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertNull(offsetDateTime); + } + + @Test + public void testConvertFieldStringFormatNull() { + final long currentTime = System.currentTimeMillis(); + final String field = Long.toString(currentTime); + final OffsetDateTime offsetDateTime = CONVERTER.convertField(field, Optional.empty(), FIELD_NAME); + assertEquals(currentTime, offsetDateTime.toInstant().toEpochMilli()); + } + + @Test + public void testConvertFieldStringFormatNullNumberFormatException() { + final String field = String.class.getSimpleName(); + final FieldConversionException exception = assertThrows(FieldConversionException.class, () -> CONVERTER.convertField(field, Optional.empty(), FIELD_NAME)); + assertTrue(exception.getMessage().contains(field)); + } + + @Test + public void testConvertFieldStringFormatDefault() { + final OffsetDateTime offsetDateTime = CONVERTER.convertField(OFFSET_DATE_TIME_DEFAULT, Optional.of(OFFSET_DATE_TIME_PATTERN), FIELD_NAME); + assertEquals(OFFSET_DATE_TIME_DEFAULT, offsetDateTime.toString()); + } + + @Test + public void testConvertFieldStringFormatCustomNanoseconds() { + final OffsetDateTime offsetDateTime = CONVERTER.convertField(DATE_TIME_NANOSECONDS, Optional.of(NANOSECONDS_PATTERN), FIELD_NAME); + final OffsetDateTime expected = OffsetDateTime.parse(DATE_TIME_NANOSECONDS); + assertEquals(expected, offsetDateTime); + } + + @Test + public void testConvertFieldStringFormatCustomFormatterException() { + final FieldConversionException exception = assertThrows(FieldConversionException.class, () -> CONVERTER.convertField(DATE_TIME_DEFAULT, Optional.of(NANOSECONDS_PATTERN), FIELD_NAME)); + assertTrue(exception.getMessage().contains(DATE_TIME_DEFAULT)); + } +} diff --git a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimeFieldConverterTest.java b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimeFieldConverterTest.java new file mode 100644 index 0000000000000..0e88c454301cc --- /dev/null +++ b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimeFieldConverterTest.java @@ -0,0 +1,83 @@ +/* + * 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. + */ +package org.apache.nifi.serialization.record.field; + +import org.apache.nifi.serialization.record.RecordFieldType; +import org.junit.jupiter.api.Test; + +import java.sql.Time; +import java.util.Date; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +public class ObjectTimeFieldConverterTest { + private static final ObjectTimeFieldConverter CONVERTER = new ObjectTimeFieldConverter(); + + private static final String DEFAULT_PATTERN = RecordFieldType.TIME.getDefaultFormat(); + + private static final String FIELD_NAME = Time.class.getSimpleName(); + + private static final String EMPTY = ""; + + private static final String TIME_DEFAULT = "12:30:45"; + + private static final String TIME_NANOSECONDS_PATTERN = "HH:mm:ss.SSSSSSSSS"; + + private static final String TIME_NANOSECONDS = "12:30:45.123456789"; + + @Test + public void testConvertFieldNull() { + final Time time = CONVERTER.convertField(null, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertNull(time); + } + + @Test + public void testConvertFieldStringEmpty() { + final Time time = CONVERTER.convertField(EMPTY, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertNull(time); + } + + @Test + public void testConvertFieldTime() { + final Time field = Time.valueOf(TIME_DEFAULT); + final Time time = CONVERTER.convertField(field, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertEquals(field.getTime(), time.getTime()); + } + + @Test + public void testConvertFieldTimeNanoseconds() { + final Time time = CONVERTER.convertField(TIME_NANOSECONDS, Optional.of(TIME_NANOSECONDS_PATTERN), FIELD_NAME); + assertEquals(TIME_DEFAULT, time.toString()); + } + + @Test + public void testConvertFieldDate() { + final Date field = new Date(); + final Time time = CONVERTER.convertField(field, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertNotNull(time); + } + + @Test + public void testConvertFieldLong() { + final long field = System.currentTimeMillis(); + final Time time = CONVERTER.convertField(field, Optional.of(DEFAULT_PATTERN), FIELD_NAME); + assertNotNull(time); + } +} diff --git a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverterTest.java b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverterTest.java index 9424d0fa1b08a..cd69236c4cca2 100644 --- a/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverterTest.java +++ b/nifi-commons/nifi-record/src/test/java/org/apache/nifi/serialization/record/field/ObjectTimestampFieldConverterTest.java @@ -17,7 +17,6 @@ package org.apache.nifi.serialization.record.field; import org.apache.nifi.serialization.record.RecordFieldType; -import org.apache.nifi.serialization.record.util.IllegalTypeConversionException; import org.junit.jupiter.api.Test; import java.sql.Timestamp; @@ -88,7 +87,7 @@ public void testConvertFieldStringFormatNull() { @Test public void testConvertFieldStringFormatNullNumberFormatException() { final String field = String.class.getSimpleName(); - final IllegalTypeConversionException exception = assertThrows(IllegalTypeConversionException.class, () -> CONVERTER.convertField(field, Optional.empty(), FIELD_NAME)); + final FieldConversionException exception = assertThrows(FieldConversionException.class, () -> CONVERTER.convertField(field, Optional.empty(), FIELD_NAME)); assertTrue(exception.getMessage().contains(field)); } @@ -108,7 +107,7 @@ public void testConvertFieldStringFormatCustomNanoseconds() { @Test public void testConvertFieldStringFormatCustomFormatterException() { - final IllegalTypeConversionException exception = assertThrows(IllegalTypeConversionException.class, () -> CONVERTER.convertField(DATE_TIME_DEFAULT, DATE_TIME_NANOSECONDS_PATTERN, FIELD_NAME)); + final FieldConversionException exception = assertThrows(FieldConversionException.class, () -> CONVERTER.convertField(DATE_TIME_DEFAULT, DATE_TIME_NANOSECONDS_PATTERN, FIELD_NAME)); assertTrue(exception.getMessage().contains(DATE_TIME_DEFAULT)); } } diff --git a/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java b/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java index 20936d5ea3749..a6c7230d629a6 100644 --- a/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java +++ b/nifi-commons/nifi-security-kerberos/src/main/java/org/apache/nifi/security/krb/AbstractKerberosUser.java @@ -32,17 +32,15 @@ import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; +import java.time.format.DateTimeFormatter; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** * Base class for implementations of KerberosUser. - * * Generally implementations must provide the specific Configuration instance for performing the login, * along with an optional CallbackHandler. - * * Some functionality in this class is adapted from Hadoop's UserGroupInformation. */ public abstract class AbstractKerberosUser implements KerberosUser { @@ -50,6 +48,7 @@ public abstract class AbstractKerberosUser implements KerberosUser { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractKerberosUser.class); static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT); /** * Percentage of the ticket window to use before we renew the TGT. @@ -99,7 +98,7 @@ public synchronized void login() { loginContext.login(); loggedIn.set(true); - LOGGER.debug("Successful login for {}", new Object[]{principal}); + LOGGER.debug("Successful login for {}", principal); } catch (final LoginException le) { throw new KerberosLoginException("Unable to login with " + principal + " due to: " + le.getMessage(), le); } @@ -143,7 +142,7 @@ public synchronized void logout() { try { loginContext.logout(); loggedIn.set(false); - LOGGER.debug("Successful logout for {}", new Object[]{principal}); + LOGGER.debug("Successful logout for {}", principal); loginContext = null; } catch (final LoginException e) { @@ -190,7 +189,6 @@ public T doAs(final PrivilegedExceptionAction action) /** * Re-login a user from keytab if TGT is expired or is close to expiry. * - * @throws LoginException if an error happens performing the re-login */ @Override public synchronized boolean checkTGTAndRelogin() { @@ -200,7 +198,7 @@ public synchronized boolean checkTGTAndRelogin() { return logoutAndLogin(); } - if (tgt != null && System.currentTimeMillis() < getRefreshTime(tgt)) { + if (System.currentTimeMillis() < getRefreshTime(tgt)) { LOGGER.debug("TGT for {} was found, but has not reached expiration window", principal); return false; } @@ -222,7 +220,7 @@ public synchronized boolean checkTGTAndRelogin() { } private boolean logoutAndLogin() { - LOGGER.debug("Performing logout/login", principal); + LOGGER.debug("Performing logout/login {}", principal); logout(); login(); return true; @@ -271,15 +269,14 @@ private long getRefreshTime(final KerberosTicket tgt) { final long end = tgt.getEndTime().getTime(); if (LOGGER.isTraceEnabled()) { - final SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - final String startDate = dateFormat.format(new Date(start)); - final String endDate = dateFormat.format(new Date(end)); + final String startDate = DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(start)); + final String endDate = DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(end)); LOGGER.trace("TGT for {} is valid starting at [{}]", principal, startDate); LOGGER.trace("TGT for {} expires at [{}]", principal, endDate); if (tgt.getRenewTill() == null) { LOGGER.trace("TGT for {} is non-renewable", principal); } else { - LOGGER.trace("TGT for {} renews until [{}]", principal, dateFormat.format(tgt.getRenewTill())); + LOGGER.trace("TGT for {} renews until [{}]", principal, DATE_TIME_FORMATTER.format(tgt.getRenewTill().toInstant())); } } diff --git a/nifi-commons/nifi-swagger-integration/pom.xml b/nifi-commons/nifi-swagger-integration/pom.xml new file mode 100644 index 0000000000000..fa20b5ab42b8d --- /dev/null +++ b/nifi-commons/nifi-swagger-integration/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + + org.apache.nifi + nifi-commons + 2.0.0-SNAPSHOT + + nifi-swagger-integration + jar + + + + io.swagger.core.v3 + swagger-integration-jakarta + ${swagger.annotations.version} + provided + + + diff --git a/nifi-commons/nifi-swagger-integration/src/main/java/org/apache/nifi/swagger/integration/StandardObjectMapperProcessor.java b/nifi-commons/nifi-swagger-integration/src/main/java/org/apache/nifi/swagger/integration/StandardObjectMapperProcessor.java new file mode 100644 index 0000000000000..c0c17ca7f2858 --- /dev/null +++ b/nifi-commons/nifi-swagger-integration/src/main/java/org/apache/nifi/swagger/integration/StandardObjectMapperProcessor.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.nifi.swagger.integration; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import io.swagger.v3.oas.integration.api.ObjectMapperProcessor; + +/** + * Standard Jackson Object Mapper Processor for customizing OpenAPI Specification generation + */ +public class StandardObjectMapperProcessor implements ObjectMapperProcessor { + + @Override + public void processJsonObjectMapper(final ObjectMapper mapper) { + // Write enums using name() instead of toString() + mapper.disable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING); + } +} diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java index 8dec493f642bd..783f26e88f923 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/FormatUtils.java @@ -447,7 +447,7 @@ public static DateTimeFormatter prepareLenientCaseInsensitiveDateTimeFormatter(S } /** - * Parse text to Instant - support different formats like: zoned date time, date time, date, time (similar to those supported in SimpleDateFormat) + * Parse text to Instant - support different formats like: zoned date time, date time, date, time * @param formatter configured formatter * @param text text which will be parsed * @return parsed Instant diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/SimpleDateFormatMatcher.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeFormatterMatcher.java similarity index 75% rename from nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/SimpleDateFormatMatcher.java rename to nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeFormatterMatcher.java index 721d140e1d327..b0bb88fb849f7 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/SimpleDateFormatMatcher.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeFormatterMatcher.java @@ -16,20 +16,19 @@ */ package org.apache.nifi.util.text; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; -class SimpleDateFormatMatcher implements DateTimeMatcher { - private final DateFormat dateFormat; +class DateTimeFormatterMatcher implements DateTimeMatcher { + private final DateTimeFormatter dateTimeFormatter; - public SimpleDateFormatMatcher(final String format) { - this.dateFormat = new SimpleDateFormat(format); + public DateTimeFormatterMatcher(final String format) { + this.dateTimeFormatter = DateTimeFormatter.ofPattern(format); } @Override public boolean matches(final String text) { try { - dateFormat.parse(text); + dateTimeFormatter.parse(text); return true; } catch (final Exception e) { return false; diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcher.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcher.java index 2e35ec229287b..678779e796c88 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcher.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcher.java @@ -19,13 +19,13 @@ /** *

    * A utility class that can be used to determine whether or not a String matches a given date/time format, as specified - * by the Time Format used in {@link java.text.SimpleDateFormat}. It is not uncommon to see code written along the lines of: + * by the Time Format used in {@link java.time.format.DateTimeFormatter}. It is not uncommon to see code written along the lines of: *

    * *
      * final String format = "yyyy/MM/dd HH:mm:ss.SSS";
      * try {
    - *     new SimpleDateFormat(format).parse(text);
    + *     DateTimeFormatter.ofPattern(format).parse(text);
      *     return true;
      * } catch (Exception e) {
      *     return false;
    @@ -34,7 +34,7 @@
      *
      * 

    * This approach, however, is frowned upon for two important reasons. Firstly, the performance is poor. A micro-benchmark that involves executing - * the above code (even reusing the SimpleDateFormat object) to evaluate whether or not text is a timestamp took approximately 125-130 seconds + * the above code o evaluate whether or not text is a timestamp took approximately 125-130 seconds * to iterate 1,000,000 times (after discarding the first 1,000,000 iterations as a 'warmup'). As a comparison, this utility takes about 8-11 seconds against * the same data and on the same machine. *

    @@ -46,8 +46,8 @@ *

    * *

    - * Note, however, that this class is not intended to replace SimpleDateFormat, as it does not perform the actual parsing but instead only determines whether or not - * a given input text matches the pattern, so that if it does, a SimpleDateFormat can be used parse the input. + * Note, however, that this class is not intended to replace DateTimeFormatter, as it does not perform the actual parsing but instead only determines whether or not + * a given input text matches the pattern, so that if it does, a DateTimeFormatter can be used parse the input. *

    */ public interface DateTimeMatcher { diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcherCompiler.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcherCompiler.java index 5bf854be2505b..b0215b56b76c4 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcherCompiler.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/DateTimeMatcherCompiler.java @@ -49,8 +49,8 @@ DateTimeMatcher compile(final String format) { matchers.add(regexMatcher); - // Use the SimpleDateFormatMatcher only if our regex matches. This allows us to parse the date only to guarantee that we are correct if we say that the input text matches. - matchers.add(new SimpleDateFormatMatcher(format)); + // Use the DateTimeFormatterMatcher only if our regex matches. This allows us to parse the date only to guarantee that we are correct if we say that the input text matches. + matchers.add(new DateTimeFormatterMatcher(format)); return new ListDateTimeMatcher(matchers); } } diff --git a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/RegexDateTimeMatcher.java b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/RegexDateTimeMatcher.java index 48f07744936b6..8bd27ff1d5fc3 100644 --- a/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/RegexDateTimeMatcher.java +++ b/nifi-commons/nifi-utils/src/main/java/org/apache/nifi/util/text/RegexDateTimeMatcher.java @@ -487,7 +487,7 @@ private void addGeneralTimeZone() { } private String getGMTOffsetTimeZone() { - // From SimpleDateFormat JavaDocs, GMTOffsetTimeZone defined as: GMT Sign Hours : Minutes + // From Date Format JavaDocs, GMTOffsetTimeZone defined as: GMT Sign Hours : Minutes // Sign defined as '-' or '+' // Hours defined as 1 or 2 digits, Minutes defined as 1 or 2 digits // Digit defined as number between 0-9 diff --git a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java index 454b086e2650b..05718393223b0 100644 --- a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java +++ b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/TestFormatUtils.java @@ -25,14 +25,12 @@ import org.junit.jupiter.params.provider.ValueSource; import java.text.DecimalFormatSymbols; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.Arrays; -import java.util.Locale; import java.util.TimeZone; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -404,8 +402,8 @@ private static Stream getFormatDataSize() { @ParameterizedTest @MethodSource("getParseToInstantUsingFormatterWithoutZones") - public void testParseToInstantUsingFormatterWithoutZones(String pattern, String parsedDateTime, String systemDefaultZoneId, String expectedUtcDateTime) throws Exception { - checkSameResultsWithSimpleDateFormat(pattern, parsedDateTime, systemDefaultZoneId, null, expectedUtcDateTime); + public void testParseToInstantUsingFormatterWithoutZones(String pattern, String parsedDateTime, String systemDefaultZoneId, String expectedUtcDateTime) { + checkSameResultsWithFormatter(pattern, parsedDateTime, systemDefaultZoneId, null, expectedUtcDateTime); } private static Stream getParseToInstantUsingFormatterWithoutZones() { @@ -428,8 +426,8 @@ private static Stream getParseToInstantUsingFormatterWithoutZones() { @ParameterizedTest @MethodSource("getParseToInstantUsingFormatterWithZone") - public void testParseToInstantUsingFormatterWithZone(String pattern, String parsedDateTime, String systemDefaultZoneId, String formatZoneId, String expectedUtcDateTime) throws Exception { - checkSameResultsWithSimpleDateFormat(pattern, parsedDateTime, systemDefaultZoneId, formatZoneId, expectedUtcDateTime); + public void testParseToInstantUsingFormatterWithZone(String pattern, String parsedDateTime, String systemDefaultZoneId, String formatZoneId, String expectedUtcDateTime) { + checkSameResultsWithFormatter(pattern, parsedDateTime, systemDefaultZoneId, formatZoneId, expectedUtcDateTime); } private static Stream getParseToInstantUsingFormatterWithZone() { @@ -448,8 +446,8 @@ private static Stream getParseToInstantUsingFormatterWithZone() { @ParameterizedTest @MethodSource("getParseToInstantWithZonePassedInText") - public void testParseToInstantWithZonePassedInText(String pattern, String parsedDateTime, String systemDefaultZoneId, String expectedUtcDateTime) throws Exception { - checkSameResultsWithSimpleDateFormat(pattern, parsedDateTime, systemDefaultZoneId, null, expectedUtcDateTime); + public void testParseToInstantWithZonePassedInText(String pattern, String parsedDateTime, String systemDefaultZoneId, String expectedUtcDateTime) { + checkSameResultsWithFormatter(pattern, parsedDateTime, systemDefaultZoneId, null, expectedUtcDateTime); } private static Stream getParseToInstantWithZonePassedInText() { @@ -465,27 +463,19 @@ private static Stream getParseToInstantWithZonePassedInText() { Arguments.of(pattern, "2020-01-01 02:00:00 +0000", UTC_TIME_ZONE_ID, "2020-01-01T02:00:00")); } - private void checkSameResultsWithSimpleDateFormat(String pattern, String parsedDateTime, String systemDefaultZoneId, String formatZoneId, String expectedUtcDateTime) throws Exception { + private void checkSameResultsWithFormatter(String pattern, String parsedDateTime, String systemDefaultZoneId, String formatZoneId, String expectedUtcDateTime) { TimeZone current = TimeZone.getDefault(); TimeZone.setDefault(TimeZone.getTimeZone(systemDefaultZoneId)); try { - checkSameResultsWithSimpleDateFormat(pattern, parsedDateTime, formatZoneId, expectedUtcDateTime); + checkSameResultsWithFormatter(pattern, parsedDateTime, formatZoneId, expectedUtcDateTime); } finally { TimeZone.setDefault(current); } } - private void checkSameResultsWithSimpleDateFormat(String pattern, String parsedDateTime, String formatterZoneId, String expectedUtcDateTime) throws Exception { + private void checkSameResultsWithFormatter(String pattern, String parsedDateTime, String formatterZoneId, String expectedUtcDateTime) { Instant expectedInstant = LocalDateTime.parse(expectedUtcDateTime).atZone(ZoneOffset.UTC).toInstant(); - // reference implementation - SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.US); - if (formatterZoneId != null) { - sdf.setTimeZone(TimeZone.getTimeZone(formatterZoneId)); - } - Instant simpleDateFormatResult = sdf.parse(parsedDateTime).toInstant(); - assertEquals(expectedInstant, simpleDateFormatResult); - // current implementation DateTimeFormatter dtf = FormatUtils.prepareLenientCaseInsensitiveDateTimeFormatter(pattern); if (formatterZoneId != null) { diff --git a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/text/TestRegexDateTimeMatcher.java b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/text/TestRegexDateTimeMatcher.java index aadc98b07c73a..28e7e5e1a80b4 100644 --- a/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/text/TestRegexDateTimeMatcher.java +++ b/nifi-commons/nifi-utils/src/test/java/org/apache/nifi/util/text/TestRegexDateTimeMatcher.java @@ -45,8 +45,6 @@ public void testCommonFormatsExpectedToPass() { exampleToPattern.put("12 Dec 2018", "dd MMM yyyy"); exampleToPattern.put("12 December 2018", "dd MMM yyyy"); - // TODO: The following examples are taken from the SimpleDateFormat's JavaDoc. Ensure that this is not a licensing concern, - // since it is not being distributed. exampleToPattern.put("2001.07.04 AD at 12:08:56 PDT", "yyyy.MM.dd G 'at' HH:mm:ss z"); exampleToPattern.put("Wed, Jul 4, '01", "EEE, MMM d, ''yy"); exampleToPattern.put("12:08 PM", "h:mm a"); diff --git a/nifi-commons/pom.xml b/nifi-commons/pom.xml index 034b39f12313a..d860e6c8e2f3c 100644 --- a/nifi-commons/pom.xml +++ b/nifi-commons/pom.xml @@ -68,6 +68,7 @@ nifi-single-user-utils nifi-site-to-site-client nifi-socket-utils + nifi-swagger-integration nifi-utils nifi-uuid5 nifi-hashicorp-vault diff --git a/nifi-dependency-check-maven/suppressions.xml b/nifi-dependency-check-maven/suppressions.xml index 8a3b463fea0b1..fa25b9355d1db 100644 --- a/nifi-dependency-check-maven/suppressions.xml +++ b/nifi-dependency-check-maven/suppressions.xml @@ -444,4 +444,19 @@ ^pkg:maven/info\.picocli/picocli@.*$ CVE-2015-0897 + + CVE-2023-36052 applies to Azure CLI not Azure Java libraries + ^pkg:maven/com\.azure/.*$ + CVE-2023-36052 + + + software.amazon.ion:ion-java is newer than com.amazonaws.ion:ion-java and does not share the same vulnerabilities + ^pkg:maven/software\.amazon\.ion/ion\-java@.*$ + cpe:/a:amazon:ion + + + JSON Path 2.9.0 resolves CVE-2023-51074 + ^pkg:maven/com\.jayway\.jsonpath/json\-path@2.9.0$ + CVE-2023-51074 + diff --git a/nifi-docker/dockerhub/sh/start.sh b/nifi-docker/dockerhub/sh/start.sh index 584e55b13a891..8a9b35e3135bd 100755 --- a/nifi-docker/dockerhub/sh/start.sh +++ b/nifi-docker/dockerhub/sh/start.sh @@ -82,6 +82,9 @@ prop_replace 'nifi.analytics.connection.model.implementation' "${NIFI_ANALYTIC prop_replace 'nifi.analytics.connection.model.score.name' "${NIFI_ANALYTICS_MODEL_SCORE_NAME:-rSquared}" prop_replace 'nifi.analytics.connection.model.score.threshold' "${NIFI_ANALYTICS_MODEL_SCORE_THRESHOLD:-.90}" +# Set kubernetes properties +prop_replace 'nifi.cluster.leader.election.kubernetes.lease.prefix' "${NIFI_CLUSTER_LEADER_ELECTION_KUBERNETES_LEASE_PREFIX:-}" + # Add NAR provider properties # nifi-registry NAR provider if [ -n "${NIFI_NAR_LIBRARY_PROVIDER_NIFI_REGISTRY_URL}" ]; then diff --git a/nifi-docker/dockerhub/sh/update_cluster_state_management.sh b/nifi-docker/dockerhub/sh/update_cluster_state_management.sh index 718e52de77687..06879470e58af 100755 --- a/nifi-docker/dockerhub/sh/update_cluster_state_management.sh +++ b/nifi-docker/dockerhub/sh/update_cluster_state_management.sh @@ -28,4 +28,6 @@ edit_property() { } edit_property 'Connect String' "${NIFI_ZK_CONNECT_STRING}" -edit_property "Root Node" "${NIFI_ZK_ROOT_NODE}" \ No newline at end of file +edit_property "Root Node" "${NIFI_ZK_ROOT_NODE}" + +edit_property 'ConfigMap Name Prefix' "${NIFI_KUBERNETES_CONFIGMAP_NAME_PREFIX}" \ No newline at end of file diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc b/nifi-docs/src/main/asciidoc/administration-guide.adoc index 332290f382162..66ac8ef0f2e7e 100644 --- a/nifi-docs/src/main/asciidoc/administration-guide.adoc +++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc @@ -24,7 +24,7 @@ Apache NiFi Team Apache NiFi can run on something as simple as a laptop, but it can also be clustered across many enterprise-class servers. Therefore, the amount of hardware and memory needed will depend on the size and nature of the dataflow involved. The data is stored on disk while NiFi is processing it. So NiFi needs to have sufficient disk space allocated for its various repositories, particularly the content repository, flowfile repository, and provenance repository (see the <> section for more information about these repositories). NiFi has the following minimum system requirements: * Requires Java 21 -* Use of Python-based Processors (beta feature) requires Python 3.9+ +* Use of Python-based Processors (beta feature) requires Python 3.9, 3.10 or 3.11 * Supported Operating Systems: ** Linux ** Unix @@ -159,12 +159,6 @@ Set how long sockets stay in a TIMED_WAIT state when closed:: You don't want your sockets to sit and linger too long given that you want to be able to quickly setup and teardown new sockets. It is a good idea to read more about it and adjust to something like - -for kernel 2.6 ----- -sudo sysctl -w net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait="1" ----- -for kernel 3.0 ---- sudo sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait="1" ---- @@ -237,7 +231,7 @@ The `name` attribute must start with `deprecation`, followed by the component cl NiFi is a Java-based application. NiFi 2.0 introduces support for a Python-based Processor API. This capability is still considered to be in "Beta" mode and should not be used in production. By default, support for Python-based Processors is disabled. In order to enable it, -Python 3.9+ must be installed on the NiFi node. +Python 3.9, 3.10 or 3.11 must be installed on the NiFi node (Python 3.12 is not supported yet). The following properties may be used to configure the Python 3 installation and process management. These properties are all located under the "Python Extensions" heading in the _nifi.properties_ file: diff --git a/nifi-docs/src/main/asciidoc/python-developer-guide.adoc b/nifi-docs/src/main/asciidoc/python-developer-guide.adoc index 415b2f0ba4f21..d610c482a673d 100644 --- a/nifi-docs/src/main/asciidoc/python-developer-guide.adoc +++ b/nifi-docs/src/main/asciidoc/python-developer-guide.adoc @@ -315,7 +315,7 @@ class PrettyPrintJson(FlowFileTransform): numspaces = PropertyDescriptor(name="Number of Spaces", description="Number of spaces to use for pretty-printing", validators=[StandardValidators.POSITIVE_INTEGER_VALIDATOR], - defaultValue="4", + default_value="4", required=True) self.descriptors = [numspaces] @@ -424,10 +424,92 @@ that there are no longer any invocations of the `transform` method running when +[[documenting_use_cases]] +== Documenting Use Cases + +No matter how powerful a piece of software is, it has no value unless people are able to use it. To that end, documentation of Processors is +very important. While a description of the Processor should be provided in the `ProcessorDetails` class and each PropertyDescriptor is expected to have a description, +it is usually helpful to also call out specific use cases that can be performed by the Processor. This is particularly important for Processors that perform +more generalized transformations on objects, where a single Processor may be capable of performing multiple tasks, based on its configuration. + +[[use_case_decorator]] +=== The `@use_case` Decorator + +The `@use_case` decorator, defined in the `nifiapi.documentation` module can facilitate this. The decorator takes four arguments: + +- `description`: A simple 1 (at most 2) sentence description of the use case. Generally, this should not include any extraneous details, + such as caveats, etc. Those can be provided using the `notes` argument. The description is required. +- `notes`: Most of the time, 1-2 sentences is sufficient to describe a use case. Those 1-2 sentence should then be returned + by the `description`. In the event that the description is not sufficient, details may be provided to + further explain, by providing caveats, etc. This is optional. +- `keywords`: An array of keywords that can be associated with the use case. This is optional. +- `configuration`: A description of how to configure the Processor for this particular use case. This may include explicit values to set for some properties, + and may include instructions on how to choose the appropriate value for other properties. The configuration is required. + +A single Processor may have multiple `@use_case` decorators. + + +[[multi_processor_use_case_decorator]] +=== The `@multi_processor_use_case` Decorator + +When designing and creating Processors, it is important to keep in mind the idea of loose coupling. One Processor should not be dependent on another Processor +in order to perform its task. That being said, it is often advantageous to build Processors that are designed to work well together. For example, a Processor that +is able to perform a listing of files in a directory can provide an important capability in and of itself. Similarly, a Processor that is able to ingest the contents +of a specific file and make that file's contents the contents of a FlowFile is also an important capability in and of itself. But far more powerful than either of these +individual capabilities is the notion of being able to compose a flow that lists all files in a directory and then ingests each of those files as a FlowFile. This is +done by using a combination of the two. As such, it is important that the two Processors be able to work together in such a way that the output of the first is +easily understood as the input of the second. + +In this case, it makes sense to document this composition of Processors as a use case so that users can understand how to compose such a pipeline. This is accomplished +by using the `@multi_processor_use_case` decorator. This decorator is very similar to the <> but instead of a `configuration` element, it has a +`configurations` element, which is a `list` of `ProcessorConfiguration` objects, where each `ProcessorConfiguration` object has both a `processor_type`, which is the +name of the Processor, and a `configuration` that explains how to configure that particular Processor. The `configuration` element typically also explains how to connect +outbound Relationships. + +For example, we might use these decorators as such: +---- +@use_case(description="Retrieve the contents of a given file on disk and create a FlowFile from it without modifying the file", + keywords=["file", "filesystem"], + configuration=""" + Set the 'Filename' property to the fully qualified path of the file to ingest + Set the 'Completion Strategy' to 'None' + """) +@use_case(description="Retrieve the contents of a given file on disk and create a FlowFile from it, deleting the local file upon success", + keywords=["file", "filesystem"], + configuration=""" + Set the 'Filename' property to the fully qualified path of the file to ingest + Set the 'Completion Strategy' to 'Delete' + """) +@multi_processor_use_case( + description="Ingest all files from a landing directory on the filesystem and delete them after ingesting them.", + keywords=["file", "filesystem", "landing directory"], + configurations=[ + ProcessorConfiguration( + processor_type="org.apache.nifi.processors.standard.ListFile", + configuration=""" + Set 'Input Directory' to the directory that files should be ingested from + Set 'Input Directory Location' to 'Local' + """ + ), + ProcessorConfiguration( + processor_type="FetchFile", + configuration=""" + Set the 'Filename' property to `${absolute.path}/${filename}` + Set the 'Completion Strategy' to 'Delete' + """ + ) + ]) +class FetchFile(FlowFileTransform): +---- + +Note that in this case, we are able to specifically tell the user that the Filename property of FetchFile should be set to the value `${absolute.path}/${filename}` +because we know that the ListFile Processor will produce these attributes for us. + + [[requirements]] == Requirements -The Python API requires that Python 3.9+ is available on the machine hosting NiFi. +The Python API requires that Python 3.9, 3.10 or 3.11 is available on the machine hosting NiFi (Python 3.12 is not supported yet). Each Processor may have its own list of requirements / dependencies. These are made available to the Processor by creating a separate environment for each Processor implementation (not for each instance of a Processor on the canvas). PyPI is then used to install these diff --git a/nifi-docs/src/main/asciidoc/record-path-guide.adoc b/nifi-docs/src/main/asciidoc/record-path-guide.adoc index 864dbcbfb80a6..a4d0323c4cb30 100644 --- a/nifi-docs/src/main/asciidoc/record-path-guide.adoc +++ b/nifi-docs/src/main/asciidoc/record-path-guide.adoc @@ -640,7 +640,7 @@ Converts a Date to a String in the given format with an optional time zone. The time zone when the second argument is not provided. The first argument to this function must be a Date or a Number, and the second argument must be a format String that -follows the Java SimpleDateFormat, and the third argument, optional, must be a format String that +follows the Java DateTimeFormatter, and the third argument, optional, must be a format String that either an abbreviation such as "PST", a full name such as "America/Los_Angeles", or a custom ID such as "GMT-8:00" For example, given a schema such as: diff --git a/nifi-external/nifi-kafka-connect/nifi-kafka-connector-assembly/pom.xml b/nifi-external/nifi-kafka-connect/nifi-kafka-connector-assembly/pom.xml index 488202b15cb9a..f7bd45370a0b9 100644 --- a/nifi-external/nifi-kafka-connect/nifi-kafka-connector-assembly/pom.xml +++ b/nifi-external/nifi-kafka-connect/nifi-kafka-connector-assembly/pom.xml @@ -45,17 +45,6 @@ 2.0.0-SNAPSHOT - - - jakarta.servlet - jakarta.servlet-api - compile - - - org.eclipse.jetty.toolchain - jetty-schemas - compile - org.slf4j slf4j-api diff --git a/nifi-external/nifi-kafka-connect/nifi-kafka-connector/pom.xml b/nifi-external/nifi-kafka-connect/nifi-kafka-connector/pom.xml index 77a70a5f8ba37..6632c22bfec8b 100644 --- a/nifi-external/nifi-kafka-connect/nifi-kafka-connector/pom.xml +++ b/nifi-external/nifi-kafka-connect/nifi-kafka-connector/pom.xml @@ -51,17 +51,6 @@ 2.0.0-SNAPSHOT - - - jakarta.servlet - jakarta.servlet-api - compile - - - org.eclipse.jetty.toolchain - jetty-schemas - compile - org.slf4j slf4j-api diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/bundle/BundleDetails.java b/nifi-framework-api/src/main/java/org/apache/nifi/bundle/BundleDetails.java index c1f2117f77867..28be25a94d0ec 100644 --- a/nifi-framework-api/src/main/java/org/apache/nifi/bundle/BundleDetails.java +++ b/nifi-framework-api/src/main/java/org/apache/nifi/bundle/BundleDetails.java @@ -17,8 +17,9 @@ package org.apache.nifi.bundle; import java.io.File; -import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Date; /** @@ -107,10 +108,9 @@ public String toString() { public Date getBuildTimestampDate() { if (buildTimestamp != null && !buildTimestamp.isEmpty()) { try { - SimpleDateFormat buildTimestampFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - Date buildTimestampDate = buildTimestampFormat.parse(buildTimestamp); - return buildTimestampDate; - } catch (ParseException parseEx) { + final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"); + return Date.from(OffsetDateTime.parse(buildTimestamp, dateTimeFormatter).toInstant()); + } catch (DateTimeParseException e) { return null; } } else { diff --git a/nifi-manifest/nifi-extension-manifest-model/pom.xml b/nifi-manifest/nifi-extension-manifest-model/pom.xml index 706d9ab68692a..2087ca6860f16 100644 --- a/nifi-manifest/nifi-extension-manifest-model/pom.xml +++ b/nifi-manifest/nifi-extension-manifest-model/pom.xml @@ -25,7 +25,7 @@ - io.swagger + io.swagger.core.v3 swagger-annotations diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/AllowableValue.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/AllowableValue.java index 02efeb28b61bc..cb927b357280f 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/AllowableValue.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/AllowableValue.java @@ -16,13 +16,13 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; + +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel + @XmlAccessorType(XmlAccessType.FIELD) public class AllowableValue { @@ -30,7 +30,7 @@ public class AllowableValue { private String displayName; private String description; - @ApiModelProperty(value = "The value of the allowable value") + @Schema(description = "The value of the allowable value") public String getValue() { return value; } @@ -39,7 +39,7 @@ public void setValue(String value) { this.value = value; } - @ApiModelProperty(value = "The display name of the allowable value") + @Schema(description = "The display name of the allowable value") public String getDisplayName() { return displayName; } @@ -48,7 +48,7 @@ public void setDisplayName(String displayName) { this.displayName = displayName; } - @ApiModelProperty(value = "The description of the allowable value") + @Schema(description = "The description of the allowable value") public String getDescription() { return description; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Attribute.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Attribute.java index 0f900ee94f96c..82ee5f06b0d00 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Attribute.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Attribute.java @@ -16,20 +16,18 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Attribute { private String name; private String description; - @ApiModelProperty(value = "The name of the attribute") + @Schema(description = "The name of the attribute") public String getName() { return name; } @@ -38,7 +36,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the attribute") + @Schema(description = "The description of the attribute") public String getDescription() { return description; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/BuildInfo.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/BuildInfo.java index d884603bd6da8..a4f8774d73095 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/BuildInfo.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/BuildInfo.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class BuildInfo { @@ -33,7 +31,7 @@ public class BuildInfo { private String builtBy; private String timestamp; - @ApiModelProperty(value = "The tag the NAR was built from") + @Schema(description = "The tag the NAR was built from") public String getTag() { return tag; } @@ -42,7 +40,7 @@ public void setTag(String tag) { this.tag = tag; } - @ApiModelProperty(value = "The branch the NAR was built from") + @Schema(description = "The branch the NAR was built from") public String getBranch() { return branch; } @@ -51,7 +49,7 @@ public void setBranch(String branch) { this.branch = branch; } - @ApiModelProperty(value = "The revision the NAR was built from") + @Schema(description = "The revision the NAR was built from") public String getRevision() { return revision; } @@ -60,7 +58,7 @@ public void setRevision(String revision) { this.revision = revision; } - @ApiModelProperty(value = "The JDK the NAR was built with") + @Schema(description = "The JDK the NAR was built with") public String getJdk() { return jdk; } @@ -69,7 +67,7 @@ public void setJdk(String jdk) { this.jdk = jdk; } - @ApiModelProperty(value = "The OS user that performed the build") + @Schema(description = "The OS user that performed the build") public String getBuiltBy() { return builtBy; } @@ -78,7 +76,7 @@ public void setBuiltBy(String builtBy) { this.builtBy = builtBy; } - @ApiModelProperty(value = "The timestamp of the build") + @Schema(description = "The timestamp of the build") public String getTimestamp() { return timestamp; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Cardinality.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Cardinality.java index 0b0966e2f3f26..5b0b2d5a2c043 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Cardinality.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Cardinality.java @@ -16,9 +16,6 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - -@ApiModel public enum Cardinality { /** diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ControllerServiceDefinition.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ControllerServiceDefinition.java index c6670d1c7676f..37c623f8e82b0 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ControllerServiceDefinition.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ControllerServiceDefinition.java @@ -16,14 +16,12 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import java.util.Objects; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class ControllerServiceDefinition { @@ -32,7 +30,7 @@ public class ControllerServiceDefinition { private String artifactId; private String version; - @ApiModelProperty(value = "The class name of the service API") + @Schema(description = "The class name of the service API") public String getClassName() { return className; } @@ -41,7 +39,7 @@ public void setClassName(String className) { this.className = className; } - @ApiModelProperty(value = "The group id of the service API") + @Schema(description = "The group id of the service API") public String getGroupId() { return groupId; } @@ -50,7 +48,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty(value = "The artifact id of the service API") + @Schema(description = "The artifact id of the service API") public String getArtifactId() { return artifactId; } @@ -59,7 +57,7 @@ public void setArtifactId(String artifactId) { this.artifactId = artifactId; } - @ApiModelProperty(value = "The version of the service API") + @Schema(description = "The version of the service API") public String getVersion() { return version; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSchedule.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSchedule.java index 8cd79aae5443b..6609ccc48b6e9 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSchedule.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSchedule.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class DefaultSchedule { @@ -30,7 +28,7 @@ public class DefaultSchedule { private String period; private String concurrentTasks; - @ApiModelProperty("The default scheduling strategy") + @Schema(description = "The default scheduling strategy") public String getStrategy() { return strategy; } @@ -39,7 +37,7 @@ public void setStrategy(String strategy) { this.strategy = strategy; } - @ApiModelProperty("The default scheduling period") + @Schema(description = "The default scheduling period") public String getPeriod() { return period; } @@ -48,7 +46,7 @@ public void setPeriod(String period) { this.period = period; } - @ApiModelProperty("The default concurrent tasks") + @Schema(description = "The default concurrent tasks") public String getConcurrentTasks() { return concurrentTasks; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSettings.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSettings.java index a7b97998965ec..d4cf2ce0a0a55 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSettings.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DefaultSettings.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class DefaultSettings { @@ -30,7 +28,7 @@ public class DefaultSettings { private String penaltyDuration; private String bulletinLevel; - @ApiModelProperty("The default yield duration") + @Schema(description = "The default yield duration") public String getYieldDuration() { return yieldDuration; } @@ -39,7 +37,7 @@ public void setYieldDuration(String yieldDuration) { this.yieldDuration = yieldDuration; } - @ApiModelProperty("The default penalty duration") + @Schema(description = "The default penalty duration") public String getPenaltyDuration() { return penaltyDuration; } @@ -48,7 +46,7 @@ public void setPenaltyDuration(String penaltyDuration) { this.penaltyDuration = penaltyDuration; } - @ApiModelProperty("The default bulletin level") + @Schema(description = "The default bulletin level") public String getBulletinLevel() { return bulletinLevel; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Dependency.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Dependency.java index fce50f5737270..04aee18590a2f 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Dependency.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Dependency.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Dependency { @@ -30,7 +28,7 @@ public class Dependency { private String propertyDisplayName; private DependentValues dependentValues; - @ApiModelProperty(value = "The name of the dependent property") + @Schema(description = "The name of the dependent property") public String getPropertyName() { return propertyName; } @@ -39,7 +37,7 @@ public void setPropertyName(String propertyName) { this.propertyName = propertyName; } - @ApiModelProperty(value = "The display name of the dependent property") + @Schema(description = "The display name of the dependent property") public String getPropertyDisplayName() { return propertyDisplayName; } @@ -48,7 +46,7 @@ public void setPropertyDisplayName(String propertyDisplayName) { this.propertyDisplayName = propertyDisplayName; } - @ApiModelProperty(value = "The values of the dependent property that enable the depending property") + @Schema(description = "The values of the dependent property that enable the depending property") public DependentValues getDependentValues() { return dependentValues; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DependentValues.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DependentValues.java index 0e88780ba6c91..bb13b126eb084 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DependentValues.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DependentValues.java @@ -16,22 +16,20 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class DependentValues { @XmlElement(name = "dependentValue") private List values; - @ApiModelProperty(value = "The dependent values") + @Schema(description = "The dependent values") public List getValues() { return values; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DeprecationNotice.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DeprecationNotice.java index dbffb6a06ce46..3b271cc01f1fc 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DeprecationNotice.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DeprecationNotice.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; @@ -25,7 +24,6 @@ import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class DeprecationNotice { @@ -35,7 +33,7 @@ public class DeprecationNotice { @XmlElement(name = "alternative") private List alternatives; - @ApiModelProperty(value = "The reason for the deprecation") + @Schema(description = "The reason for the deprecation") public String getReason() { return reason; } @@ -44,7 +42,7 @@ public void setReason(String reason) { this.reason = reason; } - @ApiModelProperty(value = "The alternatives to use") + @Schema(description = "The alternatives to use") public List getAlternatives() { return alternatives; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicProperty.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicProperty.java index 9de143aa1f8d9..a049c95e40cbb 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicProperty.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicProperty.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class DynamicProperty { @@ -32,7 +30,7 @@ public class DynamicProperty { private ExpressionLanguageScope expressionLanguageScope; private boolean expressionLanguageSupported; - @ApiModelProperty(value = "The description of the dynamic property name") + @Schema(description = "The description of the dynamic property name") public String getName() { return name; } @@ -41,7 +39,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the dynamic property value") + @Schema(description = "The description of the dynamic property value") public String getValue() { return value; } @@ -50,7 +48,7 @@ public void setValue(String value) { this.value = value; } - @ApiModelProperty(value = "The description of the dynamic property") + @Schema(description = "The description of the dynamic property") public String getDescription() { return description; } @@ -59,7 +57,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "Whether or not expression language is supported") + @Schema(description = "Whether or not expression language is supported") public boolean isExpressionLanguageSupported() { return expressionLanguageSupported; } @@ -68,7 +66,7 @@ public void setExpressionLanguageSupported(boolean expressionLanguageSupported) this.expressionLanguageSupported = expressionLanguageSupported; } - @ApiModelProperty(value = "The scope of the expression language support") + @Schema(description = "The scope of the expression language support") public ExpressionLanguageScope getExpressionLanguageScope() { return expressionLanguageScope; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicRelationship.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicRelationship.java index bbf75010006df..92185cdaf2fb0 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicRelationship.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/DynamicRelationship.java @@ -16,20 +16,20 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; + +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel + @XmlAccessorType(XmlAccessType.FIELD) public class DynamicRelationship { private String name; private String description; - @ApiModelProperty(value = "The description of the dynamic relationship name") + @Schema(description = "The description of the dynamic relationship name") public String getName() { return name; } @@ -38,7 +38,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the dynamic relationship") + @Schema(description = "The description of the dynamic relationship") public String getDescription() { return description; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExpressionLanguageScope.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExpressionLanguageScope.java index c713724d7d46e..9d2e6daca6d4a 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExpressionLanguageScope.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExpressionLanguageScope.java @@ -16,9 +16,6 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - -@ApiModel public enum ExpressionLanguageScope { /** diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Extension.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Extension.java index a0b2a380dd2ad..3459efd49185d 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Extension.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Extension.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.Valid; import jakarta.xml.bind.annotation.XmlAccessType; @@ -27,7 +26,6 @@ import java.util.List; import java.util.Objects; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Extension { @@ -109,7 +107,7 @@ public class Extension { @XmlElement(name = "multiProcessorUseCase") private List multiProcessorUseCases; - @ApiModelProperty(value = "The name of the extension") + @Schema(description = "The name of the extension") public String getName() { return name; } @@ -118,7 +116,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The type of the extension") + @Schema(description = "The type of the extension") public ExtensionType getType() { return type; } @@ -127,7 +125,7 @@ public void setType(ExtensionType type) { this.type = type; } - @ApiModelProperty(value = "The deprecation notice of the extension") + @Schema(description = "The deprecation notice of the extension") public DeprecationNotice getDeprecationNotice() { return deprecationNotice; } @@ -136,7 +134,7 @@ public void setDeprecationNotice(DeprecationNotice deprecationNotice) { this.deprecationNotice = deprecationNotice; } - @ApiModelProperty(value = "The description of the extension") + @Schema(description = "The description of the extension") public String getDescription() { return description; } @@ -145,7 +143,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "The tags of the extension") + @Schema(description = "The tags of the extension") public List getTags() { return tags; } @@ -154,7 +152,7 @@ public void setTags(List tags) { this.tags = tags; } - @ApiModelProperty(value = "The properties of the extension") + @Schema(description = "The properties of the extension") public List getProperties() { return properties; } @@ -171,7 +169,7 @@ public void setSupportsSensitiveDynamicProperties(boolean supportsSensitiveDynam this.supportsSensitiveDynamicProperties = supportsSensitiveDynamicProperties; } - @ApiModelProperty(value = "The dynamic properties of the extension") + @Schema(description = "The dynamic properties of the extension") public List getDynamicProperties() { return dynamicProperties; } @@ -180,7 +178,7 @@ public void setDynamicProperties(List dynamicProperties) { this.dynamicProperties = dynamicProperties; } - @ApiModelProperty(value = "The relationships of the extension") + @Schema(description = "The relationships of the extension") public List getRelationships() { return relationships; } @@ -189,7 +187,7 @@ public void setRelationships(List relationships) { this.relationships = relationships; } - @ApiModelProperty(value = "The dynamic relationships of the extension") + @Schema(description = "The dynamic relationships of the extension") public DynamicRelationship getDynamicRelationship() { return dynamicRelationship; } @@ -198,7 +196,7 @@ public void setDynamicRelationship(DynamicRelationship dynamicRelationship) { this.dynamicRelationship = dynamicRelationship; } - @ApiModelProperty(value = "The attributes read from flow files by the extension") + @Schema(description = "The attributes read from flow files by the extension") public List getReadsAttributes() { return readsAttributes; } @@ -207,7 +205,7 @@ public void setReadsAttributes(List readsAttributes) { this.readsAttributes = readsAttributes; } - @ApiModelProperty(value = "The attributes written to flow files by the extension") + @Schema(description = "The attributes written to flow files by the extension") public List getWritesAttributes() { return writesAttributes; } @@ -216,7 +214,7 @@ public void setWritesAttributes(List writesAttributes) { this.writesAttributes = writesAttributes; } - @ApiModelProperty(value = "The information about how the extension stores state") + @Schema(description = "The information about how the extension stores state") public Stateful getStateful() { return stateful; } @@ -225,7 +223,7 @@ public void setStateful(Stateful stateful) { this.stateful = stateful; } - @ApiModelProperty(value = "The restrictions of the extension") + @Schema(description = "The restrictions of the extension") public Restricted getRestricted() { return restricted; } @@ -234,7 +232,7 @@ public void setRestricted(Restricted restricted) { this.restricted = restricted; } - @ApiModelProperty(value = "The input requirement of the extension") + @Schema(description = "The input requirement of the extension") public InputRequirement getInputRequirement() { return inputRequirement; } @@ -243,7 +241,7 @@ public void setInputRequirement(InputRequirement inputRequirement) { this.inputRequirement = inputRequirement; } - @ApiModelProperty(value = "The resource considerations of the extension") + @Schema(description = "The resource considerations of the extension") public List getSystemResourceConsiderations() { return systemResourceConsiderations; } @@ -252,7 +250,7 @@ public void setSystemResourceConsiderations(List sy this.systemResourceConsiderations = systemResourceConsiderations; } - @ApiModelProperty(value = "The names of other extensions to see") + @Schema(description = "The names of other extensions to see") public List getSeeAlso() { return seeAlso; } @@ -261,7 +259,7 @@ public void setSeeAlso(List seeAlso) { this.seeAlso = seeAlso; } - @ApiModelProperty(value = "The service APIs provided by this extension") + @Schema(description = "The service APIs provided by this extension") public List getProvidedServiceAPIs() { return providedServiceAPIs; } @@ -270,7 +268,7 @@ public void setProvidedServiceAPIs(List providedServiceAPIs) this.providedServiceAPIs = providedServiceAPIs; } - @ApiModelProperty(value = "The default settings for a processor") + @Schema(description = "The default settings for a processor") public DefaultSettings getDefaultSettings() { return defaultSettings; } @@ -279,7 +277,7 @@ public void setDefaultSettings(DefaultSettings defaultSettings) { this.defaultSettings = defaultSettings; } - @ApiModelProperty(value = "The default schedule for a processor reporting task") + @Schema(description = "The default schedule for a processor reporting task") public DefaultSchedule getDefaultSchedule() { return defaultSchedule; } @@ -288,7 +286,7 @@ public void setDefaultSchedule(DefaultSchedule defaultSchedule) { this.defaultSchedule = defaultSchedule; } - @ApiModelProperty(value = "Indicates that a processor should be triggered serially") + @Schema(description = "Indicates that a processor should be triggered serially") public boolean getTriggerSerially() { return triggerSerially; } @@ -297,7 +295,7 @@ public void setTriggerSerially(boolean triggerSerially) { this.triggerSerially = triggerSerially; } - @ApiModelProperty(value = "Indicates that a processor should be triggered when the incoming queues are empty") + @Schema(description = "Indicates that a processor should be triggered when the incoming queues are empty") public boolean getTriggerWhenEmpty() { return triggerWhenEmpty; } @@ -306,7 +304,7 @@ public void setTriggerWhenEmpty(boolean triggerWhenEmpty) { this.triggerWhenEmpty = triggerWhenEmpty; } - @ApiModelProperty(value = "Indicates that a processor should be triggered when any destinations have space for flow files") + @Schema(description = "Indicates that a processor should be triggered when any destinations have space for flow files") public boolean getTriggerWhenAnyDestinationAvailable() { return triggerWhenAnyDestinationAvailable; } @@ -315,7 +313,7 @@ public void setTriggerWhenAnyDestinationAvailable(boolean triggerWhenAnyDestinat this.triggerWhenAnyDestinationAvailable = triggerWhenAnyDestinationAvailable; } - @ApiModelProperty(value = "Indicates that a processor supports batching") + @Schema(description = "Indicates that a processor supports batching") public boolean getSupportsBatching() { return supportsBatching; } @@ -324,7 +322,7 @@ public void setSupportsBatching(boolean supportsBatching) { this.supportsBatching = supportsBatching; } - @ApiModelProperty(value = "Indicates that a processor should be scheduled only on the primary node") + @Schema(description = "Indicates that a processor should be scheduled only on the primary node") public boolean getPrimaryNodeOnly() { return primaryNodeOnly; } @@ -333,7 +331,7 @@ public void setPrimaryNodeOnly(boolean primaryNodeOnly) { this.primaryNodeOnly = primaryNodeOnly; } - @ApiModelProperty(value = "Indicates that a processor is side effect free") + @Schema(description = "Indicates that a processor is side effect free") public boolean getSideEffectFree() { return sideEffectFree; } @@ -342,7 +340,7 @@ public void setSideEffectFree(boolean sideEffectFree) { this.sideEffectFree = sideEffectFree; } - @ApiModelProperty(value = "Zero or more documented use cases for how the extension may be used") + @Schema(description = "Zero or more documented use cases for how the extension may be used") public List getUseCases() { return useCases; } @@ -351,7 +349,7 @@ public void setUseCases(final List useCases) { this.useCases = useCases; } - @ApiModelProperty(value = "Zero or more documented use cases for how the processor may be used in conjunction with other processors") + @Schema(description = "Zero or more documented use cases for how the processor may be used in conjunction with other processors") public List getMultiProcessorUseCases() { return multiProcessorUseCases; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExtensionManifest.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExtensionManifest.java index 70dffed57518f..a4c924d25617b 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExtensionManifest.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ExtensionManifest.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; @@ -26,7 +25,6 @@ import jakarta.xml.bind.annotation.XmlRootElement; import java.util.List; -@ApiModel @XmlRootElement(name = "extensionManifest") @XmlAccessorType(XmlAccessType.FIELD) public class ExtensionManifest { @@ -54,7 +52,7 @@ public ExtensionManifest(String systemApiVersion, List extensions) { this.extensions = extensions; } - @ApiModelProperty(value = "The group id of this NAR") + @Schema(description = "The group id of this NAR") public String getGroupId() { return groupId; } @@ -63,7 +61,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty(value = "The artifact id of this NAR") + @Schema(description = "The artifact id of this NAR") public String getArtifactId() { return artifactId; } @@ -72,7 +70,7 @@ public void setArtifactId(String artifactId) { this.artifactId = artifactId; } - @ApiModelProperty(value = "The version of this NAR") + @Schema(description = "The version of this NAR") public String getVersion() { return version; } @@ -81,7 +79,7 @@ public void setVersion(String version) { this.version = version; } - @ApiModelProperty(value = "The info for the parent NAR of this NAR") + @Schema(description = "The info for the parent NAR of this NAR") public ParentNar getParentNar() { return parentNar; } @@ -90,7 +88,7 @@ public void setParentNar(ParentNar parentNar) { this.parentNar = parentNar; } - @ApiModelProperty(value = "The version of nifi-api this NAR was built against") + @Schema(description = "The version of nifi-api this NAR was built against") public String getSystemApiVersion() { return systemApiVersion; } @@ -99,7 +97,7 @@ public void setSystemApiVersion(String systemApiVersion) { this.systemApiVersion = systemApiVersion; } - @ApiModelProperty(value = "The build info for the NAR") + @Schema(description = "The build info for the NAR") public BuildInfo getBuildInfo() { return buildInfo; } @@ -108,7 +106,7 @@ public void setBuildInfo(BuildInfo buildInfo) { this.buildInfo = buildInfo; } - @ApiModelProperty(value = "The list of extensions contained in this NAR") + @Schema(description = "The list of extensions contained in this NAR") public List getExtensions() { return extensions; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/InputRequirement.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/InputRequirement.java index 51cd7d3c254b5..15e038c2861c6 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/InputRequirement.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/InputRequirement.java @@ -16,9 +16,6 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - -@ApiModel public enum InputRequirement { /** diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/MultiProcessorUseCase.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/MultiProcessorUseCase.java index 2fdd2b2c6a18a..dfdec5bb1f2a9 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/MultiProcessorUseCase.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/MultiProcessorUseCase.java @@ -17,15 +17,12 @@ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class MultiProcessorUseCase { private String description; diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ParentNar.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ParentNar.java index a86c44e7f61b8..8ffcd7eb16744 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ParentNar.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ParentNar.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class ParentNar { @@ -30,7 +28,7 @@ public class ParentNar { private String artifactId; private String version; - @ApiModelProperty(value = "The group id of the parent NAR") + @Schema(description = "The group id of the parent NAR") public String getGroupId() { return groupId; } @@ -39,7 +37,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty(value = "The artifact id of the parent NAR") + @Schema(description = "The artifact id of the parent NAR") public String getArtifactId() { return artifactId; } @@ -48,7 +46,7 @@ public void setArtifactId(String artifactId) { this.artifactId = artifactId; } - @ApiModelProperty(value = "The version of the parent NAR") + @Schema(description = "The version of the parent NAR") public String getVersion() { return version; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProcessorConfiguration.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProcessorConfiguration.java index 0f9b118b3e4b7..5125a8e139a7a 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProcessorConfiguration.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProcessorConfiguration.java @@ -17,9 +17,6 @@ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - -@ApiModel public class ProcessorConfiguration { private String processorClassName; private String configuration; diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Property.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Property.java index 6f97a4f6296b3..acd5739c968ac 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Property.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Property.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; @@ -25,7 +24,6 @@ import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Property { @@ -54,7 +52,7 @@ public class Property { private ResourceDefinition resourceDefinition; - @ApiModelProperty(value = "The name of the property") + @Schema(description = "The name of the property") public String getName() { return name; } @@ -63,7 +61,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The display name") + @Schema(description = "The display name") public String getDisplayName() { return displayName; } @@ -72,7 +70,7 @@ public void setDisplayName(String displayName) { this.displayName = displayName; } - @ApiModelProperty(value = "The description") + @Schema(description = "The description") public String getDescription() { return description; } @@ -81,7 +79,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "The default value") + @Schema(description = "The default value") public String getDefaultValue() { return defaultValue; } @@ -90,7 +88,7 @@ public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } - @ApiModelProperty(value = "The controller service required by this property, or null if none is required") + @Schema(description = "The controller service required by this property, or null if none is required") public ControllerServiceDefinition getControllerServiceDefinition() { return controllerServiceDefinition; } @@ -99,7 +97,7 @@ public void setControllerServiceDefinition(ControllerServiceDefinition controlle this.controllerServiceDefinition = controllerServiceDefinition; } - @ApiModelProperty(value = "The allowable values for this property") + @Schema(description = "The allowable values for this property") public List getAllowableValues() { return allowableValues; } @@ -108,7 +106,7 @@ public void setAllowableValues(List allowableValues) { this.allowableValues = allowableValues; } - @ApiModelProperty(value = "Whether or not the property is required") + @Schema(description = "Whether or not the property is required") public boolean isRequired() { return required; } @@ -117,7 +115,7 @@ public void setRequired(boolean required) { this.required = required; } - @ApiModelProperty(value = "Whether or not the property is sensitive") + @Schema(description = "Whether or not the property is sensitive") public boolean isSensitive() { return sensitive; } @@ -126,7 +124,7 @@ public void setSensitive(boolean sensitive) { this.sensitive = sensitive; } - @ApiModelProperty(value = "Whether or not expression language is supported") + @Schema(description = "Whether or not expression language is supported") public boolean isExpressionLanguageSupported() { return expressionLanguageSupported; } @@ -135,7 +133,7 @@ public void setExpressionLanguageSupported(boolean expressionLanguageSupported) this.expressionLanguageSupported = expressionLanguageSupported; } - @ApiModelProperty(value = "The scope of expression language support") + @Schema(description = "The scope of expression language support") public ExpressionLanguageScope getExpressionLanguageScope() { return expressionLanguageScope; } @@ -144,7 +142,7 @@ public void setExpressionLanguageScope(ExpressionLanguageScope expressionLanguag this.expressionLanguageScope = expressionLanguageScope; } - @ApiModelProperty(value = "Whether or not the processor dynamically modifies the classpath") + @Schema(description = "Whether or not the processor dynamically modifies the classpath") public boolean isDynamicallyModifiesClasspath() { return dynamicallyModifiesClasspath; } @@ -153,7 +151,7 @@ public void setDynamicallyModifiesClasspath(boolean dynamicallyModifiesClasspath this.dynamicallyModifiesClasspath = dynamicallyModifiesClasspath; } - @ApiModelProperty(value = "Whether or not the processor is dynamic") + @Schema(description = "Whether or not the processor is dynamic") public boolean isDynamic() { return dynamic; } @@ -162,7 +160,7 @@ public void setDynamic(boolean dynamic) { this.dynamic = dynamic; } - @ApiModelProperty(value = "The properties that this property depends on") + @Schema(description = "The properties that this property depends on") public List getDependencies() { return dependencies; } @@ -171,7 +169,7 @@ public void setDependencies(List dependencies) { this.dependencies = dependencies; } - @ApiModelProperty(value = "The optional resource definition") + @Schema(description = "The optional resource definition") public ResourceDefinition getResourceDefinition() { return resourceDefinition; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProvidedServiceAPI.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProvidedServiceAPI.java index 06a98105fdf1a..a92216cecbc50 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProvidedServiceAPI.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ProvidedServiceAPI.java @@ -16,15 +16,13 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.constraints.NotBlank; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import java.util.Objects; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class ProvidedServiceAPI { @@ -37,7 +35,7 @@ public class ProvidedServiceAPI { @NotBlank private String version; - @ApiModelProperty(value = "The class name of the service API being provided") + @Schema(description = "The class name of the service API being provided") public String getClassName() { return className; } @@ -46,7 +44,7 @@ public void setClassName(String className) { this.className = className; } - @ApiModelProperty(value = "The group id of the service API being provided") + @Schema(description = "The group id of the service API being provided") public String getGroupId() { return groupId; } @@ -55,7 +53,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty(value = "The artifact id of the service API being provided") + @Schema(description = "The artifact id of the service API being provided") public String getArtifactId() { return artifactId; } @@ -64,7 +62,7 @@ public void setArtifactId(String artifactId) { this.artifactId = artifactId; } - @ApiModelProperty(value = "The version of the service API being provided") + @Schema(description = "The version of the service API being provided") public String getVersion() { return version; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Relationship.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Relationship.java index 576a6c8c76732..80f45ccc0f0c0 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Relationship.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Relationship.java @@ -16,13 +16,11 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Relationship { @@ -30,7 +28,7 @@ public class Relationship { private String description; private boolean autoTerminated; - @ApiModelProperty(value = "The name of the relationship") + @Schema(description = "The name of the relationship") public String getName() { return name; } @@ -39,7 +37,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(value = "The description of the relationship") + @Schema(description = "The description of the relationship") public String getDescription() { return description; } @@ -48,7 +46,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "Whether or not the relationship is auto-terminated by default") + @Schema(description = "Whether or not the relationship is auto-terminated by default") public boolean isAutoTerminated() { return autoTerminated; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceDefinition.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceDefinition.java index 3755e0c934925..6525f7b844379 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceDefinition.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceDefinition.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; @@ -25,7 +24,6 @@ import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class ResourceDefinition { @@ -35,7 +33,7 @@ public class ResourceDefinition { @XmlElement(name = "resourceType") private List resourceTypes; - @ApiModelProperty(value = "The cardinality of the resource definition") + @Schema(description = "The cardinality of the resource definition") public Cardinality getCardinality() { return cardinality; } @@ -44,7 +42,7 @@ public void setCardinality(Cardinality cardinality) { this.cardinality = cardinality; } - @ApiModelProperty(value = "The types of resources") + @Schema(description = "The types of resources") public List getResourceTypes() { return resourceTypes; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceType.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceType.java index 2f217f9ef9b72..f481839d01893 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceType.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/ResourceType.java @@ -16,9 +16,6 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - -@ApiModel public enum ResourceType { /** diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restricted.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restricted.java index 861b0ab501e6f..0162806f54214 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restricted.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restricted.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.Valid; import jakarta.xml.bind.annotation.XmlAccessType; @@ -26,7 +25,6 @@ import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Restricted { @@ -37,7 +35,7 @@ public class Restricted { @XmlElement(name = "restriction") private List restrictions; - @ApiModelProperty(value = "The general restriction for the extension, or null if only specific restrictions exist") + @Schema(description = "The general restriction for the extension, or null if only specific restrictions exist") public String getGeneralRestrictionExplanation() { return generalRestrictionExplanation; } @@ -46,7 +44,7 @@ public void setGeneralRestrictionExplanation(String generalRestrictionExplanatio this.generalRestrictionExplanation = generalRestrictionExplanation; } - @ApiModelProperty(value = "The specific restrictions") + @Schema(description = "The specific restrictions") public List getRestrictions() { return restrictions; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restriction.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restriction.java index 92bd0e2bededc..241a4981505f8 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restriction.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Restriction.java @@ -16,15 +16,13 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.constraints.NotBlank; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import java.util.Objects; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Restriction { @@ -33,7 +31,7 @@ public class Restriction { @NotBlank private String explanation; - @ApiModelProperty(value = "The permission required for this restriction") + @Schema(description = "The permission required for this restriction") public String getRequiredPermission() { return requiredPermission; } @@ -42,7 +40,7 @@ public void setRequiredPermission(String requiredPermission) { this.requiredPermission = requiredPermission; } - @ApiModelProperty(value = "The explanation of this restriction") + @Schema(description = "The explanation of this restriction") public String getExplanation() { return explanation; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Scope.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Scope.java index 7ee414ded46c7..e4db465a3ecfd 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Scope.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Scope.java @@ -16,12 +16,9 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - /** * Possible scopes for storing state. */ -@ApiModel public enum Scope { CLUSTER, diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Stateful.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Stateful.java index 9b576b43ea4d7..ae718952a9bf9 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Stateful.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/Stateful.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; @@ -25,7 +24,6 @@ import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class Stateful { @@ -35,7 +33,7 @@ public class Stateful { @XmlElement(name = "scope") private List scopes; - @ApiModelProperty(value = "The description for how the extension stores state") + @Schema(description = "The description for how the extension stores state") public String getDescription() { return description; } @@ -44,7 +42,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "The scopes used to store state") + @Schema(description = "The scopes used to store state") public List getScopes() { return scopes; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/SystemResourceConsideration.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/SystemResourceConsideration.java index b4528fc162613..b1fe60c0d2c92 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/SystemResourceConsideration.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/SystemResourceConsideration.java @@ -16,20 +16,18 @@ */ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class SystemResourceConsideration { private String resource; private String description; - @ApiModelProperty(value = "The resource to consider") + @Schema(description = "The resource to consider") public String getResource() { return resource; } @@ -38,7 +36,7 @@ public void setResource(String resource) { this.resource = resource; } - @ApiModelProperty(value = "The description of how the resource is affected") + @Schema(description = "The description of how the resource is affected") public String getDescription() { return description; } diff --git a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/UseCase.java b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/UseCase.java index fc8fa093481ff..b62e03a712718 100644 --- a/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/UseCase.java +++ b/nifi-manifest/nifi-extension-manifest-model/src/main/java/org/apache/nifi/extension/manifest/UseCase.java @@ -17,15 +17,12 @@ package org.apache.nifi.extension.manifest; -import io.swagger.annotations.ApiModel; - import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlElementWrapper; import java.util.List; -@ApiModel @XmlAccessorType(XmlAccessType.FIELD) public class UseCase { diff --git a/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/RuntimeManifestGenerator.java b/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/RuntimeManifestGenerator.java index bbbe1f9db1ccf..1d76db0a43291 100644 --- a/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/RuntimeManifestGenerator.java +++ b/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/RuntimeManifestGenerator.java @@ -39,8 +39,8 @@ import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; import java.util.Properties; @@ -59,6 +59,7 @@ public class RuntimeManifestGenerator { private static final String BUILD_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; private static final String BUILD_JDK = "Build-Jdk"; private static final String BUILD_JDK_VENDOR = "Build-Jdk-Vendor"; + private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern(BUILD_TIMESTAMP_FORMAT); private final File extensionManifestBaseDir; private final File buildPropertiesFile; @@ -87,9 +88,7 @@ public void execute() throws IOException { long buildTimestampMillis; try { - final SimpleDateFormat buildTimestampFormat = new SimpleDateFormat(BUILD_TIMESTAMP_FORMAT); - final Date buildTimestampDate = buildTimestampFormat.parse(buildTimestamp); - buildTimestampMillis = buildTimestampDate.getTime(); + buildTimestampMillis = OffsetDateTime.parse(buildTimestamp, TIMESTAMP_FORMATTER).toInstant().toEpochMilli(); } catch (Exception e) { buildTimestampMillis = System.currentTimeMillis(); } diff --git a/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/StandardRuntimeManifestBuilder.java b/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/StandardRuntimeManifestBuilder.java index e027b13d286b9..2fa5446f56b1f 100644 --- a/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/StandardRuntimeManifestBuilder.java +++ b/nifi-manifest/nifi-runtime-manifest-core/src/main/java/org/apache/nifi/runtime/manifest/impl/StandardRuntimeManifestBuilder.java @@ -23,6 +23,8 @@ import org.apache.nifi.c2.protocol.component.api.ControllerServiceDefinition; import org.apache.nifi.c2.protocol.component.api.DefinedType; import org.apache.nifi.c2.protocol.component.api.ExtensionComponent; +import org.apache.nifi.c2.protocol.component.api.MultiProcessorUseCase; +import org.apache.nifi.c2.protocol.component.api.ProcessorConfiguration; import org.apache.nifi.c2.protocol.component.api.ProcessorDefinition; import org.apache.nifi.c2.protocol.component.api.PropertyAllowableValue; import org.apache.nifi.c2.protocol.component.api.PropertyDependency; @@ -33,6 +35,7 @@ import org.apache.nifi.c2.protocol.component.api.Restriction; import org.apache.nifi.c2.protocol.component.api.RuntimeManifest; import org.apache.nifi.c2.protocol.component.api.SchedulingDefaults; +import org.apache.nifi.c2.protocol.component.api.UseCase; import org.apache.nifi.components.resource.ResourceCardinality; import org.apache.nifi.components.resource.ResourceType; import org.apache.nifi.components.state.Scope; @@ -151,7 +154,7 @@ public RuntimeManifestBuilder addBundle(final ExtensionManifestContainer extensi @Override public RuntimeManifestBuilder addBundles(final Iterable extensionManifests) { - extensionManifests.forEach(em -> addBundle(em)); + extensionManifests.forEach(this::addBundle); return this; } @@ -277,9 +280,45 @@ private void addProcessorDefinition(final ExtensionManifest extensionManifest, f ); } + final List useCases = extension.getUseCases() == null ? List.of() : extension.getUseCases().stream() + .map(StandardRuntimeManifestBuilder::createUseCase) + .toList(); + processorDefinition.setUseCases(useCases); + + final List multiProcessorUseCases = extension.getMultiProcessorUseCases() == null ? List.of() : extension.getMultiProcessorUseCases().stream() + .map(StandardRuntimeManifestBuilder::createMultiProcessorUseCase) + .toList(); + processorDefinition.setMultiProcessorUseCases(multiProcessorUseCases); + componentManifestBuilder.addProcessor(processorDefinition); } + private static UseCase createUseCase(final org.apache.nifi.extension.manifest.UseCase extensionUseCase) { + final UseCase useCase = new UseCase(); + useCase.setDescription(extensionUseCase.getDescription()); + useCase.setConfiguration(extensionUseCase.getConfiguration()); + useCase.setKeywords(extensionUseCase.getKeywords()); + useCase.setNotes(extensionUseCase.getNotes()); + return useCase; + } + + private static MultiProcessorUseCase createMultiProcessorUseCase(final org.apache.nifi.extension.manifest.MultiProcessorUseCase extensionUseCase) { + final MultiProcessorUseCase useCase = new MultiProcessorUseCase(); + useCase.setDescription(extensionUseCase.getDescription()); + useCase.setKeywords(extensionUseCase.getKeywords()); + useCase.setNotes(extensionUseCase.getNotes()); + + final List processorConfigs = new ArrayList<>(); + for (final org.apache.nifi.extension.manifest.ProcessorConfiguration extensionConfig : extensionUseCase.getProcessorConfigurations()) { + final ProcessorConfiguration processorConfig = new ProcessorConfiguration(); + processorConfig.setConfiguration(extensionConfig.getConfiguration()); + processorConfig.setProcessorClassName(extensionConfig.getProcessorClassName()); + processorConfigs.add(processorConfig); + } + useCase.setConfigurations(processorConfigs); + return useCase; + } + private org.apache.nifi.c2.protocol.component.api.Attribute getAttribute(final Attribute attribute) { final org.apache.nifi.c2.protocol.component.api.Attribute c2Attribute = new org.apache.nifi.c2.protocol.component.api.Attribute(); c2Attribute.setName(attribute.getName()); @@ -299,16 +338,11 @@ private InputRequirement.Requirement getInputRequirement(final org.apache.nifi.e return null; } - switch (inputRequirement) { - case INPUT_ALLOWED: - return InputRequirement.Requirement.INPUT_ALLOWED; - case INPUT_REQUIRED: - return InputRequirement.Requirement.INPUT_REQUIRED; - case INPUT_FORBIDDEN: - return InputRequirement.Requirement.INPUT_FORBIDDEN; - default: - throw new IllegalArgumentException("Unknown input requirement: " + inputRequirement.name()); - } + return switch (inputRequirement) { + case INPUT_ALLOWED -> InputRequirement.Requirement.INPUT_ALLOWED; + case INPUT_REQUIRED -> InputRequirement.Requirement.INPUT_REQUIRED; + case INPUT_FORBIDDEN -> InputRequirement.Requirement.INPUT_FORBIDDEN; + }; } private List getSupportedRelationships(final List relationships) { @@ -460,14 +494,10 @@ private org.apache.nifi.c2.protocol.component.api.SystemResourceConsideration ge } private Scope getScope(final org.apache.nifi.extension.manifest.Scope sourceScope) { - switch (sourceScope) { - case LOCAL: - return Scope.LOCAL; - case CLUSTER: - return Scope.CLUSTER; - default: - throw new IllegalArgumentException("Unknown scope: " + sourceScope); - } + return switch (sourceScope) { + case LOCAL -> Scope.LOCAL; + case CLUSTER -> Scope.CLUSTER; + }; } private Restriction createRestriction(final org.apache.nifi.extension.manifest.Restriction extensionRestriction) { @@ -550,8 +580,7 @@ private List getPropertyDependencies(final List final DependentValues dependentValues = dependency.getDependentValues(); if (dependentValues != null && dependentValues.getValues() != null) { - final List values = new ArrayList(); - values.addAll(dependentValues.getValues()); + final List values = new ArrayList<>(dependentValues.getValues()); propertyDependency.setDependentValues(values); } propertyDependencies.add(propertyDependency); @@ -565,18 +594,15 @@ private PropertyResourceDefinition getPropertyResourceDefinition(final ResourceD } final PropertyResourceDefinition propertyResourceDefinition = new PropertyResourceDefinition(); - switch (resourceDefinition.getCardinality()) { - case SINGLE: - propertyResourceDefinition.setCardinality(ResourceCardinality.SINGLE); - break; - case MULTIPLE: - propertyResourceDefinition.setCardinality(ResourceCardinality.MULTIPLE); - break; - } + final ResourceCardinality cardinality = switch (resourceDefinition.getCardinality()) { + case SINGLE -> ResourceCardinality.SINGLE; + case MULTIPLE -> ResourceCardinality.MULTIPLE; + }; + propertyResourceDefinition.setCardinality(cardinality); propertyResourceDefinition.setResourceTypes( resourceDefinition.getResourceTypes().stream() - .map(rt -> getResourceType(rt)) + .map(this::getResourceType) .collect(Collectors.toSet()) ); @@ -584,18 +610,12 @@ private PropertyResourceDefinition getPropertyResourceDefinition(final ResourceD } private ResourceType getResourceType(final org.apache.nifi.extension.manifest.ResourceType resourceType) { - switch (resourceType) { - case URL: - return ResourceType.URL; - case FILE: - return ResourceType.FILE; - case TEXT: - return ResourceType.TEXT; - case DIRECTORY: - return ResourceType.DIRECTORY; - default: - throw new IllegalArgumentException("Unknown resource type: " + resourceType); - } + return switch (resourceType) { + case URL -> ResourceType.URL; + case FILE -> ResourceType.FILE; + case TEXT -> ResourceType.TEXT; + case DIRECTORY -> ResourceType.DIRECTORY; + }; } private ExpressionLanguageScope getELScope(final org.apache.nifi.extension.manifest.ExpressionLanguageScope elScope) { @@ -603,16 +623,11 @@ private ExpressionLanguageScope getELScope(final org.apache.nifi.extension.manif return null; } - switch (elScope) { - case NONE: - return ExpressionLanguageScope.NONE; - case FLOWFILE_ATTRIBUTES: - return ExpressionLanguageScope.FLOWFILE_ATTRIBUTES; - case ENVIRONMENT: - return ExpressionLanguageScope.ENVIRONMENT; - default: - throw new IllegalArgumentException("Unknown Expression Language Scope: " + elScope.name()); - } + return switch (elScope) { + case NONE -> ExpressionLanguageScope.NONE; + case FLOWFILE_ATTRIBUTES -> ExpressionLanguageScope.FLOWFILE_ATTRIBUTES; + case ENVIRONMENT -> ExpressionLanguageScope.ENVIRONMENT; + }; } private List getPropertyAllowableValues(final List allowableValues) { diff --git a/nifi-manifest/nifi-runtime-manifest-test/src/test/java/org/apache/nifi/runtime/manifest/TestRuntimeManifest.java b/nifi-manifest/nifi-runtime-manifest-test/src/test/java/org/apache/nifi/runtime/manifest/TestRuntimeManifest.java index 46ce07a20e81c..eb34a91cea432 100644 --- a/nifi-manifest/nifi-runtime-manifest-test/src/test/java/org/apache/nifi/runtime/manifest/TestRuntimeManifest.java +++ b/nifi-manifest/nifi-runtime-manifest-test/src/test/java/org/apache/nifi/runtime/manifest/TestRuntimeManifest.java @@ -128,8 +128,8 @@ void testRuntimeManifest() throws IOException { assertEquals(REPORTING_TASK_DEFAULT_SCHEDULE_TIME, prometheusDefaultSchedulingPeriods.get(SchedulingStrategy.TIMER_DRIVEN.name())); assertEquals(SchedulingStrategy.CRON_DRIVEN.getDefaultSchedulingPeriod(), prometheusDefaultSchedulingPeriods.get(SchedulingStrategy.CRON_DRIVEN.name())); - final ProcessorDefinition joltTransformDef = getProcessorDefinition(bundles, "nifi-jolt-record-nar", - "org.apache.nifi.processors.jolt.record.JoltTransformRecord"); + final ProcessorDefinition joltTransformDef = getProcessorDefinition(bundles, "nifi-jolt-nar", + "org.apache.nifi.processors.jolt.JoltTransformRecord"); assertEquals(SchedulingStrategy.TIMER_DRIVEN.name(), joltTransformDef.getDefaultSchedulingStrategy()); final List joltTransformSchedulingStrategies = joltTransformDef.getSupportedSchedulingStrategies(); diff --git a/nifi-maven-archetypes/nifi-processor-bundle-archetype/src/main/resources/archetype-resources/nifi-__artifactBaseName__-nar/pom.xml b/nifi-maven-archetypes/nifi-processor-bundle-archetype/src/main/resources/archetype-resources/nifi-__artifactBaseName__-nar/pom.xml index c5c63998fe7e2..2737b68a88266 100644 --- a/nifi-maven-archetypes/nifi-processor-bundle-archetype/src/main/resources/archetype-resources/nifi-__artifactBaseName__-nar/pom.xml +++ b/nifi-maven-archetypes/nifi-processor-bundle-archetype/src/main/resources/archetype-resources/nifi-__artifactBaseName__-nar/pom.xml @@ -32,6 +32,12 @@ nifi-${artifactBaseName}-processors ${version} + + org.apache.nifi + nifi-standard-services-api-nar + ${version} + nar + diff --git a/nifi-mock/src/main/java/org/apache/nifi/state/MockStateManager.java b/nifi-mock/src/main/java/org/apache/nifi/state/MockStateManager.java index 6086191d41822..5ef3116223728 100644 --- a/nifi-mock/src/main/java/org/apache/nifi/state/MockStateManager.java +++ b/nifi-mock/src/main/java/org/apache/nifi/state/MockStateManager.java @@ -29,10 +29,20 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import static org.apache.nifi.state.MockStateManager.ExecutionMode.CLUSTERED; +import static org.apache.nifi.state.MockStateManager.ExecutionMode.STANDALONE; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class MockStateManager implements StateManager { + + public enum ExecutionMode { + // in CLUSTERED mode separate state maps are used for the CLUSTER and the LOCAL scopes + CLUSTERED, + // in STANDALONE mode the same state map (the local one) is used for both the CLUSTER and the LOCAL scopes + STANDALONE + } + private final AtomicInteger versionIndex = new AtomicInteger(0); private StateMap localStateMap = new MockStateMap(null, -1L); @@ -50,6 +60,8 @@ public class MockStateManager implements StateManager { private final boolean usesLocalState; private final boolean usesClusterState; + private ExecutionMode executionMode = CLUSTERED; + public MockStateManager(final Object component) { final Stateful stateful = component.getClass().getAnnotation(Stateful.class); if (stateful == null) { @@ -78,13 +90,17 @@ public void reset() { localStateMap = new MockStateMap(null, -1L); } + public void setExecutionMode(ExecutionMode executionMode) { + this.executionMode = executionMode; + } + @Override public synchronized void setState(final Map state, final Scope scope) throws IOException { verifyAnnotation(scope); verifyCanSet(scope); final StateMap stateMap = new MockStateMap(state, versionIndex.incrementAndGet()); - if (scope == Scope.CLUSTER) { + if (scope == Scope.CLUSTER && executionMode == CLUSTERED) { clusterStateMap = stateMap; } else { localStateMap = stateMap; @@ -102,7 +118,7 @@ private synchronized StateMap retrieveState(final Scope scope) { verifyAnnotation(scope); if (scope == Scope.CLUSTER) { clusterRetrievedCount.incrementAndGet(); - return clusterStateMap; + return executionMode == CLUSTERED ? clusterStateMap : localStateMap; } else { localRetrievedCount.incrementAndGet(); return localStateMap; @@ -120,10 +136,14 @@ public long getRetrievalCount(final Scope scope) { public synchronized boolean replace(final StateMap oldValue, final Map newValue, final Scope scope) throws IOException { verifyAnnotation(scope); if (scope == Scope.CLUSTER) { - if (oldValue == clusterStateMap) { + if (executionMode == CLUSTERED && oldValue == clusterStateMap) { verifyCanSet(scope); clusterStateMap = new MockStateMap(newValue, versionIndex.incrementAndGet()); return true; + } else if (executionMode == STANDALONE && oldValue == localStateMap) { + verifyCanSet(scope); + localStateMap = new MockStateMap(newValue, versionIndex.incrementAndGet()); + return true; } return false; @@ -176,7 +196,7 @@ private void verifyAnnotation(final Scope scope) { private String getValue(final String key, final Scope scope) { final StateMap stateMap; - if (scope == Scope.CLUSTER) { + if (scope == Scope.CLUSTER && executionMode == CLUSTERED) { stateMap = clusterStateMap; } else { stateMap = localStateMap; diff --git a/nifi-mock/src/main/java/org/apache/nifi/util/MockPropertyValue.java b/nifi-mock/src/main/java/org/apache/nifi/util/MockPropertyValue.java index 226df960f538f..8244802858ea7 100644 --- a/nifi-mock/src/main/java/org/apache/nifi/util/MockPropertyValue.java +++ b/nifi-mock/src/main/java/org/apache/nifi/util/MockPropertyValue.java @@ -25,7 +25,6 @@ import org.apache.nifi.attribute.expression.language.Query; import org.apache.nifi.attribute.expression.language.Query.Range; import org.apache.nifi.attribute.expression.language.StandardPropertyValue; -import org.apache.nifi.components.DescribedValue; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.PropertyValue; import org.apache.nifi.components.resource.ResourceContext; @@ -324,9 +323,9 @@ public ResourceReferences asResources() { } @Override - public & DescribedValue> E asDescribedValue(Class enumType) throws IllegalArgumentException { + public > E asAllowableValue(Class enumType) throws IllegalArgumentException { ensureExpressionsEvaluated(); - return stdPropValue.asDescribedValue(enumType); + return stdPropValue.asAllowableValue(enumType); } @Override diff --git a/nifi-nar-bundles/nifi-asana-bundle/nifi-asana-processors/src/main/java/org/apache/nifi/processors/asana/GetAsanaObject.java b/nifi-nar-bundles/nifi-asana-bundle/nifi-asana-processors/src/main/java/org/apache/nifi/processors/asana/GetAsanaObject.java index 2ab1877ee1a7a..597248e365ee4 100644 --- a/nifi-nar-bundles/nifi-asana-bundle/nifi-asana-processors/src/main/java/org/apache/nifi/processors/asana/GetAsanaObject.java +++ b/nifi-nar-bundles/nifi-asana-bundle/nifi-asana-processors/src/main/java/org/apache/nifi/processors/asana/GetAsanaObject.java @@ -341,7 +341,7 @@ private static void transferFlowFileByAsanaObjectState(ProcessSession session, A } protected AsanaObjectFetcher createObjectFetcher(final ProcessContext context, AsanaClient client) { - final AsanaObjectType objectType = context.getProperty(PROP_ASANA_OBJECT_TYPE).asDescribedValue(AsanaObjectType.class); + final AsanaObjectType objectType = context.getProperty(PROP_ASANA_OBJECT_TYPE).asAllowableValue(AsanaObjectType.class); final String projectName = context.getProperty(PROP_ASANA_PROJECT).getValue(); final String sectionName = context.getProperty(PROP_ASANA_SECTION).getValue(); final String teamName = context.getProperty(PROP_ASANA_TEAM_NAME).getValue(); diff --git a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/BerStringConverter.java b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/BerStringConverter.java index 1b113768548f8..1e0d8530785a3 100644 --- a/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/BerStringConverter.java +++ b/nifi-nar-bundles/nifi-asn1-bundle/nifi-asn1-services/src/main/java/org/apache/nifi/jasn1/convert/converters/BerStringConverter.java @@ -16,6 +16,7 @@ */ package org.apache.nifi.jasn1.convert.converters; +import com.beanit.asn1bean.ber.types.BerObjectIdentifier; import com.beanit.asn1bean.ber.types.BerType; import com.beanit.asn1bean.ber.types.string.BerBMPString; import com.beanit.asn1bean.ber.types.string.BerGeneralString; @@ -46,7 +47,8 @@ public class BerStringConverter implements JASN1TypeAndValueConverter { BerVisibleString.class, BerVideotexString.class, BerBMPString.class, - BerUTF8String.class + BerUTF8String.class, + BerObjectIdentifier.class ); @Override diff --git a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/ListS3.java b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/ListS3.java index 13e15a4aaecea..94a1c9d127aa1 100644 --- a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/ListS3.java +++ b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/ListS3.java @@ -143,12 +143,17 @@ public class ListS3 extends AbstractS3Processor implements VerifiableProcessor { " However an additional DistributedMapCache controller service is required and more JVM heap memory is used." + " For more information on how the 'Entity Tracking Time Window' property works, see the description."); + public static final AllowableValue NO_TRACKING = new AllowableValue("none", "No Tracking", + "This strategy lists all entities without any tracking. The same entities will be listed each time" + + " this processor is scheduled. It is recommended to change the default run schedule value." + + " Any property that relates to the persisting state will be ignored."); + public static final PropertyDescriptor LISTING_STRATEGY = new Builder() .name("listing-strategy") .displayName("Listing Strategy") .description("Specify how to determine new/updated entities. See each strategy descriptions for detail.") .required(true) - .allowableValues(BY_TIMESTAMPS, BY_ENTITIES) + .allowableValues(BY_TIMESTAMPS, BY_ENTITIES, NO_TRACKING) .defaultValue(BY_TIMESTAMPS.getValue()) .build(); @@ -161,11 +166,12 @@ public class ListS3 extends AbstractS3Processor implements VerifiableProcessor { public static final PropertyDescriptor INITIAL_LISTING_TARGET = new PropertyDescriptor.Builder() .fromPropertyDescriptor(ListedEntityTracker.INITIAL_LISTING_TARGET) .dependsOn(LISTING_STRATEGY, BY_ENTITIES) + .required(true) .build(); public static final PropertyDescriptor TRACKING_TIME_WINDOW = new PropertyDescriptor.Builder() .fromPropertyDescriptor(ListedEntityTracker.TRACKING_TIME_WINDOW) - .dependsOn(INITIAL_LISTING_TARGET, ListedEntityTracker.INITIAL_LISTING_TARGET_WINDOW) + .dependsOn(ListedEntityTracker.TRACKING_STATE_CACHE) .required(true) .build(); @@ -289,8 +295,8 @@ public class ListS3 extends AbstractS3Processor implements VerifiableProcessor { AWS_CREDENTIALS_PROVIDER_SERVICE, LISTING_STRATEGY, TRACKING_STATE_CACHE, - INITIAL_LISTING_TARGET, TRACKING_TIME_WINDOW, + INITIAL_LISTING_TARGET, RECORD_WRITER, MIN_AGE, MAX_AGE, @@ -321,6 +327,8 @@ public class ListS3 extends AbstractS3Processor implements VerifiableProcessor { private volatile boolean justElectedPrimaryNode = false; private volatile boolean resetEntityTrackingState = false; private volatile ListedEntityTracker> listedEntityTracker; + private volatile Long minObjectAgeMilliseconds; + private volatile Long maxObjectAgeMilliseconds; @OnPrimaryNodeStateChange public void onPrimaryNodeChange(final PrimaryNodeState newState) { @@ -334,7 +342,7 @@ public void initListedEntityTracker(ProcessContext context) { try { listedEntityTracker.clearListedEntities(); } catch (IOException e) { - throw new RuntimeException("Failed to reset previously listed entities due to " + e, e); + throw new RuntimeException("Failed to reset previously listed entities", e); } } resetEntityTrackingState = false; @@ -346,6 +354,9 @@ public void initListedEntityTracker(ProcessContext context) { } else { listedEntityTracker = null; } + + minObjectAgeMilliseconds = context.getProperty(MIN_AGE).asTimePeriod(TimeUnit.MILLISECONDS); + maxObjectAgeMilliseconds = context.getProperty(MAX_AGE) != null ? context.getProperty(MAX_AGE).asTimePeriod(TimeUnit.MILLISECONDS) : null; } protected ListedEntityTracker> createListedEntityTracker() { @@ -356,7 +367,7 @@ private static Validator createRequesterPaysValidator() { return new Validator() { @Override public ValidationResult validate(final String subject, final String input, final ValidationContext context) { - boolean requesterPays = Boolean.valueOf(input); + boolean requesterPays = Boolean.parseBoolean(input); boolean useVersions = context.getProperty(USE_VERSIONS).asBoolean(); boolean valid = !requesterPays || !useVersions; return new ValidationResult.Builder() @@ -407,7 +418,7 @@ private Set extractKeys(final StateMap stateMap) { private void restoreState(final ProcessSession session) throws IOException { final StateMap stateMap = session.getState(Scope.CLUSTER); - if (!stateMap.getStateVersion().isPresent() || stateMap.get(CURRENT_TIMESTAMP) == null || stateMap.get(CURRENT_KEY_PREFIX+"0") == null) { + if (stateMap.getStateVersion().isEmpty() || stateMap.get(CURRENT_TIMESTAMP) == null || stateMap.get(CURRENT_KEY_PREFIX + "0") == null) { forcefullyUpdateListing(0L, Collections.emptySet()); } else { final long timestamp = Long.parseLong(stateMap.get(CURRENT_TIMESTAMP)); @@ -451,20 +462,14 @@ public void onTrigger(final ProcessContext context, final ProcessSession session listByTrackingTimestamps(context, session); } else if (BY_ENTITIES.equals(listingStrategy)) { listByTrackingEntities(context, session); + } else if (NO_TRACKING.equals(listingStrategy)) { + listNoTracking(context, session); } else { throw new ProcessException("Unknown listing strategy: " + listingStrategy); } } - private void listByTrackingTimestamps(ProcessContext context, ProcessSession session) { - try { - restoreState(session); - } catch (IOException ioe) { - getLogger().error("Failed to restore processor state; yielding", ioe); - context.yield(); - return; - } - + private void listNoTracking(ProcessContext context, ProcessSession session) { final AmazonS3 client = getClient(context); S3BucketLister bucketLister = getS3BucketLister(context, client); @@ -477,15 +482,10 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses final String bucket = context.getProperty(BUCKET_WITHOUT_DEFAULT_VALUE).evaluateAttributeExpressions().getValue(); final int batchSize = context.getProperty(BATCH_SIZE).asInteger(); - final ListingSnapshot currentListing = listing.get(); - final long currentTimestamp = currentListing.getTimestamp(); - final Set currentKeys = currentListing.getKeys(); int listCount = 0; int totalListCount = 0; - long latestListedTimestampInThisCycle = currentTimestamp; - final Set listedKeys = new HashSet<>(); - getLogger().trace("Start listing, listingTimestamp={}, currentTimestamp={}, currentKeys={}", new Object[]{listingTimestamp, currentTimestamp, currentKeys}); + getLogger().trace("Start listing, listingTimestamp={}", listingTimestamp); final S3ObjectWriter writer; final RecordSetWriterFactory writerFactory = context.getProperty(RECORD_WRITER).asControllerService(RecordSetWriterFactory.class); @@ -502,14 +502,12 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses VersionListing versionListing = bucketLister.listVersions(); for (S3VersionSummary versionSummary : versionListing.getVersionSummaries()) { long lastModified = versionSummary.getLastModified().getTime(); - if (lastModified < currentTimestamp - || lastModified == currentTimestamp && currentKeys.contains(versionSummary.getKey()) - || (maxAgeMilliseconds != null && (lastModified < (listingTimestamp - maxAgeMilliseconds))) + if ((maxAgeMilliseconds != null && (lastModified < (listingTimestamp - maxAgeMilliseconds))) || lastModified > (listingTimestamp - minAgeMilliseconds)) { continue; } - getLogger().trace("Listed key={}, lastModified={}, currentKeys={}", new Object[]{versionSummary.getKey(), lastModified, currentKeys}); + getLogger().trace("Listed key={}, lastModified={}", versionSummary.getKey(), lastModified); GetObjectTaggingResult taggingResult = getTaggingResult(context, client, versionSummary); @@ -518,6 +516,92 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses // Write the entity to the listing writer.addToListing(versionSummary, taggingResult, objectMetadata, context.getProperty(S3_REGION).getValue()); + listCount++; + } + bucketLister.setNextMarker(); + + totalListCount += listCount; + + if (listCount >= batchSize && writer.isCheckpoint()) { + getLogger().info("Successfully listed {} new files from S3; routing to success", listCount); + session.commitAsync(); + } + + listCount = 0; + } while (bucketLister.isTruncated()); + + writer.finishListing(); + } catch (final Exception e) { + getLogger().error("Failed to list contents of bucket", e); + writer.finishListingExceptionally(e); + session.rollback(); + context.yield(); + return; + } + + final long listMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos); + getLogger().info("Successfully listed S3 bucket {} in {} millis", bucket, listMillis); + + if (totalListCount == 0) { + getLogger().debug("No new objects in S3 bucket {} to list. Yielding.", bucket); + context.yield(); + } + } + + private void listByTrackingTimestamps(ProcessContext context, ProcessSession session) { + try { + restoreState(session); + } catch (IOException ioe) { + getLogger().error("Failed to restore processor state; yielding", ioe); + context.yield(); + return; + } + + final AmazonS3 client = getClient(context); + final S3BucketLister bucketLister = getS3BucketLister(context, client); + final String bucket = context.getProperty(BUCKET_WITHOUT_DEFAULT_VALUE).evaluateAttributeExpressions().getValue(); + final int batchSize = context.getProperty(BATCH_SIZE).asInteger(); + + final ListingSnapshot currentListing = listing.get(); + final long startNanos = System.nanoTime(); + final long currentTimestamp = System.currentTimeMillis(); + final long listingTimestamp = currentListing.getTimestamp(); + final Set currentKeys = currentListing.getKeys(); + int listCount = 0; + int totalListCount = 0; + long latestListedTimestampInThisCycle = listingTimestamp; + + final Set listedKeys = new HashSet<>(); + getLogger().trace("Start listing, listingTimestamp={}, currentTimestamp={}, currentKeys={}", currentTimestamp, listingTimestamp, currentKeys); + + final S3ObjectWriter writer; + final RecordSetWriterFactory writerFactory = context.getProperty(RECORD_WRITER).asControllerService(RecordSetWriterFactory.class); + if (writerFactory == null) { + writer = new AttributeObjectWriter(session); + } else { + writer = new RecordObjectWriter(session, writerFactory, getLogger(), context.getProperty(S3_REGION).getValue()); + } + + try { + writer.beginListing(); + + do { + final VersionListing versionListing = bucketLister.listVersions(); + for (S3VersionSummary versionSummary : versionListing.getVersionSummaries()) { + final long lastModified = versionSummary.getLastModified().getTime(); + if (lastModified < listingTimestamp + || lastModified == listingTimestamp && currentKeys.contains(versionSummary.getKey()) + || !includeObjectInListing(versionSummary, currentTimestamp)) { + continue; + } + + getLogger().trace("Listed key={}, lastModified={}, currentKeys={}", versionSummary.getKey(), lastModified, currentKeys); + + // Write the entity to the listing + final GetObjectTaggingResult taggingResult = getTaggingResult(context, client, versionSummary); + final ObjectMetadata objectMetadata = getObjectMetadata(context, client, versionSummary); + writer.addToListing(versionSummary, taggingResult, objectMetadata, context.getProperty(S3_REGION).getValue()); + // Track the latest lastModified timestamp and keys having that timestamp. // NOTE: Amazon S3 lists objects in UTF-8 character encoding in lexicographical order. Not ordered by timestamps. if (lastModified > latestListedTimestampInThisCycle) { @@ -531,8 +615,8 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses listCount++; } - bucketLister.setNextMarker(); + bucketLister.setNextMarker(); totalListCount += listCount; if (listCount >= batchSize && writer.isCheckpoint()) { @@ -545,7 +629,7 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses writer.finishListing(); } catch (final Exception e) { - getLogger().error("Failed to list contents of bucket due to {}", e, e); + getLogger().error("Failed to list contents of bucket", e); writer.finishListingExceptionally(e); session.rollback(); context.yield(); @@ -553,7 +637,7 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses } final Set updatedKeys = new HashSet<>(); - if (latestListedTimestampInThisCycle <= currentTimestamp) { + if (latestListedTimestampInThisCycle <= listingTimestamp) { updatedKeys.addAll(currentKeys); } updatedKeys.addAll(listedKeys); @@ -566,10 +650,10 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses }); final long listMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNanos); - getLogger().info("Successfully listed S3 bucket {} in {} millis", new Object[]{bucket, listMillis}); + getLogger().info("Successfully listed S3 bucket {} in {} millis", bucket, listMillis); if (totalListCount == 0) { - getLogger().debug("No new objects in S3 bucket {} to list. Yielding.", new Object[]{bucket}); + getLogger().debug("No new objects in S3 bucket {} to list. Yielding.", bucket); context.yield(); } } @@ -577,10 +661,12 @@ private void listByTrackingTimestamps(ProcessContext context, ProcessSession ses private void listByTrackingEntities(ProcessContext context, ProcessSession session) { listedEntityTracker.trackEntities(context, session, justElectedPrimaryNode, Scope.CLUSTER, minTimestampToList -> { S3BucketLister bucketLister = getS3BucketLister(context, getClient(context)); + final long currentTime = System.currentTimeMillis(); - List> listedEntities = bucketLister.listVersions().getVersionSummaries() + return bucketLister.listVersions().getVersionSummaries() .stream() - .filter(s3VersionSummary -> s3VersionSummary.getLastModified().getTime() >= minTimestampToList) + .filter(s3VersionSummary -> s3VersionSummary.getLastModified().getTime() >= minTimestampToList + && includeObjectInListing(s3VersionSummary, currentTime)) .map(s3VersionSummary -> new ListableEntityWrapper( s3VersionSummary, S3VersionSummary::getKey, @@ -589,8 +675,6 @@ private void listByTrackingEntities(ProcessContext context, ProcessSession sessi S3VersionSummary::getSize )) .collect(Collectors.toList()); - - return listedEntities; }, null); justElectedPrimaryNode = false; @@ -606,7 +690,7 @@ protected void createRecordsForEntities( ProcessContext context, ProcessSession session, List> updatedEntities - ) throws IOException, SchemaNotFoundException { + ) { publishListing(context, session, updatedEntities); } @@ -637,16 +721,15 @@ private void publishListing(ProcessContext context, ProcessSession session, List for (ListableEntityWrapper updatedEntity : updatedEntities) { S3VersionSummary s3VersionSummary = updatedEntity.getRawEntity(); - AmazonS3Client s3Client = getClient(context); - GetObjectTaggingResult taggingResult = getTaggingResult(context, s3Client, s3VersionSummary); - ObjectMetadata objectMetadata = getObjectMetadata(context, s3Client, s3VersionSummary); - + final AmazonS3Client s3Client = getClient(context); + final GetObjectTaggingResult taggingResult = getTaggingResult(context, s3Client, s3VersionSummary); + final ObjectMetadata objectMetadata = getObjectMetadata(context, s3Client, s3VersionSummary); writer.addToListing(s3VersionSummary, taggingResult, objectMetadata, context.getProperty(S3_REGION).getValue()); listCount++; if (listCount >= batchSize && writer.isCheckpoint()) { - getLogger().info("Successfully listed {} new files from S3; routing to success", new Object[]{listCount}); + getLogger().info("Successfully listed {} new files from S3; routing to success", listCount); session.commitAsync(); } @@ -656,11 +739,10 @@ private void publishListing(ProcessContext context, ProcessSession session, List writer.finishListing(); } catch (final Exception e) { - getLogger().error("Failed to list contents of bucket due to {}", e, e); + getLogger().error("Failed to list contents of bucket", e); writer.finishListingExceptionally(e); session.rollback(); context.yield(); - return; } } } @@ -732,7 +814,7 @@ private interface S3BucketLister { } public class S3ObjectBucketLister implements S3BucketLister { - private AmazonS3 client; + private final AmazonS3 client; private ListObjectsRequest listObjectsRequest; private ObjectListing objectListing; @@ -762,22 +844,11 @@ public void setRequesterPays(boolean requesterPays) { @Override public VersionListing listVersions() { - VersionListing versionListing = new VersionListing(); - this.objectListing = client.listObjects(listObjectsRequest); - for(S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) { - S3VersionSummary versionSummary = new S3VersionSummary(); - versionSummary.setBucketName(objectSummary.getBucketName()); - versionSummary.setETag(objectSummary.getETag()); - versionSummary.setKey(objectSummary.getKey()); - versionSummary.setLastModified(objectSummary.getLastModified()); - versionSummary.setOwner(objectSummary.getOwner()); - versionSummary.setSize(objectSummary.getSize()); - versionSummary.setStorageClass(objectSummary.getStorageClass()); - versionSummary.setIsLatest(true); - - versionListing.getVersionSummaries().add(versionSummary); - } - + objectListing = client.listObjects(listObjectsRequest); + final VersionListing versionListing = new VersionListing(); + versionListing.setVersionSummaries(objectListing.getObjectSummaries().stream() + .map(ListS3.this::objectSummaryToVersionSummary) + .collect(Collectors.toList())); return versionListing; } @@ -788,12 +859,12 @@ public void setNextMarker() { @Override public boolean isTruncated() { - return (objectListing == null) ? false : objectListing.isTruncated(); + return objectListing != null && objectListing.isTruncated(); } } public class S3ObjectBucketListerVersion2 implements S3BucketLister { - private AmazonS3 client; + private final AmazonS3 client; private ListObjectsV2Request listObjectsRequest; private ListObjectsV2Result objectListing; @@ -823,22 +894,11 @@ public void setRequesterPays(boolean requesterPays) { @Override public VersionListing listVersions() { - VersionListing versionListing = new VersionListing(); - this.objectListing = client.listObjectsV2(listObjectsRequest); - for(S3ObjectSummary objectSummary : objectListing.getObjectSummaries()) { - S3VersionSummary versionSummary = new S3VersionSummary(); - versionSummary.setBucketName(objectSummary.getBucketName()); - versionSummary.setETag(objectSummary.getETag()); - versionSummary.setKey(objectSummary.getKey()); - versionSummary.setLastModified(objectSummary.getLastModified()); - versionSummary.setOwner(objectSummary.getOwner()); - versionSummary.setSize(objectSummary.getSize()); - versionSummary.setStorageClass(objectSummary.getStorageClass()); - versionSummary.setIsLatest(true); - - versionListing.getVersionSummaries().add(versionSummary); - } - + objectListing = client.listObjectsV2(listObjectsRequest); + final VersionListing versionListing = new VersionListing(); + versionListing.setVersionSummaries(objectListing.getObjectSummaries().stream() + .map(ListS3.this::objectSummaryToVersionSummary) + .collect(Collectors.toList())); return versionListing; } @@ -849,12 +909,12 @@ public void setNextMarker() { @Override public boolean isTruncated() { - return (objectListing == null) ? false : objectListing.isTruncated(); + return objectListing != null && objectListing.isTruncated(); } } public class S3VersionBucketLister implements S3BucketLister { - private AmazonS3 client; + private final AmazonS3 client; private ListVersionsRequest listVersionsRequest; private VersionListing versionListing; @@ -896,7 +956,7 @@ public void setNextMarker() { @Override public boolean isTruncated() { - return (versionListing == null) ? false : versionListing.isTruncated(); + return versionListing != null && versionListing.isTruncated(); } } @@ -944,13 +1004,12 @@ static class RecordObjectWriter implements S3ObjectWriter { RECORD_SCHEMA = new SimpleRecordSchema(fields); } - private final ProcessSession session; private final RecordSetWriterFactory writerFactory; private final ComponentLog logger; + private final String region; private RecordSetWriter recordWriter; private FlowFile flowFile; - private String region; public RecordObjectWriter(final ProcessSession session, final RecordSetWriterFactory writerFactory, final ComponentLog logger, final String region) { this.session = session; @@ -995,7 +1054,7 @@ public void finishListingExceptionally(final Exception cause) { try { recordWriter.close(); } catch (IOException e) { - logger.error("Failed to write listing as Records due to {}", e, e); + logger.error("Failed to write listing as Records", e); } session.remove(flowFile); @@ -1042,8 +1101,6 @@ private Record createRecordForListing(final S3VersionSummary versionSummary, fin } } - - static class AttributeObjectWriter implements S3ObjectWriter { private final ProcessSession session; @@ -1062,14 +1119,17 @@ public void addToListing(final S3VersionSummary versionSummary, final GetObjectT attributes.put(CoreAttributes.FILENAME.key(), versionSummary.getKey()); attributes.put("s3.bucket", versionSummary.getBucketName()); attributes.put("s3.region", region); + if (versionSummary.getOwner() != null) { // We may not have permission to read the owner attributes.put("s3.owner", versionSummary.getOwner().getId()); } + attributes.put("s3.etag", versionSummary.getETag()); attributes.put("s3.lastModified", String.valueOf(versionSummary.getLastModified().getTime())); attributes.put("s3.length", String.valueOf(versionSummary.getSize())); attributes.put("s3.storeClass", versionSummary.getStorageClass()); attributes.put("s3.isLatest", String.valueOf(versionSummary.isLatest())); + if (versionSummary.getVersionId() != null) { attributes.put("s3.version", versionSummary.getVersionId()); } @@ -1094,7 +1154,7 @@ public void addToListing(final S3VersionSummary versionSummary, final GetObjectT } @Override - public void finishListing() throws IOException { + public void finishListing() { } @Override @@ -1131,8 +1191,6 @@ public List verify(final ProcessContext context, final final List results = new ArrayList<>(super.verify(context, logger, attributes)); final String bucketName = context.getProperty(BUCKET_WITHOUT_DEFAULT_VALUE).evaluateAttributeExpressions(attributes).getValue(); - final long minAgeMilliseconds = context.getProperty(MIN_AGE).asTimePeriod(TimeUnit.MILLISECONDS); - final Long maxAgeMilliseconds = context.getProperty(MAX_AGE) != null ? context.getProperty(MAX_AGE).asTimePeriod(TimeUnit.MILLISECONDS) : null; if (bucketName == null || bucketName.trim().isEmpty()) { results.add(new ConfigVerificationResult.Builder() @@ -1144,36 +1202,28 @@ public List verify(final ProcessContext context, final return results; } - final S3BucketLister bucketLister = getS3BucketLister(context, client); - final long listingTimestamp = System.currentTimeMillis(); - // Attempt to perform a listing of objects in the S3 bucket try { - int listCount = 0; - int totalListCount = 0; - VersionListing versionListing; + final S3BucketLister bucketLister = getS3BucketLister(context, client); + int totalItems = 0; + int totalMatchingItems = 0; do { - versionListing = bucketLister.listVersions(); + final VersionListing versionListing = bucketLister.listVersions(); + final long currentTime = System.currentTimeMillis(); for (final S3VersionSummary versionSummary : versionListing.getVersionSummaries()) { - long lastModified = versionSummary.getLastModified().getTime(); - if ((maxAgeMilliseconds != null && (lastModified < (listingTimestamp - maxAgeMilliseconds))) - || lastModified > (listingTimestamp - minAgeMilliseconds)) { - continue; + totalItems++; + if (includeObjectInListing(versionSummary, currentTime)) { + totalMatchingItems++; } - - listCount++; } bucketLister.setNextMarker(); - - totalListCount += listCount; - - listCount = 0; } while (bucketLister.isTruncated()); results.add(new ConfigVerificationResult.Builder() .verificationStepName("Perform Listing") .outcome(Outcome.SUCCESSFUL) - .explanation("Successfully listed contents of bucket '" + bucketName + "', finding " + totalListCount + " objects matching the filter") + .explanation("Successfully listed contents of bucket '" + bucketName + "', finding " + totalItems + " total object(s). " + + totalMatchingItems + " objects matched the filter.") .build()); logger.info("Successfully verified configuration"); @@ -1189,4 +1239,27 @@ public List verify(final ProcessContext context, final return results; } + + /** + * Return whether to include the entity in the listing, based on the minimum and maximum object age (if configured). + */ + private boolean includeObjectInListing(final S3VersionSummary versionSummary, final long currentTimeMillis) { + final long lastModifiedTime = versionSummary.getLastModified().getTime(); + + return (minObjectAgeMilliseconds == null || currentTimeMillis >= lastModifiedTime + minObjectAgeMilliseconds) + && (maxObjectAgeMilliseconds == null || currentTimeMillis <= lastModifiedTime + maxObjectAgeMilliseconds); + } + + private S3VersionSummary objectSummaryToVersionSummary(final S3ObjectSummary objectSummary) { + final S3VersionSummary versionSummary = new S3VersionSummary(); + versionSummary.setBucketName(objectSummary.getBucketName()); + versionSummary.setETag(objectSummary.getETag()); + versionSummary.setKey(objectSummary.getKey()); + versionSummary.setLastModified(objectSummary.getLastModified()); + versionSummary.setOwner(objectSummary.getOwner()); + versionSummary.setSize(objectSummary.getSize()); + versionSummary.setStorageClass(objectSummary.getStorageClass()); + versionSummary.setIsLatest(true); + return versionSummary; + } } diff --git a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/PutS3Object.java b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/PutS3Object.java index 37fd0b5037353..3247f9a6a8d88 100644 --- a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/PutS3Object.java +++ b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/s3/PutS3Object.java @@ -71,8 +71,6 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -877,7 +875,6 @@ public void process(final InputStream in) throws IOException { private final Lock s3BucketLock = new ReentrantLock(); private final AtomicLong lastS3AgeOff = new AtomicLong(0L); - private final DateFormat logFormat = new SimpleDateFormat(); protected void ageoffS3Uploads(final ProcessContext context, final AmazonS3 s3, final long now, String bucket) { MultipartUploadListing oldUploads = getS3AgeoffListAndAgeoffLocalState(context, s3, now, bucket); @@ -940,10 +937,10 @@ protected void abortS3MultipartUpload(final AmazonS3 s3, final String bucket, fi try { s3.abortMultipartUpload(abortRequest); getLogger().info("Aborting out of date multipart upload, bucket {} key {} ID {}, initiated {}", - new Object[]{bucket, uploadKey, uploadId, logFormat.format(upload.getInitiated())}); + bucket, uploadKey, uploadId, upload.getInitiated()); } catch (AmazonClientException ace) { getLogger().info("Error trying to abort multipart upload from bucket {} with key {} and ID {}: {}", - new Object[]{bucket, uploadKey, uploadId, ace.getMessage()}); + bucket, uploadKey, uploadId, ace.getMessage()); } } diff --git a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/s3/TestListS3.java b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/s3/TestListS3.java index a64574cba2071..1a8259a268544 100644 --- a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/s3/TestListS3.java +++ b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/s3/TestListS3.java @@ -49,8 +49,8 @@ import org.mockito.Mockito; import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Collections; import java.util.Date; @@ -132,7 +132,7 @@ public void testList() { .verify(runner.getProcessContext(), runner.getLogger(), Collections.emptyMap()); assertEquals(ConfigVerificationResult.Outcome.SUCCESSFUL, results.get(0).getOutcome()); assertEquals(ConfigVerificationResult.Outcome.SUCCESSFUL, results.get(1).getOutcome()); - assertTrue(results.get(1).getExplanation().contains("finding 3 objects")); + assertTrue(results.get(1).getExplanation().contains("finding 3 total object(s)")); } @Test @@ -175,8 +175,8 @@ public void testListWithRecords() throws InitializationException { runner.assertAllFlowFilesTransferred(ListS3.REL_SUCCESS, 1); - final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - final String lastModifiedString = dateFormat.format(lastModified); + final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + final String lastModifiedString = dateTimeFormatter.format(lastModified.toInstant().atZone(ZoneOffset.systemDefault())); final MockFlowFile flowFile = runner.getFlowFilesForRelationship(ListS3.REL_SUCCESS).get(0); flowFile.assertAttributeEquals("record.count", "3"); @@ -568,4 +568,63 @@ public void testWriteUserMetadata() { Mockito.verify(mockS3Client, Mockito.never()).listVersions(Mockito.any()); } + + @Test + public void testNoTrackingList() { + runner.setProperty(ListS3.REGION, "eu-west-1"); + runner.setProperty(ListS3.BUCKET_WITHOUT_DEFAULT_VALUE, "test-bucket"); + runner.setProperty(ListS3.LISTING_STRATEGY, ListS3.NO_TRACKING); + + Date lastModified = new Date(); + ObjectListing objectListing = new ObjectListing(); + S3ObjectSummary objectSummary1 = new S3ObjectSummary(); + objectSummary1.setBucketName("test-bucket"); + objectSummary1.setKey("a"); + objectSummary1.setLastModified(lastModified); + objectListing.getObjectSummaries().add(objectSummary1); + S3ObjectSummary objectSummary2 = new S3ObjectSummary(); + objectSummary2.setBucketName("test-bucket"); + objectSummary2.setKey("b/c"); + objectSummary2.setLastModified(lastModified); + objectListing.getObjectSummaries().add(objectSummary2); + S3ObjectSummary objectSummary3 = new S3ObjectSummary(); + objectSummary3.setBucketName("test-bucket"); + objectSummary3.setKey("d/e"); + objectSummary3.setLastModified(lastModified); + objectListing.getObjectSummaries().add(objectSummary3); + Mockito.when(mockS3Client.listObjects(Mockito.any(ListObjectsRequest.class))).thenReturn(objectListing); + + runner.run(); + + ArgumentCaptor captureRequest = ArgumentCaptor.forClass(ListObjectsRequest.class); + Mockito.verify(mockS3Client, Mockito.times(1)).listObjects(captureRequest.capture()); + ListObjectsRequest request = captureRequest.getValue(); + assertEquals("test-bucket", request.getBucketName()); + assertFalse(request.isRequesterPays()); + Mockito.verify(mockS3Client, Mockito.never()).listVersions(Mockito.any()); + + runner.assertAllFlowFilesTransferred(ListS3.REL_SUCCESS, 3); + List flowFiles = runner.getFlowFilesForRelationship(ListS3.REL_SUCCESS); + MockFlowFile ff0 = flowFiles.get(0); + ff0.assertAttributeEquals("filename", "a"); + ff0.assertAttributeEquals("s3.bucket", "test-bucket"); + ff0.assertAttributeEquals("s3.region", "eu-west-1"); + String lastModifiedTimestamp = String.valueOf(lastModified.getTime()); + ff0.assertAttributeEquals("s3.lastModified", lastModifiedTimestamp); + flowFiles.get(1).assertAttributeEquals("filename", "b/c"); + flowFiles.get(2).assertAttributeEquals("filename", "d/e"); + + final List results = ((VerifiableProcessor) runner.getProcessor()) + .verify(runner.getProcessContext(), runner.getLogger(), Collections.emptyMap()); + assertEquals(ConfigVerificationResult.Outcome.SUCCESSFUL, results.get(0).getOutcome()); + assertEquals(ConfigVerificationResult.Outcome.SUCCESSFUL, results.get(1).getOutcome()); + assertTrue(results.get(1).getExplanation().contains("finding 3")); + + runner.clearTransferState(); + + runner.run(); + + runner.assertAllFlowFilesTransferred(ListS3.REL_SUCCESS, 3); + runner.getStateManager().assertStateEquals(ListS3.CURRENT_TIMESTAMP, null, Scope.CLUSTER); + } } diff --git a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-service-api/pom.xml b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-service-api/pom.xml index 553fce66ec11e..a7422bebc708a 100644 --- a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-service-api/pom.xml +++ b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-service-api/pom.xml @@ -40,6 +40,10 @@ com.amazonaws aws-java-sdk-s3 + + com.amazonaws + aws-java-sdk-sts + org.apache.nifi nifi-api diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProvider.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProvider.java index 2902e09206b91..03c7f59f99725 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProvider.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProvider.java @@ -28,19 +28,6 @@ import com.microsoft.graph.requests.extensions.IUserCollectionWithReferencesPage; import com.microsoft.graph.requests.extensions.IUserCollectionWithReferencesRequest; import com.microsoft.graph.requests.extensions.IUserCollectionWithReferencesRequestBuilder; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; import org.apache.nifi.authorization.AuthorizerConfigurationContext; import org.apache.nifi.authorization.Group; import org.apache.nifi.authorization.User; @@ -58,6 +45,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + /** * The AzureGraphUserGroupProvider provides support for retrieving users and * groups from Azure Active Directory (AAD) using graph rest-api & SDK. @@ -275,7 +275,7 @@ private Set getGroupsWith(String groupFilterList, String prefix, String Arrays.stream(groupFilterList.split(",")) .map(String::trim) .filter(s-> !s.isEmpty()) - .collect(Collectors.toList()) + .toList() ); } return Collections.unmodifiableSet(groupDisplayNames); @@ -309,14 +309,10 @@ private Set queryGroupsWith(String prefix, String suffix, String substri List currentPage = filterResults.getCurrentPage(); while (currentPage != null) { for (com.microsoft.graph.models.extensions.Group grp : currentPage) { - boolean filterEvaluation = true; - if (!StringUtils.isEmpty(suffix) && !grp.displayName.endsWith(suffix)) { - filterEvaluation = false; - } - if (!StringUtils.isEmpty(substring) && !grp.displayName.contains(substring)) { - filterEvaluation = false; - } - if (filterEvaluation) { + boolean suffixMatches = StringUtils.isEmpty(suffix) || grp.displayName.endsWith(suffix); + boolean substringMatches = StringUtils.isEmpty(substring) || grp.displayName.contains(substring); + + if (suffixMatches && substringMatches) { groups.add(grp.displayName); } } @@ -345,7 +341,7 @@ private UserGroupQueryResult getUsersFrom(String groupName, int pageSize) throws final List currentPage = results.getCurrentPage(); if (currentPage != null && !currentPage.isEmpty()) { - final com.microsoft.graph.models.extensions.Group graphGroup = results.getCurrentPage().get(0); + final com.microsoft.graph.models.extensions.Group graphGroup = results.getCurrentPage().getFirst(); final Group.Builder groupBuilder = new Group.Builder() .identifier(graphGroup.id) diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/ImmutableAzureGraphUserGroup.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/ImmutableAzureGraphUserGroup.java index 0aab27455973c..743623e389798 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/ImmutableAzureGraphUserGroup.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/main/java/org/apache/nifi/authorization/azure/ImmutableAzureGraphUserGroup.java @@ -17,7 +17,9 @@ package org.apache.nifi.authorization.azure; -import static java.util.stream.Collectors.toMap; +import org.apache.nifi.authorization.Group; +import org.apache.nifi.authorization.User; +import org.apache.nifi.authorization.UserAndGroups; import java.util.Collections; import java.util.HashMap; @@ -25,9 +27,7 @@ import java.util.Map; import java.util.Set; -import org.apache.nifi.authorization.Group; -import org.apache.nifi.authorization.User; -import org.apache.nifi.authorization.UserAndGroups; +import static java.util.stream.Collectors.toMap; public class ImmutableAzureGraphUserGroup { private final Set users; @@ -119,9 +119,7 @@ public static ImmutableAzureGraphUserGroup newInstance(final Set users, fi final Map groupsByObjectId = new HashMap<>(); final Map groupsByDisplayName = new HashMap<>(); final Map> groupsByUserObjectId = - users.stream().collect(toMap(User::getIdentifier, user -> { - return new HashSet(); - })); + users.stream().collect(toMap(User::getIdentifier, user -> new HashSet<>())); groups.forEach(group -> { groupsByObjectId.put(group.getIdentifier(), group); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/test/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProviderIT.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/test/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProviderIT.java index 7049bc4cd549d..f866971417d06 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/test/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProviderIT.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-graph-authorizer/src/test/java/org/apache/nifi/authorization/azure/AzureGraphUserGroupProviderIT.java @@ -31,16 +31,15 @@ import org.slf4j.LoggerFactory; import java.io.FileInputStream; -import java.io.IOException; +import java.util.HashSet; import java.util.List; import java.util.Properties; import java.util.Set; -import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; public class AzureGraphUserGroupProviderIT { private static final Logger logger = LoggerFactory.getLogger(AzureGraphUserGroupProviderIT.class); @@ -92,7 +91,7 @@ protected static String getGroupListInclusion() { private UserGroupProviderInitializationContext initContext; @BeforeEach - public void setup() throws IOException { + public void setup() { authContext = Mockito.mock(AuthorizerConfigurationContext.class); initContext = Mockito.mock(UserGroupProviderInitializationContext.class); @@ -115,7 +114,6 @@ private void setupTestingProvider() { testingProvider.onConfigured(authContext); } catch (final Exception exc) { logger.error("Error during setup; tests cannot run on this system."); - return; } } @@ -132,11 +130,11 @@ public void testWithGroupListFilter(){ setupTestingProvider(); - assertTrue(testingProvider.getGroups().size() > 0); - assertTrue(testingProvider.getUsers().size() > 0); + assertFalse(testingProvider.getGroups().isEmpty()); + assertFalse(testingProvider.getUsers().isEmpty()); UserAndGroups uag = testingProvider.getUserAndGroups(getKnownTestUserName()); assertNotNull(uag.getUser()); - assertTrue(uag.getGroups().size() > 0); + assertFalse(uag.getGroups().isEmpty()); } @@ -149,15 +147,15 @@ public void testWithPaging(){ setupTestingProvider(); - assertTrue(testingProvider.getGroups().size() > 0); - assertTrue(testingProvider.getUsers().size() > 0); + assertFalse(testingProvider.getGroups().isEmpty()); + assertFalse(testingProvider.getUsers().isEmpty()); UserAndGroups uag = testingProvider.getUserAndGroups(getKnownTestUserName()); assertNotNull(uag.getUser()); - assertTrue(uag.getGroups().size() > 0); + assertFalse(uag.getGroups().isEmpty()); String knownGroupName = getKnownTestGroupName(); - List search = testingProvider.getGroups().stream().filter(g-> g.getName().equals(knownGroupName)).collect(Collectors.toList()); - assertTrue(search.size() > 0); + List search = testingProvider.getGroups().stream().filter(g-> g.getName().equals(knownGroupName)).toList(); + assertFalse(search.isEmpty()); } @Test @@ -169,9 +167,9 @@ public void testWithGroupFilterPrefix(){ .thenReturn(new MockPropertyValue(prefix)); setupTestingProvider(); - assertTrue(testingProvider.getGroups().size() > 0); - List search = testingProvider.getGroups().stream().filter(g-> g.getName().equals(knownGroupName)).collect(Collectors.toList()); - assertTrue(search.size() > 0); + assertFalse(testingProvider.getGroups().isEmpty()); + List search = testingProvider.getGroups().stream().filter(g-> g.getName().equals(knownGroupName)).toList(); + assertFalse(search.isEmpty()); } @Test @@ -183,9 +181,9 @@ public void testWithGroupFilterSuffix(){ .thenReturn(new MockPropertyValue(suffix)); setupTestingProvider(); - assertTrue(testingProvider.getGroups().size() > 0); - List search = testingProvider.getGroups().stream().filter(g-> g.getName().equals(knownGroupName)).collect(Collectors.toList()); - assertTrue(search.size() > 0); + assertFalse(testingProvider.getGroups().isEmpty()); + List search = testingProvider.getGroups().stream().filter(g-> g.getName().equals(knownGroupName)).toList(); + assertFalse(search.isEmpty()); } @Test @@ -197,9 +195,9 @@ public void testWithGroupFilterSubstring(){ .thenReturn(new MockPropertyValue(substring)); setupTestingProvider(); - assertTrue(testingProvider.getGroups().size() > 0); - List search = testingProvider.getGroups().stream().filter( g-> g.getName().equals(knownGroupName)).collect(Collectors.toList()); - assertTrue(search.size() > 0); + assertFalse(testingProvider.getGroups().isEmpty()); + List search = testingProvider.getGroups().stream().filter( g-> g.getName().equals(knownGroupName)).toList(); + assertFalse(search.isEmpty()); } @Test @@ -213,8 +211,8 @@ public void testWithGroupFilterOperatorAndListInclusion(){ .thenReturn(new MockPropertyValue(getGroupListInclusion())); setupTestingProvider(); - assertTrue(testingProvider.getGroups().size() > 0); - Set search = testingProvider.getGroups().stream().collect(Collectors.toSet()); + assertFalse(testingProvider.getGroups().isEmpty()); + Set search = new HashSet<>(testingProvider.getGroups()); // check there is no duplicate group assertEquals(search.size(), testingProvider.getGroups().size()); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/main/java/org/apache/nifi/parameter/azure/AzureKeyVaultSecretsParameterProvider.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/main/java/org/apache/nifi/parameter/azure/AzureKeyVaultSecretsParameterProvider.java index 568dc49384c82..45bc98c4d2c2b 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/main/java/org/apache/nifi/parameter/azure/AzureKeyVaultSecretsParameterProvider.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/main/java/org/apache/nifi/parameter/azure/AzureKeyVaultSecretsParameterProvider.java @@ -34,9 +34,7 @@ import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.services.azure.AzureCredentialsService; -import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -78,15 +76,11 @@ public class AzureKeyVaultSecretsParameterProvider extends AbstractParameterProv static final String GROUP_NAME_TAG = "group-name"; - private static final List PROPERTIES; - - static { - final List props = new ArrayList<>(); - props.add(AZURE_CREDENTIALS_SERVICE); - props.add(KEY_VAULT_URI); - props.add(GROUP_NAME_PATTERN); - PROPERTIES = Collections.unmodifiableList(props); - } + private static final List PROPERTIES = List.of( + AZURE_CREDENTIALS_SERVICE, + KEY_VAULT_URI, + GROUP_NAME_PATTERN + ); @Override protected List getSupportedPropertyDescriptors() { @@ -94,11 +88,10 @@ protected List getSupportedPropertyDescriptors() { } @Override - public List fetchParameters(final ConfigurationContext context) throws IOException { + public List fetchParameters(final ConfigurationContext context) { final SecretClient secretClient = configureSecretClient(context); final List secrets = getAllSecrets(secretClient); - final List groups = getParameterGroupsFromSecrets(context, secrets); - return groups; + return getParameterGroupsFromSecrets(context, secrets); } @Override diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/test/java/org/apache/nifi/parameter/azure/TestAzureKeyVaultSecretsParameterProvider.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/test/java/org/apache/nifi/parameter/azure/TestAzureKeyVaultSecretsParameterProvider.java index 6e821d9b3e762..9d332037516ae 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/test/java/org/apache/nifi/parameter/azure/TestAzureKeyVaultSecretsParameterProvider.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-parameter-providers/src/test/java/org/apache/nifi/parameter/azure/TestAzureKeyVaultSecretsParameterProvider.java @@ -18,6 +18,7 @@ import com.azure.core.http.rest.PagedIterable; import com.azure.security.keyvault.secrets.SecretClient; +import com.azure.security.keyvault.secrets.implementation.SecretPropertiesHelper; import com.azure.security.keyvault.secrets.models.KeyVaultSecret; import com.azure.security.keyvault.secrets.models.SecretProperties; import org.apache.nifi.components.ConfigVerificationResult; @@ -37,13 +38,12 @@ import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -61,7 +61,7 @@ public class TestAzureKeyVaultSecretsParameterProvider { @Spy private AzureKeyVaultSecretsParameterProvider parameterProvider; - private final List mySecretParameters = Arrays.asList( + private final List mySecretParameters = List.of( parameter("paramA", "valueA"), parameter("paramB", "valueB"), parameter("otherC", "valueOther"), @@ -69,11 +69,11 @@ public class TestAzureKeyVaultSecretsParameterProvider { parameter("nonSensitiveE", "valueE"), parameter("otherF", "valueF") ); - private final List otherSecretParameters = Arrays.asList( + private final List otherSecretParameters = List.of( parameter("paramG", "valueG"), parameter("otherH", "valueOther") ); - private final List mockParameterGroups = Arrays.asList( + private final List mockParameterGroups = List.of( new ParameterGroup("MySecret", mySecretParameters), new ParameterGroup("OtherSecret", otherSecretParameters) ); @@ -84,79 +84,61 @@ public void setup() { } @Test - public void testFetchParametersWithNoSecrets() throws IOException, InitializationException { - final List parameterGroups = Collections.singletonList(new ParameterGroup("MySecret", Collections.emptyList())); + public void testFetchParametersWithNoSecrets() throws InitializationException { + final List parameterGroups = List.of(new ParameterGroup("MySecret", Collections.emptyList())); mockSecretClient(parameterGroups); runProviderTest(0, ConfigVerificationResult.Outcome.SUCCESSFUL); } @Test - public void testFetchParameters() throws IOException, InitializationException { + public void testFetchParameters() throws InitializationException { mockSecretClient(mockParameterGroups); - runProviderTest( 8, ConfigVerificationResult.Outcome.SUCCESSFUL); + runProviderTest(8, ConfigVerificationResult.Outcome.SUCCESSFUL); } @Test - public void testFetchDisabledParameters() throws IOException, InitializationException { - final List secretPropertiesList = new ArrayList<>(); - for (final ParameterGroup group : mockParameterGroups) { - for (final Parameter parameter : group.getParameters()) { - final SecretProperties secretProperties = mock(SecretProperties.class); - - when(secretProperties.isEnabled()).thenReturn(false); - - secretPropertiesList.add(secretProperties); - } + public void testFetchDisabledParameters() throws InitializationException { + final List secretPropertiesList = Stream + .generate(() -> new SecretProperties().setEnabled(false)) + .limit(mockParameterGroups.stream().mapToInt(group -> group.getParameters().size()).sum()) + .toList(); - } - - final PagedIterable mockIterable = mock(PagedIterable.class); - when(secretClient.listPropertiesOfSecrets()).thenReturn(mockIterable); - when(mockIterable.iterator()).thenReturn(secretPropertiesList.iterator()); - runProviderTest( 0, ConfigVerificationResult.Outcome.SUCCESSFUL); + mockListPropertiesOfSecrets(secretPropertiesList); + runProviderTest(0, ConfigVerificationResult.Outcome.SUCCESSFUL); } @Test - public void testFetchParametersWithNullTagsShouldNotThrowError() throws IOException, InitializationException { + public void testFetchParametersWithNullTagsShouldNotThrowError() throws InitializationException { final List secretPropertiesList = new ArrayList<>(); for (final ParameterGroup group : mockParameterGroups) { for (final Parameter parameter : group.getParameters()) { final String parameterName = parameter.getDescriptor().getName(); final String parameterValue = parameter.getValue(); - final KeyVaultSecret secret = mock(KeyVaultSecret.class); - when(secret.getName()).thenReturn(parameterName); - when(secret.getValue()).thenReturn(parameterValue); - final SecretProperties secretProperties = mock(SecretProperties.class); - when(secret.getProperties()).thenReturn(secretProperties); + final SecretProperties secretProperties = new SecretProperties(); + SecretPropertiesHelper.setName(secretProperties, parameterName); + secretProperties.setEnabled(true); - final Map tags = null; - when(secretProperties.getTags()).thenReturn(tags); + final KeyVaultSecret secret = new KeyVaultSecret(parameterName, parameterValue); + secret.setProperties(secretProperties); - when(secretProperties.getName()).thenReturn(parameterName); - when(secretProperties.getVersion()).thenReturn(null); - when(secretProperties.isEnabled()).thenReturn(true); when(secretClient.getSecret(eq(parameterName), any())).thenReturn(secret); - secretPropertiesList.add(secretProperties); } - } - final PagedIterable mockIterable = mock(PagedIterable.class); - when(secretClient.listPropertiesOfSecrets()).thenReturn(mockIterable); - when(mockIterable.iterator()).thenReturn(secretPropertiesList.iterator()); - runProviderTest( 0, ConfigVerificationResult.Outcome.SUCCESSFUL); + mockListPropertiesOfSecrets(secretPropertiesList); + runProviderTest(0, ConfigVerificationResult.Outcome.SUCCESSFUL); } @Test - public void testFetchParametersListFailure() throws IOException, InitializationException { + public void testFetchParametersListFailure() throws InitializationException { when(secretClient.listPropertiesOfSecrets()).thenThrow(new RuntimeException("Fake RuntimeException")); runProviderTest(0, ConfigVerificationResult.Outcome.FAILED); } @Test - public void testFetchParametersWithGroupNameRegex() throws IOException, InitializationException { + public void testFetchParametersWithGroupNameRegex() throws InitializationException { mockSecretClient(mockParameterGroups); final Map properties = new HashMap<>(); properties.put(AzureKeyVaultSecretsParameterProvider.GROUP_NAME_PATTERN, "MySecret"); @@ -169,44 +151,43 @@ private void mockSecretClient(final List mockGroups) { for (final Parameter parameter : group.getParameters()) { final String parameterName = parameter.getDescriptor().getName(); final String parameterValue = parameter.getValue(); - final KeyVaultSecret secret = mock(KeyVaultSecret.class); - when(secret.getName()).thenReturn(parameterName); - when(secret.getValue()).thenReturn(parameterValue); - final SecretProperties secretProperties = mock(SecretProperties.class); - when(secret.getProperties()).thenReturn(secretProperties); + final SecretProperties secretProperties = new SecretProperties(); + SecretPropertiesHelper.setName(secretProperties, parameterName); + secretProperties.setTags( + Map.of(AzureKeyVaultSecretsParameterProvider.GROUP_NAME_TAG, group.getGroupName()) + ); + secretProperties.setEnabled(true); - final Map tags = new HashMap<>(); - tags.put(AzureKeyVaultSecretsParameterProvider.GROUP_NAME_TAG, group.getGroupName()); - when(secretProperties.getTags()).thenReturn(tags); + final KeyVaultSecret secret = new KeyVaultSecret(parameterName, parameterValue); + secret.setProperties(secretProperties); - when(secretProperties.getName()).thenReturn(parameterName); - when(secretProperties.getVersion()).thenReturn(null); - when(secretProperties.isEnabled()).thenReturn(true); when(secretClient.getSecret(eq(parameterName), any())).thenReturn(secret); - secretPropertiesList.add(secretProperties); } - } + mockListPropertiesOfSecrets(secretPropertiesList); + } + + private void mockListPropertiesOfSecrets(final List secretPropertiesList) { final PagedIterable mockIterable = mock(PagedIterable.class); - when(secretClient.listPropertiesOfSecrets()).thenReturn(mockIterable); when(mockIterable.iterator()).thenReturn(secretPropertiesList.iterator()); + when(secretClient.listPropertiesOfSecrets()).thenReturn(mockIterable); } - private List runProviderTest(final int expectedCount, - final ConfigVerificationResult.Outcome expectedOutcome) - throws IOException, InitializationException { - final Map properties = new HashMap<>(); - properties.put(AzureKeyVaultSecretsParameterProvider.GROUP_NAME_PATTERN, ".*"); - return runProviderTestWithProperties(expectedCount, expectedOutcome, properties); + private void runProviderTest(final int expectedCount, final ConfigVerificationResult.Outcome expectedOutcome) + throws InitializationException { + runProviderTestWithProperties( + expectedCount, expectedOutcome, + Map.of(AzureKeyVaultSecretsParameterProvider.GROUP_NAME_PATTERN, ".*") + ); } - private List runProviderTestWithProperties(final int expectedCount, - final ConfigVerificationResult.Outcome expectedOutcome, - final Map properties) - throws InitializationException, IOException { + private void runProviderTestWithProperties(final int expectedCount, + final ConfigVerificationResult.Outcome expectedOutcome, + final Map properties) + throws InitializationException { final MockParameterProviderInitializationContext initContext = new MockParameterProviderInitializationContext("id", "name", new MockComponentLog("providerId", parameterProvider)); parameterProvider.initialize(initContext); @@ -219,9 +200,9 @@ private List runProviderTestWithProperties(final int expectedCou assertThrows(RuntimeException.class, () -> parameterProvider.fetchParameters(mockConfigurationContext)); } else { parameterGroups = parameterProvider.fetchParameters(mockConfigurationContext); - final int parameterCount = (int) parameterGroups.stream() - .flatMap(group -> group.getParameters().stream()) - .count(); + final int parameterCount = parameterGroups.stream() + .mapToInt(group -> group.getParameters().size()) + .sum(); assertEquals(expectedCount, parameterCount); } @@ -229,9 +210,7 @@ private List runProviderTestWithProperties(final int expectedCou final List results = ((VerifiableParameterProvider) parameterProvider).verify(mockConfigurationContext, initContext.getLogger()); assertEquals(1, results.size()); - assertEquals(expectedOutcome, results.get(0).getOutcome()); - - return parameterGroups; + assertEquals(expectedOutcome, results.getFirst().getOutcome()); } private static Parameter parameter(final String name, final String value) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml index 5885515aa1026..202e427b5521a 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/pom.xml @@ -111,7 +111,12 @@ com.microsoft.azure.kusto kusto-data - 4.0.4 + 5.0.3 + + + com.microsoft.azure.kusto + kusto-ingest + 5.0.3 org.slf4j @@ -194,6 +199,12 @@ 2.0.0-SNAPSHOT test + + io.projectreactor + reactor-test + 3.5.11 + test + diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java index 1e2692922ed33..89fee5701c257 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureBlobProcessor_v12.java @@ -33,10 +33,8 @@ import org.apache.nifi.services.azure.storage.AzureStorageCredentialsDetails_v12; import org.apache.nifi.services.azure.storage.AzureStorageCredentialsService_v12; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Supplier; @@ -80,10 +78,7 @@ public abstract class AbstractAzureBlobProcessor_v12 extends AbstractProcessor { .description("Unsuccessful operations will be transferred to the failure relationship.") .build(); - private static final Set RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - REL_SUCCESS, - REL_FAILURE - ))); + private static final Set RELATIONSHIPS = Set.of(REL_SUCCESS, REL_FAILURE); private volatile BlobServiceClientFactory clientFactory; @@ -112,9 +107,7 @@ protected BlobServiceClient getStorageClient(PropertyContext context, PropertyDe final AzureStorageCredentialsService_v12 credentialsService = context.getProperty(storageCredentialsServiceProperty).asControllerService(AzureStorageCredentialsService_v12.class); final AzureStorageCredentialsDetails_v12 credentialsDetails = credentialsService.getCredentialsDetails(attributes); - final BlobServiceClient storageClient = clientFactory.getStorageClient(credentialsDetails); - - return storageClient; + return clientFactory.getStorageClient(credentialsDetails); } protected Map createBlobAttributesMap(BlobClient blobClient) { @@ -132,7 +125,7 @@ protected void applyStandardBlobAttributes(Map attributes, BlobC } protected void applyBlobMetadata(Map attributes, BlobClient blobClient) { - Supplier props = new Supplier() { + Supplier props = new Supplier<>() { BlobProperties properties; public BlobProperties get() { if (properties == null) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java index 8a958e5880caf..bb62bd54006d8 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/AbstractAzureDataLakeStorageProcessor.java @@ -37,9 +37,7 @@ import org.apache.nifi.services.azure.storage.ADLSCredentialsDetails; import org.apache.nifi.services.azure.storage.ADLSCredentialsService; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -91,10 +89,7 @@ public abstract class AbstractAzureDataLakeStorageProcessor extends AbstractProc .description("Files that could not be written to Azure storage for some reason are transferred to this relationship") .build(); - private static final Set RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( - REL_SUCCESS, - REL_FAILURE - ))); + private static final Set RELATIONSHIPS = Set.of(REL_SUCCESS, REL_FAILURE); public static final String TEMP_FILE_DIRECTORY = "_nifitempdirectory"; @@ -119,12 +114,9 @@ public DataLakeServiceClient getStorageClient(PropertyContext context, FlowFile final Map attributes = flowFile != null ? flowFile.getAttributes() : Collections.emptyMap(); final ADLSCredentialsService credentialsService = context.getProperty(ADLS_CREDENTIALS_SERVICE).asControllerService(ADLSCredentialsService.class); - final ADLSCredentialsDetails credentialsDetails = credentialsService.getCredentialsDetails(attributes); - final DataLakeServiceClient storageClient = clientFactory.getStorageClient(credentialsDetails); - - return storageClient; + return clientFactory.getStorageClient(credentialsDetails); } public static String evaluateFileSystemProperty(ProcessContext context, FlowFile flowFile) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/ClientSideEncryptionSupport.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/ClientSideEncryptionSupport.java index af3c90e3ce915..e451cb026741c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/ClientSideEncryptionSupport.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/ClientSideEncryptionSupport.java @@ -38,20 +38,19 @@ import javax.crypto.spec.SecretKeySpec; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Optional; public interface ClientSideEncryptionSupport { - List KEY_OPERATIONS = Arrays.asList(KeyOperation.WRAP_KEY, KeyOperation.UNWRAP_KEY); + List KEY_OPERATIONS = List.of(KeyOperation.WRAP_KEY, KeyOperation.UNWRAP_KEY); PropertyDescriptor CSE_KEY_TYPE = new PropertyDescriptor.Builder() .name("Client-Side Encryption Key Type") .displayName("Client-Side Encryption Key Type") .required(true) .allowableValues(ClientSideEncryptionMethod.class) - .defaultValue(ClientSideEncryptionMethod.NONE.getValue()) + .defaultValue(ClientSideEncryptionMethod.NONE) .description("Specifies the key type to use for client-side encryption.") .build(); @@ -77,8 +76,7 @@ public interface ClientSideEncryptionSupport { default Collection validateClientSideEncryptionProperties(ValidationContext validationContext) { final List validationResults = new ArrayList<>(); - final String cseKeyTypeValue = validationContext.getProperty(CSE_KEY_TYPE).getValue(); - final ClientSideEncryptionMethod cseKeyType = ClientSideEncryptionMethod.valueOf(cseKeyTypeValue); + final ClientSideEncryptionMethod cseKeyType = validationContext.getProperty(CSE_KEY_TYPE).asAllowableValue(ClientSideEncryptionMethod.class); final String cseKeyId = validationContext.getProperty(CSE_KEY_ID).getValue(); final String cseLocalKey = validationContext.getProperty(CSE_LOCAL_KEY).getValue(); if (cseKeyType != ClientSideEncryptionMethod.NONE && StringUtils.isBlank(cseKeyId)) { @@ -116,8 +114,7 @@ default List validateLocalKey(String keyHex) { } default boolean isClientSideEncryptionEnabled(PropertyContext context) { - final String cseKeyTypeValue = context.getProperty(CSE_KEY_TYPE).getValue(); - final ClientSideEncryptionMethod cseKeyType = ClientSideEncryptionMethod.valueOf(cseKeyTypeValue); + final ClientSideEncryptionMethod cseKeyType = context.getProperty(CSE_KEY_TYPE).asAllowableValue(ClientSideEncryptionMethod.class); return cseKeyType != ClientSideEncryptionMethod.NONE; } @@ -144,18 +141,14 @@ default Optional getKeyWrapAlgorithm(byte[] keyBytes) { final int keySize256 = 32; final int keySize384 = 48; final int keySize512 = 64; - switch (keyBytes.length) { - case keySize128: - return Optional.of(KeyWrapAlgorithm.A128KW.toString()); - case keySize192: - return Optional.of(KeyWrapAlgorithm.A192KW.toString()); - case keySize256: - case keySize384: - case keySize512: - // Default to longest allowed key length for wrap - return Optional.of(KeyWrapAlgorithm.A256KW.toString()); - default: - return Optional.empty(); - } + + return switch (keyBytes.length) { + case keySize128 -> Optional.of(KeyWrapAlgorithm.A128KW.toString()); + case keySize192 -> Optional.of(KeyWrapAlgorithm.A192KW.toString()); + case keySize256, keySize384, keySize512 -> + // Default to the longest allowed key length for wrap + Optional.of(KeyWrapAlgorithm.A256KW.toString()); + default -> Optional.empty(); + }; } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AbstractAzureCosmosDBProcessor.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AbstractAzureCosmosDBProcessor.java index fcc9d0c7a4138..b9c1a3b3a500e 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AbstractAzureCosmosDBProcessor.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AbstractAzureCosmosDBProcessor.java @@ -27,12 +27,6 @@ import com.azure.cosmos.models.CosmosContainerProperties; import com.azure.cosmos.models.CosmosContainerResponse; import com.azure.cosmos.models.CosmosDatabaseResponse; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.annotation.lifecycle.OnStopped; import org.apache.nifi.components.PropertyDescriptor; @@ -45,6 +39,10 @@ import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.services.azure.cosmos.AzureCosmosDBConnectionService; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + public abstract class AbstractAzureCosmosDBProcessor extends AbstractProcessor { static final Relationship REL_SUCCESS = new Relationship.Builder() @@ -57,11 +55,6 @@ public abstract class AbstractAzureCosmosDBProcessor extends AbstractProcessor { .description("All FlowFiles that cannot be written to Cosmos DB are routed to this relationship") .build(); - static final Relationship REL_ORIGINAL = new Relationship.Builder() - .name("original") - .description("All input FlowFiles that are part of a successful are routed to this relationship") - .build(); - static final PropertyDescriptor CONNECTION_SERVICE = new PropertyDescriptor.Builder() .name("azure-cosmos-db-connection-service") .displayName("Cosmos DB Connection Service") @@ -94,28 +87,15 @@ public abstract class AbstractAzureCosmosDBProcessor extends AbstractProcessor { .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .build(); - static final PropertyDescriptor CHARACTER_SET = new PropertyDescriptor.Builder() - .name("charactor-set") - .displayName("Charactor Set") - .description("The Character Set in which the data is encoded") - .required(false) - .addValidator(StandardValidators.CHARACTER_SET_VALIDATOR) - .defaultValue("UTF-8") - .build(); - - static final List descriptors; - - static { - List _temp = new ArrayList<>(); - _temp.add(CONNECTION_SERVICE); - _temp.add(AzureCosmosDBUtils.URI); - _temp.add(AzureCosmosDBUtils.DB_ACCESS_KEY); - _temp.add(AzureCosmosDBUtils.CONSISTENCY); - _temp.add(DATABASE_NAME); - _temp.add(CONTAINER_ID); - _temp.add(PARTITION_KEY); - descriptors = Collections.unmodifiableList(_temp); - } + static final List descriptors = List.of( + CONNECTION_SERVICE, + AzureCosmosDBUtils.URI, + AzureCosmosDBUtils.DB_ACCESS_KEY, + AzureCosmosDBUtils.CONSISTENCY, + DATABASE_NAME, + CONTAINER_ID, + PARTITION_KEY + ); private CosmosClient cosmosClient; private CosmosContainer container; @@ -132,43 +112,24 @@ public void onScheduled(final ProcessContext context) throws CosmosException { final String uri = context.getProperty(AzureCosmosDBUtils.URI).getValue(); final String accessKey = context.getProperty(AzureCosmosDBUtils.DB_ACCESS_KEY).getValue(); final String selectedConsistency = context.getProperty(AzureCosmosDBUtils.CONSISTENCY).getValue(); - final ConsistencyLevel clevel; - switch (selectedConsistency) { - case AzureCosmosDBUtils.CONSISTENCY_STRONG: - clevel = ConsistencyLevel.STRONG; - break; - case AzureCosmosDBUtils.CONSISTENCY_CONSISTENT_PREFIX: - clevel = ConsistencyLevel.CONSISTENT_PREFIX; - break; - case AzureCosmosDBUtils.CONSISTENCY_SESSION: - clevel = ConsistencyLevel.SESSION; - break; - case AzureCosmosDBUtils.CONSISTENCY_BOUNDED_STALENESS: - clevel = ConsistencyLevel.BOUNDED_STALENESS; - break; - case AzureCosmosDBUtils.CONSISTENCY_EVENTUAL: - clevel = ConsistencyLevel.EVENTUAL; - break; - default: - clevel = ConsistencyLevel.SESSION; - } + final ConsistencyLevel consistencyLevel = AzureCosmosDBUtils.determineConsistencyLevel(selectedConsistency); if (cosmosClient != null) { onStopped(); } if (logger.isDebugEnabled()) { logger.debug("Creating CosmosClient"); } - createCosmosClient(uri, accessKey, clevel); + createCosmosClient(uri, accessKey, consistencyLevel); } getCosmosDocumentContainer(context); doPostActionOnSchedule(context); } - protected void createCosmosClient(final String uri, final String accessKey, final ConsistencyLevel clevel) { + protected void createCosmosClient(final String uri, final String accessKey, final ConsistencyLevel consistencyLevel) { this.cosmosClient = new CosmosClientBuilder() .endpoint(uri) .key(accessKey) - .consistencyLevel(clevel) + .consistencyLevel(consistencyLevel) .buildClient(); } @@ -194,7 +155,7 @@ protected void getCosmosDocumentContainer(final ProcessContext context) throws C public final void onStopped() { final ComponentLog logger = getLogger(); if (connectionService == null && cosmosClient != null) { - // close client only when cosmoclient is created in Processor. + // close client only when cosmoClient is created in Processor. if(logger.isDebugEnabled()) { logger.debug("Closing CosmosClient"); } @@ -235,7 +196,7 @@ protected String getConsistencyLevel(final ProcessContext context) { @Override protected Collection customValidate(ValidationContext context) { - List retVal = new ArrayList<>(); + List validationResults = new ArrayList<>(); boolean connectionServiceIsSet = context.getProperty(CONNECTION_SERVICE).isSet(); boolean uriIsSet = context.getProperty(AzureCosmosDBUtils.URI).isSet(); @@ -252,7 +213,7 @@ protected Collection customValidate(ValidationContext context) AzureCosmosDBUtils.URI.getDisplayName(), AzureCosmosDBUtils.DB_ACCESS_KEY.getDisplayName() ); - retVal.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); } else if (!connectionServiceIsSet && (!uriIsSet || !accessKeyIsSet)) { // If connection Service is not set, Both of the Processor variable URI and accessKey // should be set. @@ -261,21 +222,21 @@ protected Collection customValidate(ValidationContext context) AzureCosmosDBUtils.URI.getDisplayName(), AzureCosmosDBUtils.DB_ACCESS_KEY.getDisplayName() ); - retVal.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); } if (!databaseIsSet) { final String msg = AbstractAzureCosmosDBProcessor.DATABASE_NAME.getDisplayName() + " must be set."; - retVal.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); } if (!collectionIsSet) { final String msg = AbstractAzureCosmosDBProcessor.CONTAINER_ID.getDisplayName() + " must be set."; - retVal.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); } if (!partitionIsSet) { final String msg = AbstractAzureCosmosDBProcessor.PARTITION_KEY.getDisplayName() + " must be set."; - retVal.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().valid(false).explanation(msg).build()); } - return retVal; + return validationResults; } protected CosmosClient getCosmosClient() { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AzureCosmosDBUtils.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AzureCosmosDBUtils.java index 3b4fe220d5dca..5e34eecf2c7eb 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AzureCosmosDBUtils.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/AzureCosmosDBUtils.java @@ -18,6 +18,7 @@ */ package org.apache.nifi.processors.azure.cosmos.document; +import com.azure.cosmos.ConsistencyLevel; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.processor.util.StandardValidators; @@ -60,4 +61,15 @@ public final class AzureCosmosDBUtils { CONSISTENCY_CONSISTENT_PREFIX, CONSISTENCY_EVENTUAL) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .build(); + + public static ConsistencyLevel determineConsistencyLevel(final String consistency) { + return switch (consistency) { + case CONSISTENCY_STRONG -> ConsistencyLevel.STRONG; + case CONSISTENCY_CONSISTENT_PREFIX -> ConsistencyLevel.CONSISTENT_PREFIX; + case CONSISTENCY_BOUNDED_STALENESS -> ConsistencyLevel.BOUNDED_STALENESS; + case CONSISTENCY_EVENTUAL -> ConsistencyLevel.EVENTUAL; + case CONSISTENCY_SESSION -> ConsistencyLevel.SESSION; + default -> ConsistencyLevel.SESSION; + }; + } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecord.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecord.java index d258f8786fb67..bed246b966c41 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecord.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecord.java @@ -47,14 +47,13 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.stream.Stream; -@Tags({ "azure", "cosmos", "insert", "record", "put" }) +@Tags({"azure", "cosmos", "insert", "record", "put"}) @InputRequirement(Requirement.INPUT_REQUIRED) @CapabilityDescription("This processor is a record-aware processor for inserting data into Cosmos DB with Core SQL API. It uses a configured record reader and " + "schema to read an incoming record set from the body of a Flowfile and then inserts those records into " + @@ -67,49 +66,37 @@ public class PutAzureCosmosDBRecord extends AbstractAzureCosmosDBProcessor { static final AllowableValue UPSERT_CONFLICT = new AllowableValue("UPSERT", "Upsert", "Conflicting records will be upserted, and FlowFile will not be routed to failure"); static final PropertyDescriptor RECORD_READER_FACTORY = new PropertyDescriptor.Builder() - .name("record-reader") - .displayName("Record Reader") - .description("Specifies the Controller Service to use for parsing incoming data and determining the data's schema") - .identifiesControllerService(RecordReaderFactory.class) - .required(true) - .build(); + .name("record-reader") + .displayName("Record Reader") + .description("Specifies the Controller Service to use for parsing incoming data and determining the data's schema") + .identifiesControllerService(RecordReaderFactory.class) + .required(true) + .build(); static final PropertyDescriptor INSERT_BATCH_SIZE = new PropertyDescriptor.Builder() - .name("insert-batch-size") - .displayName("Insert Batch Size") - .description("The number of records to group together for one single insert operation against Cosmos DB") - .defaultValue("20") - .required(false) - .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) - .build(); + .name("insert-batch-size") + .displayName("Insert Batch Size") + .description("The number of records to group together for one single insert operation against Cosmos DB") + .defaultValue("20") + .required(false) + .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR) + .build(); static final PropertyDescriptor CONFLICT_HANDLE_STRATEGY = new PropertyDescriptor.Builder() - .name("azure-cosmos-db-conflict-handling-strategy") - .displayName("Cosmos DB Conflict Handling Strategy") - .description("Choose whether to ignore or upsert when conflict error occurs during insertion") - .required(false) - .allowableValues(IGNORE_CONFLICT, UPSERT_CONFLICT) - .defaultValue(IGNORE_CONFLICT.getValue()) - .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .build(); - - - private final static Set relationships; - private final static List propertyDescriptors; - - static { - List _propertyDescriptors = new ArrayList<>(); - _propertyDescriptors.addAll(descriptors); - _propertyDescriptors.add(RECORD_READER_FACTORY); - _propertyDescriptors.add(INSERT_BATCH_SIZE); - _propertyDescriptors.add(CONFLICT_HANDLE_STRATEGY); - propertyDescriptors = Collections.unmodifiableList(_propertyDescriptors); - - final Set _relationships = new HashSet<>(); - _relationships.add(REL_SUCCESS); - _relationships.add(REL_FAILURE); - relationships = Collections.unmodifiableSet(_relationships); - } + .name("azure-cosmos-db-conflict-handling-strategy") + .displayName("Cosmos DB Conflict Handling Strategy") + .description("Choose whether to ignore or upsert when conflict error occurs during insertion") + .required(false) + .allowableValues(IGNORE_CONFLICT, UPSERT_CONFLICT) + .defaultValue(IGNORE_CONFLICT) + .addValidator(StandardValidators.NON_BLANK_VALIDATOR) + .build(); + + private final static Set relationships = Set.of(REL_SUCCESS, REL_FAILURE); + private final static List propertyDescriptors = Stream.concat( + descriptors.stream(), + Stream.of(RECORD_READER_FACTORY, INSERT_BATCH_SIZE, CONFLICT_HANDLE_STRATEGY) + ).toList(); @Override public Set getRelationships() { @@ -121,19 +108,19 @@ public List getSupportedPropertyDescriptors() { return propertyDescriptors; } - protected void bulkInsert(final List> records) throws CosmosException{ + protected void bulkInsert(final List> records) throws CosmosException { // In the future, this method will be replaced by calling createItems API // for example, this.container.createItems(records); // currently, no createItems API available in Azure Cosmos Java SDK final ComponentLog logger = getLogger(); final CosmosContainer container = getContainer(); - for (Map record : records){ + for (Map record : records) { try { container.createItem(record); } catch (ConflictException e) { // insert with unique id is expected. In case conflict occurs, use the selected strategy. // By default, it will ignore. - if (conflictHandlingStrategy != null && conflictHandlingStrategy.equals(UPSERT_CONFLICT.getValue())){ + if (conflictHandlingStrategy != null && conflictHandlingStrategy.equals(UPSERT_CONFLICT.getValue())) { container.upsertItem(record); } else { if (logger.isDebugEnabled()) { @@ -168,7 +155,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session while ((record = reader.nextRecord()) != null) { // Convert each Record to HashMap Map contentMap = (Map) DataTypeUtils.convertRecordFieldtoObject(record, RecordFieldType.RECORD.getRecordDataType(schema)); - if(contentMap.containsKey("id")) { + if (contentMap.containsKey("id")) { final Object idObj = contentMap.get("id"); final String idStr = (idObj == null) ? "" : String.valueOf(idObj); if (idObj == null || StringUtils.isBlank(idStr)) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/KustoIngestDataFormat.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/KustoIngestDataFormat.java new file mode 100644 index 0000000000000..403de446865c6 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/KustoIngestDataFormat.java @@ -0,0 +1,68 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.data.explorer; + +import org.apache.nifi.components.DescribedValue; + +public enum KustoIngestDataFormat implements DescribedValue { + AVRO("avro", "An Avro format with support for logical types and for the snappy compression codec"), + APACHEAVRO("apacheavro", "An Avro format with support for logical types and for the snappy compression codec."), + CSV("csv", "A text file with comma-separated values (,). For more information, see RFC 4180: Common Format " + + "and MIME Type for Comma-Separated Values (CSV) Files."), + JSON("json", "A text file containing JSON objects separated by \\n or \\r\\n. For more information, " + + "see JSON Lines (JSONL)."), + MULTIJSON("multijson", "A text file containing a JSON array of property containers (each representing a record) or any " + + "number of property containers separated by spaces, \\n or \\r\\n. Each property container may be " + + "spread across multiple lines. This format is preferable to JSON unless the data is not property " + + "containers."), + ORC("orc", "An ORC file."), + PARQUET("parquet", "A parquet file."), + PSV("psv", "A text file with values separated by vertical bars (|)."), + SCSV("scsv", "A text file with values separated by semicolons (;)."), + SOHSV("sohsv", "A text file with SOH-separated values. (SOH is the ASCII code point 1. " + + "This format is used by Hive in HDInsight)."), + TSV("tsv", "A text file with tab delimited values (\\t)."), + TSVE("tsve", "A text file with tab-delimited values (\\t). A backslash (\\) is used as escape character."), + TXT("txt", "A text file with lines separated by \\n. Empty lines are skipped"); + + private final String kustoValue; + private final String description; + + KustoIngestDataFormat(String kustoValue, String description) { + this.kustoValue = kustoValue; + this.description = description; + } + + public String getKustoValue() { + return kustoValue; + } + + @Override + public String getValue() { + return this.getKustoValue(); + } + + @Override + public String getDisplayName() { + return kustoValue; + } + + @Override + public String getDescription() { + return description; + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/PutAzureDataExplorer.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/PutAzureDataExplorer.java new file mode 100644 index 0000000000000..f1c35442d5bd0 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/PutAzureDataExplorer.java @@ -0,0 +1,250 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.data.explorer; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.annotation.behavior.InputRequirement; +import org.apache.nifi.annotation.documentation.CapabilityDescription; +import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnScheduled; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.expression.ExpressionLanguageScope; +import org.apache.nifi.flowfile.FlowFile; +import org.apache.nifi.processor.AbstractProcessor; +import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processor.ProcessSession; +import org.apache.nifi.processor.Relationship; +import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.services.azure.data.explorer.KustoIngestService; +import org.apache.nifi.services.azure.data.explorer.KustoIngestionRequest; +import org.apache.nifi.services.azure.data.explorer.KustoIngestionResult; + +import java.io.IOException; +import java.io.InputStream; +import java.time.Duration; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +@Tags({"Azure", "Kusto", "ADX", "Explorer", "Data"}) +@CapabilityDescription("Acts as an Azure Data Explorer sink which sends FlowFiles to the provided endpoint. " + + "Data can be sent through queued ingestion or streaming ingestion to the Azure Data Explorer cluster.") +@InputRequirement(InputRequirement.Requirement.INPUT_REQUIRED) +public class PutAzureDataExplorer extends AbstractProcessor { + + public static final Relationship SUCCESS = new Relationship.Builder() + .name("success") + .description("Ingest processing succeeded") + .build(); + + public static final Relationship FAILURE = new Relationship.Builder() + .name("failure") + .description("Ingest processing failed") + .build(); + + public static final PropertyDescriptor INGEST_SERVICE = new PropertyDescriptor + .Builder().name("Kusto Ingest Service") + .displayName("Kusto Ingest Service") + .description("Azure Data Explorer Kusto Ingest Service") + .required(true) + .identifiesControllerService(KustoIngestService.class) + .build(); + + public static final PropertyDescriptor DATABASE_NAME = new PropertyDescriptor.Builder() + .name("Database Name") + .displayName("Database Name") + .description("Azure Data Explorer Database Name for ingesting data") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor TABLE_NAME = new PropertyDescriptor.Builder() + .name("Table Name") + .displayName("Table Name") + .description("Azure Data Explorer Table Name for ingesting data") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor MAPPING_NAME = new PropertyDescriptor + .Builder().name("Ingest Mapping Name") + .displayName("Ingest Mapping Name") + .description("The name of the mapping responsible for storing the data in the appropriate columns.") + .required(false) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor DATA_FORMAT = new PropertyDescriptor.Builder() + .name("Data Format") + .displayName("Data Format") + .description("The format of the data that is sent to Azure Data Explorer. Supported formats include: avro, csv, json") + .required(true) + .allowableValues(KustoIngestDataFormat.class) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor PARTIALLY_SUCCEEDED_ROUTING_STRATEGY = new PropertyDescriptor.Builder() + .name("Partially Succeeded Routing Strategy") + .displayName("Partially Succeeded Routing Strategy") + .description("Defines where to route FlowFiles that resulted in a partially succeeded status.") + .required(true) + .allowableValues(SUCCESS.getName(), FAILURE.getName()) + .defaultValue(FAILURE.getName()) + .build(); + + public static final PropertyDescriptor STREAMING_ENABLED = new PropertyDescriptor + .Builder().name("Streaming Enabled") + .displayName("Streaming Enabled") + .description("Whether to stream data to Azure Data Explorer.") + .required(true) + .allowableValues(Boolean.TRUE.toString(), Boolean.FALSE.toString()) + .addValidator(StandardValidators.BOOLEAN_VALIDATOR) + .defaultValue(Boolean.FALSE.toString()) + .build(); + + public static final PropertyDescriptor IGNORE_FIRST_RECORD = new PropertyDescriptor.Builder() + .name("Ingestion Ignore First Record") + .displayName("Ingestion Ignore First Record") + .description("Defines whether ignore first record while ingestion.") + .required(true) + .allowableValues(Boolean.TRUE.toString(), Boolean.FALSE.toString()) + .defaultValue(Boolean.FALSE.toString()) + .addValidator(StandardValidators.BOOLEAN_VALIDATOR) + .build(); + + public static final PropertyDescriptor POLL_FOR_INGEST_STATUS = new PropertyDescriptor + .Builder().name("Poll for Ingest Status") + .displayName("Poll for Ingest Status") + .description("Determines whether to poll on ingestion status after an ingestion to Azure Data Explorer is completed") + .required(true) + .allowableValues(Boolean.TRUE.toString(), Boolean.FALSE.toString()) + .addValidator(StandardValidators.BOOLEAN_VALIDATOR) + .defaultValue(Boolean.FALSE.toString()) + .build(); + + public static final PropertyDescriptor INGEST_STATUS_POLLING_TIMEOUT = new PropertyDescriptor.Builder() + .name("Ingest Status Polling Timeout") + .displayName("Ingest Status Polling Timeout") + .description("Defines the total amount time to poll for ingestion status") + .required(true) + .dependsOn(POLL_FOR_INGEST_STATUS, Boolean.TRUE.toString()) + .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) + .defaultValue("5 m") + .build(); + + public static final PropertyDescriptor INGEST_STATUS_POLLING_INTERVAL = new PropertyDescriptor.Builder() + .name("Ingest Status Polling Interval") + .displayName("Ingest Status Polling Interval") + .description("Defines the value of interval of time to poll for ingestion status") + .required(true) + .dependsOn(POLL_FOR_INGEST_STATUS, Boolean.TRUE.toString()) + .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) + .defaultValue("5 s") + .build(); + + private static final List descriptors = List.of( + INGEST_SERVICE, + DATABASE_NAME, + TABLE_NAME, + MAPPING_NAME, + DATA_FORMAT, + PARTIALLY_SUCCEEDED_ROUTING_STRATEGY, + STREAMING_ENABLED, + IGNORE_FIRST_RECORD, + POLL_FOR_INGEST_STATUS, + INGEST_STATUS_POLLING_TIMEOUT, + INGEST_STATUS_POLLING_INTERVAL + ); + + private static final Set relationships = Set.of(SUCCESS, FAILURE); + + private transient KustoIngestService service; + + @Override + public Set getRelationships() { + return relationships; + } + + @Override + public final List getSupportedPropertyDescriptors() { + return descriptors; + } + + @OnScheduled + public void onScheduled(final ProcessContext context) { + service = context.getProperty(INGEST_SERVICE).asControllerService(KustoIngestService.class); + + final String database = context.getProperty(DATABASE_NAME).getValue(); + final String tableName = context.getProperty(TABLE_NAME).getValue(); + if (!service.isTableReadable(database, tableName)) { + throw new ProcessException(String.format("Database [%s] Table [%s] not readable", database, tableName)); + } + + final boolean streamingEnabled = context.getProperty(STREAMING_ENABLED).evaluateAttributeExpressions().asBoolean(); + if (streamingEnabled && !service.isStreamingPolicyEnabled(database)) { + throw new ProcessException(String.format("Database [%s] streaming policy not enabled", database)); + } + } + + @Override + public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException { + FlowFile flowFile = session.get(); + if (flowFile == null) { + return; + } + + final String databaseName = context.getProperty(DATABASE_NAME).evaluateAttributeExpressions(flowFile).getValue(); + final String tableName = context.getProperty(TABLE_NAME).evaluateAttributeExpressions(flowFile).getValue(); + final String dataFormat = context.getProperty(DATA_FORMAT).evaluateAttributeExpressions(flowFile).getValue(); + final String mappingName = context.getProperty(MAPPING_NAME).evaluateAttributeExpressions(flowFile).getValue(); + final String partiallySucceededRoutingStrategy = context.getProperty(PARTIALLY_SUCCEEDED_ROUTING_STRATEGY).getValue(); + final Duration ingestionStatusPollingTimeout = Duration.ofSeconds(context.getProperty(INGEST_STATUS_POLLING_TIMEOUT).asTimePeriod(TimeUnit.SECONDS)); + final Duration ingestionStatusPollingInterval = Duration.ofSeconds(context.getProperty(INGEST_STATUS_POLLING_INTERVAL).asTimePeriod(TimeUnit.SECONDS)); + final boolean ignoreFirstRecord = context.getProperty(IGNORE_FIRST_RECORD).asBoolean(); + final boolean streamingEnabled = context.getProperty(STREAMING_ENABLED).evaluateAttributeExpressions().asBoolean(); + final boolean pollOnIngestionStatus = context.getProperty(POLL_FOR_INGEST_STATUS).evaluateAttributeExpressions().asBoolean(); + + Relationship transferRelationship = FAILURE; + try (final InputStream inputStream = session.read(flowFile)) { + final KustoIngestionRequest request = new KustoIngestionRequest(streamingEnabled, pollOnIngestionStatus, inputStream, databaseName, + tableName, dataFormat, mappingName, ignoreFirstRecord, ingestionStatusPollingTimeout, ingestionStatusPollingInterval); + + final KustoIngestionResult result = service.ingestData(request); + if (result == KustoIngestionResult.SUCCEEDED) { + getLogger().info("Ingest {} for {}", result.getStatus(), flowFile); + transferRelationship = SUCCESS; + } else if (result == KustoIngestionResult.FAILED) { + getLogger().error("Ingest {} for {}", result.getStatus(), flowFile); + } else if (result == KustoIngestionResult.PARTIALLY_SUCCEEDED) { + getLogger().warn("Ingest {} for {}", result.getStatus(), flowFile); + flowFile = session.putAttribute(flowFile, "ingestion_status", KustoIngestionResult.PARTIALLY_SUCCEEDED.getStatus()); + if (StringUtils.equalsIgnoreCase(partiallySucceededRoutingStrategy, SUCCESS.getName())) { + transferRelationship = SUCCESS; + } + } + } catch (final IOException e) { + getLogger().error("Azure Data Explorer Ingest processing failed {}", e, flowFile); + } + + session.transfer(flowFile, transferRelationship); + } +} \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorer.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorer.java index 574d95464551e..e4f8fdf2f651c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorer.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorer.java @@ -32,12 +32,10 @@ import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; -import org.apache.nifi.services.azure.data.explorer.KustoQueryService; import org.apache.nifi.services.azure.data.explorer.KustoQueryResponse; +import org.apache.nifi.services.azure.data.explorer.KustoQueryService; import java.io.InputStream; -import java.util.Arrays; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -92,9 +90,9 @@ public class QueryAzureDataExplorer extends AbstractProcessor { protected static final String APPLICATION_JSON = "application/json"; - private static final Set RELATIONSHIPS = new LinkedHashSet<>(Arrays.asList(SUCCESS, FAILURE)); + private static final Set RELATIONSHIPS = Set.of(SUCCESS, FAILURE); - private static final List DESCRIPTORS = Arrays.asList(KUSTO_QUERY_SERVICE, DATABASE_NAME, QUERY); + private static final List DESCRIPTORS = List.of(KUSTO_QUERY_SERVICE, DATABASE_NAME, QUERY); private volatile KustoQueryService service; diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/ConsumeAzureEventHub.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/ConsumeAzureEventHub.java index 4d99a53fae3e8..57a42bf295556 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/ConsumeAzureEventHub.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/ConsumeAzureEventHub.java @@ -16,6 +16,7 @@ */ package org.apache.nifi.processors.azure.eventhub; +import com.azure.core.amqp.AmqpClientOptions; import com.azure.core.amqp.AmqpTransportType; import com.azure.core.amqp.exception.AmqpErrorCondition; import com.azure.core.amqp.exception.AmqpException; @@ -24,6 +25,7 @@ import com.azure.core.util.HttpClientOptions; import com.azure.identity.ManagedIdentityCredential; import com.azure.identity.ManagedIdentityCredentialBuilder; +import com.azure.messaging.eventhubs.CheckpointStore; import com.azure.messaging.eventhubs.EventData; import com.azure.messaging.eventhubs.EventProcessorClient; import com.azure.messaging.eventhubs.EventProcessorClientBuilder; @@ -36,16 +38,20 @@ import com.azure.storage.blob.BlobContainerAsyncClient; import com.azure.storage.blob.BlobContainerClientBuilder; import org.apache.nifi.annotation.behavior.InputRequirement; +import org.apache.nifi.annotation.behavior.Stateful; import org.apache.nifi.annotation.behavior.TriggerSerially; import org.apache.nifi.annotation.behavior.WritesAttribute; import org.apache.nifi.annotation.behavior.WritesAttributes; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.annotation.lifecycle.OnStopped; import org.apache.nifi.components.AllowableValue; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.ValidationContext; import org.apache.nifi.components.ValidationResult; +import org.apache.nifi.components.state.Scope; +import org.apache.nifi.components.state.StateManager; import org.apache.nifi.controller.ControllerService; import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.flowfile.FlowFile; @@ -58,6 +64,9 @@ import org.apache.nifi.processor.ProcessSessionFactory; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStrategy; +import org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStore; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.ComponentStateCheckpointStoreException; import org.apache.nifi.processors.azure.eventhub.position.EarliestEventPositionProvider; import org.apache.nifi.processors.azure.eventhub.position.LegacyBlobStorageEventPositionProvider; import org.apache.nifi.processors.azure.eventhub.utils.AzureEventHubUtils; @@ -70,6 +79,7 @@ import org.apache.nifi.serialization.record.Record; import org.apache.nifi.serialization.record.RecordSchema; import org.apache.nifi.shared.azure.eventhubs.AzureEventHubComponent; +import org.apache.nifi.shared.azure.eventhubs.AzureEventHubTransportType; import org.apache.nifi.util.StopWatch; import org.apache.nifi.util.StringUtils; @@ -79,19 +89,20 @@ import java.io.OutputStream; import java.time.Duration; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.regex.Pattern; import static org.apache.commons.lang3.StringUtils.defaultIfBlank; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKey.CLIENT_ID; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKey.CLUSTERED; @Tags({"azure", "microsoft", "cloud", "eventhub", "events", "streaming", "streams"}) @CapabilityDescription("Receives messages from Microsoft Azure Event Hubs with checkpointing to ensure consistent event processing. " @@ -100,6 +111,8 @@ + "In clustered environment, ConsumeAzureEventHub processor instances form a consumer group and the messages are distributed among the cluster nodes " + "(each message is processed on one cluster node only).") @InputRequirement(InputRequirement.Requirement.INPUT_FORBIDDEN) +@Stateful(scopes = {Scope.LOCAL, Scope.CLUSTER}, description = "Local state is used to store the client id. " + + "Cluster state is used to store partition ownership and checkpoint information when component state is configured as the checkpointing strategy.") @TriggerSerially @WritesAttributes({ @WritesAttribute(attribute = "eventhub.enqueued.timestamp", description = "The time (in milliseconds since epoch, UTC) at which the message was enqueued in the event hub"), @@ -183,10 +196,10 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem static final PropertyDescriptor INITIAL_OFFSET = new PropertyDescriptor.Builder() .name("event-hub-initial-offset") .displayName("Initial Offset") - .description("Specify where to start receiving messages if offset is not stored in Azure Storage.") + .description("Specify where to start receiving messages if offset is not yet stored in the checkpoint store.") .required(true) .allowableValues(INITIAL_OFFSET_START_OF_STREAM, INITIAL_OFFSET_END_OF_STREAM) - .defaultValue(INITIAL_OFFSET_END_OF_STREAM.getValue()) + .defaultValue(INITIAL_OFFSET_END_OF_STREAM) .build(); static final PropertyDescriptor PREFETCH_COUNT = new PropertyDescriptor.Builder() .name("event-hub-prefetch-count") @@ -220,12 +233,23 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem static final PropertyDescriptor RECEIVE_TIMEOUT = new PropertyDescriptor.Builder() .name("event-hub-message-receive-timeout") .displayName("Message Receive Timeout") - .description("The amount of time this consumer should wait to receive the Prefetch Count before returning.") + .description("The amount of time this consumer should wait to receive the Batch Size before returning.") .defaultValue("1 min") .addValidator(StandardValidators.TIME_PERIOD_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .required(true) .build(); + + static final PropertyDescriptor CHECKPOINT_STRATEGY = new PropertyDescriptor.Builder() + .name("checkpoint-strategy") + .displayName("Checkpoint Strategy") + .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .required(true) + .allowableValues(CheckpointStrategy.class) + .defaultValue(CheckpointStrategy.AZURE_BLOB_STORAGE.getValue()) + .description("Specifies which strategy to use for storing and retrieving partition ownership and checkpoint information for each partition.") + .build(); + static final PropertyDescriptor STORAGE_ACCOUNT_NAME = new PropertyDescriptor.Builder() .name("storage-account-name") .displayName("Storage Account Name") @@ -233,6 +257,7 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .required(true) + .dependsOn(CHECKPOINT_STRATEGY, CheckpointStrategy.AZURE_BLOB_STORAGE) .build(); static final PropertyDescriptor STORAGE_ACCOUNT_KEY = new PropertyDescriptor.Builder() .name("storage-account-key") @@ -242,6 +267,7 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .required(false) + .dependsOn(CHECKPOINT_STRATEGY, CheckpointStrategy.AZURE_BLOB_STORAGE) .build(); static final PropertyDescriptor STORAGE_SAS_TOKEN = new PropertyDescriptor.Builder() .name("storage-sas-token") @@ -252,6 +278,7 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem "Token must start with a ? character.")) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .required(false) + .dependsOn(CHECKPOINT_STRATEGY, CheckpointStrategy.AZURE_BLOB_STORAGE) .build(); static final PropertyDescriptor STORAGE_CONTAINER_NAME = new PropertyDescriptor.Builder() .name("storage-container-name") @@ -261,6 +288,7 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .required(false) + .dependsOn(CHECKPOINT_STRATEGY, CheckpointStrategy.AZURE_BLOB_STORAGE) .build(); static final Relationship REL_SUCCESS = new Relationship.Builder() @@ -275,50 +303,39 @@ public class ConsumeAzureEventHub extends AbstractSessionFactoryProcessor implem " the contents of the message will be routed to this Relationship as its own individual FlowFile.") .build(); - private static final Set RELATIONSHIPS; - private static final Set RECORD_RELATIONSHIPS; - private static final List PROPERTIES; - - static { - PROPERTIES = Collections.unmodifiableList(Arrays.asList( - NAMESPACE, - EVENT_HUB_NAME, - SERVICE_BUS_ENDPOINT, - TRANSPORT_TYPE, - ACCESS_POLICY_NAME, - POLICY_PRIMARY_KEY, - USE_MANAGED_IDENTITY, - CONSUMER_GROUP, - RECORD_READER, - RECORD_WRITER, - INITIAL_OFFSET, - PREFETCH_COUNT, - BATCH_SIZE, - RECEIVE_TIMEOUT, - STORAGE_ACCOUNT_NAME, - STORAGE_ACCOUNT_KEY, - STORAGE_SAS_TOKEN, - STORAGE_CONTAINER_NAME, - PROXY_CONFIGURATION_SERVICE - )); - - Set relationships = new HashSet<>(); - relationships.add(REL_SUCCESS); - RELATIONSHIPS = Collections.unmodifiableSet(relationships); - - relationships.add(REL_PARSE_FAILURE); - RECORD_RELATIONSHIPS = Collections.unmodifiableSet(relationships); - } + private static final Set RELATIONSHIPS = Set.of(REL_SUCCESS); + private static final Set RECORD_RELATIONSHIPS = Set.of(REL_SUCCESS, REL_PARSE_FAILURE); + private static final List PROPERTIES = List.of(NAMESPACE, + EVENT_HUB_NAME, + SERVICE_BUS_ENDPOINT, + TRANSPORT_TYPE, + ACCESS_POLICY_NAME, + POLICY_PRIMARY_KEY, + USE_MANAGED_IDENTITY, + CONSUMER_GROUP, + RECORD_READER, + RECORD_WRITER, + INITIAL_OFFSET, + PREFETCH_COUNT, + BATCH_SIZE, + RECEIVE_TIMEOUT, + CHECKPOINT_STRATEGY, + STORAGE_ACCOUNT_NAME, + STORAGE_ACCOUNT_KEY, + STORAGE_SAS_TOKEN, + STORAGE_CONTAINER_NAME, + PROXY_CONFIGURATION_SERVICE + ); private volatile ProcessSessionFactory processSessionFactory; private volatile EventProcessorClient eventProcessorClient; private volatile RecordReaderFactory readerFactory; private volatile RecordSetWriterFactory writerFactory; - private volatile String namespaceName; private volatile boolean isRecordReaderSet = false; private volatile boolean isRecordWriterSet = false; - private volatile String serviceBusEndpoint; + + private volatile String clientId; @Override protected List getSupportedPropertyDescriptors() { @@ -342,6 +359,7 @@ protected Collection customValidate(ValidationContext validati final ControllerService recordWriter = validationContext.getProperty(RECORD_WRITER).asControllerService(); final String storageAccountKey = validationContext.getProperty(STORAGE_ACCOUNT_KEY).evaluateAttributeExpressions().getValue(); final String storageSasToken = validationContext.getProperty(STORAGE_SAS_TOKEN).evaluateAttributeExpressions().getValue(); + final CheckpointStrategy checkpointStrategy = CheckpointStrategy.valueOf(validationContext.getProperty(CHECKPOINT_STRATEGY).getValue()); if ((recordReader != null && recordWriter == null) || (recordReader == null && recordWriter != null)) { results.add(new ValidationResult.Builder() @@ -352,24 +370,26 @@ protected Collection customValidate(ValidationContext validati .build()); } - if (StringUtils.isBlank(storageAccountKey) && StringUtils.isBlank(storageSasToken)) { - results.add(new ValidationResult.Builder() - .subject(String.format("%s or %s", - STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) - .explanation(String.format("either %s or %s should be set.", - STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) - .valid(false) - .build()); - } + if (checkpointStrategy == CheckpointStrategy.AZURE_BLOB_STORAGE) { + if (StringUtils.isBlank(storageAccountKey) && StringUtils.isBlank(storageSasToken)) { + results.add(new ValidationResult.Builder() + .subject(String.format("%s or %s", + STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) + .explanation(String.format("either %s or %s should be set.", + STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) + .valid(false) + .build()); + } - if (StringUtils.isNotBlank(storageAccountKey) && StringUtils.isNotBlank(storageSasToken)) { - results.add(new ValidationResult.Builder() - .subject(String.format("%s or %s", - STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) - .explanation(String.format("%s and %s should not be set at the same time.", - STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) - .valid(false) - .build()); + if (StringUtils.isNotBlank(storageAccountKey) && StringUtils.isNotBlank(storageSasToken)) { + results.add(new ValidationResult.Builder() + .subject(String.format("%s or %s", + STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) + .explanation(String.format("%s and %s should not be set at the same time.", + STORAGE_ACCOUNT_KEY.getDisplayName(), STORAGE_SAS_TOKEN.getDisplayName())) + .valid(false) + .build()); + } } results.addAll(AzureEventHubUtils.customValidate(ACCESS_POLICY_NAME, POLICY_PRIMARY_KEY, validationContext)); return results; @@ -384,6 +404,24 @@ public void onPropertyModified(final PropertyDescriptor descriptor, final String } } + @OnScheduled + public void onScheduled(final ProcessContext context) throws IOException { + StateManager stateManager = context.getStateManager(); + + String clientId = stateManager.getState(Scope.LOCAL).get(CLIENT_ID.key()); + if (clientId == null) { + clientId = UUID.randomUUID().toString(); + + final Map clientState = new HashMap<>(); + clientState.put(CLIENT_ID.key(), clientId); + clientState.put(CLUSTERED.key(), Boolean.toString(getNodeTypeProvider().isClustered())); + + stateManager.setState(clientState, Scope.LOCAL); + } + + this.clientId = clientId; + } + @Override public void onTrigger(final ProcessContext context, final ProcessSessionFactory sessionFactory) { if (eventProcessorClient == null) { @@ -412,40 +450,57 @@ public void stopClient() { processSessionFactory = null; readerFactory = null; writerFactory = null; + clientId = null; } } protected EventProcessorClient createClient(final ProcessContext context) { - namespaceName = context.getProperty(NAMESPACE).evaluateAttributeExpressions().getValue(); + final String eventHubNamespace = context.getProperty(NAMESPACE).evaluateAttributeExpressions().getValue(); final String eventHubName = context.getProperty(EVENT_HUB_NAME).evaluateAttributeExpressions().getValue(); + final String serviceBusEndpoint = context.getProperty(SERVICE_BUS_ENDPOINT).getValue(); final String consumerGroup = context.getProperty(CONSUMER_GROUP).evaluateAttributeExpressions().getValue(); - final String containerName = defaultIfBlank(context.getProperty(STORAGE_CONTAINER_NAME).evaluateAttributeExpressions().getValue(), eventHubName); - final String storageConnectionString = createStorageConnectionString(context); - final BlobContainerClientBuilder blobContainerClientBuilder = new BlobContainerClientBuilder() - .connectionString(storageConnectionString) - .containerName(containerName); - final ProxyOptions storageProxyOptions = AzureStorageUtils.getProxyOptions(context); - if (storageProxyOptions != null) { - blobContainerClientBuilder.clientOptions(new HttpClientOptions().setProxyOptions(storageProxyOptions)); + final String fullyQualifiedNamespace = String.format("%s%s", eventHubNamespace, serviceBusEndpoint); + + final CheckpointStore checkpointStore; + final Map legacyPartitionEventPosition; + + final CheckpointStrategy checkpointStrategy = CheckpointStrategy.valueOf(context.getProperty(CHECKPOINT_STRATEGY).getValue()); + + if (checkpointStrategy == CheckpointStrategy.AZURE_BLOB_STORAGE) { + final String containerName = defaultIfBlank(context.getProperty(STORAGE_CONTAINER_NAME).evaluateAttributeExpressions().getValue(), eventHubName); + final String storageConnectionString = createStorageConnectionString(context); + final BlobContainerClientBuilder blobContainerClientBuilder = new BlobContainerClientBuilder() + .connectionString(storageConnectionString) + .containerName(containerName); + final ProxyOptions storageProxyOptions = AzureStorageUtils.getProxyOptions(context); + if (storageProxyOptions != null) { + blobContainerClientBuilder.clientOptions(new HttpClientOptions().setProxyOptions(storageProxyOptions)); + } + final BlobContainerAsyncClient blobContainerAsyncClient = blobContainerClientBuilder.buildAsyncClient(); + checkpointStore = new BlobCheckpointStore(blobContainerAsyncClient); + legacyPartitionEventPosition = getLegacyPartitionEventPosition(blobContainerAsyncClient, consumerGroup); + } else { + ComponentStateCheckpointStore componentStateCheckpointStore = new ComponentStateCheckpointStore(clientId, context.getStateManager()); + componentStateCheckpointStore.cleanUp(fullyQualifiedNamespace, eventHubName, consumerGroup); + checkpointStore = componentStateCheckpointStore; + legacyPartitionEventPosition = Collections.emptyMap(); } - final BlobContainerAsyncClient blobContainerAsyncClient = blobContainerClientBuilder.buildAsyncClient(); - final BlobCheckpointStore checkpointStore = new BlobCheckpointStore(blobContainerAsyncClient); final Long receiveTimeout = context.getProperty(RECEIVE_TIMEOUT).evaluateAttributeExpressions().asTimePeriod(TimeUnit.MILLISECONDS); final Duration maxWaitTime = Duration.ofMillis(receiveTimeout); final Integer maxBatchSize = context.getProperty(BATCH_SIZE).evaluateAttributeExpressions().asInteger(); - final AmqpTransportType transportType = AmqpTransportType.fromString(context.getProperty(TRANSPORT_TYPE).getValue()); + final AmqpTransportType transportType = context.getProperty(TRANSPORT_TYPE).asAllowableValue(AzureEventHubTransportType.class).asAmqpTransportType(); final EventProcessorClientBuilder eventProcessorClientBuilder = new EventProcessorClientBuilder() .transportType(transportType) .consumerGroup(consumerGroup) + .clientOptions(new AmqpClientOptions().setIdentifier(clientId)) .trackLastEnqueuedEventProperties(true) .checkpointStore(checkpointStore) .processError(errorProcessor) .processEventBatch(eventBatchProcessor, maxBatchSize, maxWaitTime); - final String fullyQualifiedNamespace = String.format("%s%s", namespaceName, serviceBusEndpoint); final boolean useManagedIdentity = context.getProperty(USE_MANAGED_IDENTITY).asBoolean(); if (useManagedIdentity) { final ManagedIdentityCredentialBuilder managedIdentityCredentialBuilder = new ManagedIdentityCredentialBuilder(); @@ -453,7 +508,7 @@ protected EventProcessorClient createClient(final ProcessContext context) { eventProcessorClientBuilder.credential(fullyQualifiedNamespace, eventHubName, managedIdentityCredential); } else { final String policyName = context.getProperty(ACCESS_POLICY_NAME).evaluateAttributeExpressions().getValue(); - final String policyKey = context.getProperty(POLICY_PRIMARY_KEY).evaluateAttributeExpressions().getValue(); + final String policyKey = context.getProperty(POLICY_PRIMARY_KEY).getValue(); final AzureNamedKeyCredential azureNamedKeyCredential = new AzureNamedKeyCredential(policyName, policyKey); eventProcessorClientBuilder.credential(fullyQualifiedNamespace, eventHubName, azureNamedKeyCredential); } @@ -463,7 +518,6 @@ protected EventProcessorClient createClient(final ProcessContext context) { eventProcessorClientBuilder.prefetchCount(prefetchCount); } - final Map legacyPartitionEventPosition = getLegacyPartitionEventPosition(blobContainerAsyncClient, consumerGroup); if (legacyPartitionEventPosition.isEmpty()) { final String initialOffset = context.getProperty(INITIAL_OFFSET).getValue(); // EventPosition.latest() is the default behavior is absence of existing checkpoints @@ -482,9 +536,8 @@ protected EventProcessorClient createClient(final ProcessContext context) { } protected String getTransitUri(final PartitionContext partitionContext) { - return String.format("amqps://%s%s/%s/ConsumerGroups/%s/Partitions/%s", - namespaceName, - serviceBusEndpoint, + return String.format("amqps://%s/%s/ConsumerGroups/%s/Partitions/%s", + partitionContext.getFullyQualifiedNamespace(), partitionContext.getEventHubName(), partitionContext.getConsumerGroup(), partitionContext.getPartitionId() @@ -522,8 +575,7 @@ protected String getTransitUri(final PartitionContext partitionContext) { final PartitionContext partitionContext = errorContext.getPartitionContext(); final Throwable throwable = errorContext.getThrowable(); - if (throwable instanceof AmqpException) { - final AmqpException amqpException = (AmqpException) throwable; + if (throwable instanceof AmqpException amqpException) { if (amqpException.getErrorCondition() == AmqpErrorCondition.LINK_STOLEN) { getLogger().info("Partition was stolen by another consumer instance from the consumer group. Namespace [{}] Event Hub [{}] Consumer Group [{}] Partition [{}]. {}", partitionContext.getFullyQualifiedNamespace(), @@ -535,7 +587,14 @@ protected String getTransitUri(final PartitionContext partitionContext) { } } - getLogger().error("Receive Events failed Namespace [{}] Event Hub [{}] Consumer Group [{}] Partition [{}]", + final String errorMessage; + if (throwable instanceof ComponentStateCheckpointStoreException) { + errorMessage = "Failed to access Component State Checkpoint Store"; + } else { + errorMessage = "Receive Events failed"; + } + + getLogger().error(errorMessage + ". Namespace [{}] Event Hub [{}] Consumer Group [{}] Partition [{}]", partitionContext.getFullyQualifiedNamespace(), partitionContext.getEventHubName(), partitionContext.getConsumerGroup(), @@ -681,8 +740,7 @@ private void transferTo( private String createStorageConnectionString(final ProcessContext context) { final String storageAccountName = context.getProperty(STORAGE_ACCOUNT_NAME).evaluateAttributeExpressions().getValue(); - - serviceBusEndpoint = context.getProperty(SERVICE_BUS_ENDPOINT).getValue(); + final String serviceBusEndpoint = context.getProperty(SERVICE_BUS_ENDPOINT).getValue(); final String domainName = serviceBusEndpoint.replace(".servicebus.", ""); final String storageAccountKey = context.getProperty(STORAGE_ACCOUNT_KEY).evaluateAttributeExpressions().getValue(); final String storageSasToken = context.getProperty(STORAGE_SAS_TOKEN).evaluateAttributeExpressions().getValue(); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHub.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHub.java index 5f813bd47da2e..f2620ac5d5c8b 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHub.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHub.java @@ -54,12 +54,12 @@ import org.apache.nifi.processors.azure.eventhub.utils.AzureEventHubUtils; import org.apache.nifi.scheduling.ExecutionNode; import org.apache.nifi.shared.azure.eventhubs.AzureEventHubComponent; +import org.apache.nifi.shared.azure.eventhubs.AzureEventHubTransportType; import org.apache.nifi.util.StopWatch; import java.time.Duration; import java.time.Instant; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -159,26 +159,21 @@ public class GetAzureEventHub extends AbstractProcessor implements AzureEventHub .description("Any FlowFile that is successfully received from the event hub will be transferred to this Relationship.") .build(); - private final static List propertyDescriptors; - private final static Set relationships; - - static { - propertyDescriptors = List.of( - NAMESPACE, - EVENT_HUB_NAME, - SERVICE_BUS_ENDPOINT, - TRANSPORT_TYPE, - ACCESS_POLICY, - POLICY_PRIMARY_KEY, - USE_MANAGED_IDENTITY, - CONSUMER_GROUP, - ENQUEUE_TIME, - RECEIVER_FETCH_SIZE, - RECEIVER_FETCH_TIMEOUT, - PROXY_CONFIGURATION_SERVICE - ); - relationships = Collections.singleton(REL_SUCCESS); - } + private final static List propertyDescriptors = List.of( + NAMESPACE, + EVENT_HUB_NAME, + SERVICE_BUS_ENDPOINT, + TRANSPORT_TYPE, + ACCESS_POLICY, + POLICY_PRIMARY_KEY, + USE_MANAGED_IDENTITY, + CONSUMER_GROUP, + ENQUEUE_TIME, + RECEIVER_FETCH_SIZE, + RECEIVER_FETCH_TIMEOUT, + PROXY_CONFIGURATION_SERVICE + ); + private final static Set relationships = Set.of(REL_SUCCESS); private final Map partitionEventPositions = new ConcurrentHashMap<>(); @@ -365,7 +360,7 @@ private EventHubClientBuilder createEventHubClientBuilder(final ProcessContext c final String serviceBusEndpoint = context.getProperty(SERVICE_BUS_ENDPOINT).getValue(); final boolean useManagedIdentity = context.getProperty(USE_MANAGED_IDENTITY).asBoolean(); final String fullyQualifiedNamespace = String.format("%s%s", namespace, serviceBusEndpoint); - final AmqpTransportType transportType = AmqpTransportType.fromString(context.getProperty(TRANSPORT_TYPE).getValue()); + final AmqpTransportType transportType = context.getProperty(TRANSPORT_TYPE).asAllowableValue(AzureEventHubTransportType.class).asAmqpTransportType(); final EventHubClientBuilder eventHubClientBuilder = new EventHubClientBuilder(); eventHubClientBuilder.transportType(transportType); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHub.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHub.java index ab95bab69d1d7..57bb5c09ede3f 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHub.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHub.java @@ -48,13 +48,13 @@ import org.apache.nifi.processors.azure.eventhub.utils.AzureEventHubUtils; import org.apache.nifi.processors.azure.storage.utils.FlowFileResultCarrier; import org.apache.nifi.shared.azure.eventhubs.AzureEventHubComponent; +import org.apache.nifi.shared.azure.eventhubs.AzureEventHubTransportType; import org.apache.nifi.stream.io.StreamUtils; import org.apache.nifi.util.StopWatch; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -119,28 +119,19 @@ public class PutAzureEventHub extends AbstractProcessor implements AzureEventHub .description("Any FlowFile that could not be sent to the event hub will be transferred to this Relationship.") .build(); - private final static List propertyDescriptors; - private final static Set relationships; - - static { - final List configuredDescriptors = new ArrayList<>(); - configuredDescriptors.add(NAMESPACE); - configuredDescriptors.add(EVENT_HUB_NAME); - configuredDescriptors.add(SERVICE_BUS_ENDPOINT); - configuredDescriptors.add(TRANSPORT_TYPE); - configuredDescriptors.add(ACCESS_POLICY); - configuredDescriptors.add(POLICY_PRIMARY_KEY); - configuredDescriptors.add(USE_MANAGED_IDENTITY); - configuredDescriptors.add(PARTITIONING_KEY_ATTRIBUTE_NAME); - configuredDescriptors.add(MAX_BATCH_SIZE); - configuredDescriptors.add(PROXY_CONFIGURATION_SERVICE); - propertyDescriptors = Collections.unmodifiableList(configuredDescriptors); - - final Set configuredRelationships = new HashSet<>(); - configuredRelationships.add(REL_SUCCESS); - configuredRelationships.add(REL_FAILURE); - relationships = Collections.unmodifiableSet(configuredRelationships); - } + private final static List propertyDescriptors = List.of( + NAMESPACE, + EVENT_HUB_NAME, + SERVICE_BUS_ENDPOINT, + TRANSPORT_TYPE, + ACCESS_POLICY, + POLICY_PRIMARY_KEY, + USE_MANAGED_IDENTITY, + PARTITIONING_KEY_ATTRIBUTE_NAME, + MAX_BATCH_SIZE, + PROXY_CONFIGURATION_SERVICE + ); + private final static Set relationships = Set.of(REL_SUCCESS, REL_FAILURE); private EventHubProducerClient eventHubProducerClient; @@ -196,7 +187,7 @@ protected EventHubProducerClient createEventHubProducerClient(final ProcessConte final String namespace = context.getProperty(NAMESPACE).getValue(); final String serviceBusEndpoint = context.getProperty(SERVICE_BUS_ENDPOINT).getValue(); final String eventHubName = context.getProperty(EVENT_HUB_NAME).getValue(); - final AmqpTransportType transportType = AmqpTransportType.fromString(context.getProperty(TRANSPORT_TYPE).getValue()); + final AmqpTransportType transportType = context.getProperty(TRANSPORT_TYPE).asAllowableValue(AzureEventHubTransportType.class).asAmqpTransportType(); try { final EventHubClientBuilder eventHubClientBuilder = new EventHubClientBuilder(); @@ -228,9 +219,9 @@ private void processFlowFileResults( ) { try { for (final FlowFileResultCarrier flowFileResult : flowFileResults) { - final FlowFile flowFile = flowFileResult.getFlowFile(); + final FlowFile flowFile = flowFileResult.flowFile(); - if (flowFileResult.getResult() == REL_SUCCESS) { + if (flowFileResult.result() == REL_SUCCESS) { final String namespace = context.getProperty(NAMESPACE).getValue(); final String eventHubName = context.getProperty(EVENT_HUB_NAME).getValue(); final String serviceBusEndpoint = context.getProperty(SERVICE_BUS_ENDPOINT).getValue(); @@ -238,7 +229,7 @@ private void processFlowFileResults( session.getProvenanceReporter().send(flowFile, transitUri, stopWatch.getElapsed(TimeUnit.MILLISECONDS)); session.transfer(flowFile, REL_SUCCESS); } else { - final Throwable processException = flowFileResult.getException(); + final Throwable processException = flowFileResult.exception(); getLogger().error("Send failed {}", flowFile, processException); session.transfer(session.penalize(flowFile), REL_FAILURE); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStoreKey.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStoreKey.java new file mode 100644 index 0000000000000..ccca12ebe60d0 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStoreKey.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +public enum CheckpointStoreKey { + + CLIENT_ID("_clientId"), + CLUSTERED("_clustered"); + + private final String key; + + CheckpointStoreKey(String key) { + this.key = key; + } + + public String key() { + return key; + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStoreKeyPrefix.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStoreKeyPrefix.java new file mode 100644 index 0000000000000..8f92ed69dad3a --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStoreKeyPrefix.java @@ -0,0 +1,33 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +public enum CheckpointStoreKeyPrefix { + + OWNERSHIP("ownership"), + CHECKPOINT("checkpoint"); + + private final String keyPrefix; + + CheckpointStoreKeyPrefix(String keyPrefix) { + this.keyPrefix = keyPrefix; + } + + public String keyPrefix() { + return keyPrefix; + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureBlobClientSideEncryptionMethod.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStrategy.java similarity index 59% rename from nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureBlobClientSideEncryptionMethod.java rename to nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStrategy.java index f6e7419e8ba78..8fe28d16dd757 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureBlobClientSideEncryptionMethod.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/CheckpointStrategy.java @@ -14,35 +14,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.processors.azure.storage.utils; +package org.apache.nifi.processors.azure.eventhub.checkpoint; -/** - * Enumeration capturing essential information about the various client-side - * encryption methods supported by Azure - */ -public enum AzureBlobClientSideEncryptionMethod { +import org.apache.nifi.components.DescribedValue; - NONE("None", "The blobs sent to Azure are not encrypted."), - SYMMETRIC("Symmetric", "The blobs sent to Azure are encrypted using a symmetric algorithm."); +public enum CheckpointStrategy implements DescribedValue { + AZURE_BLOB_STORAGE("Azure Blob Storage", "Use Azure Blob Storage to store partition ownership and checkpoint information"), + COMPONENT_STATE("Component State", "Use component state to store partition ownership and checkpoint information"); - private final String cseName; + private final String label; private final String description; - AzureBlobClientSideEncryptionMethod(String cseName, String description) { - this.cseName = cseName; + CheckpointStrategy(String label, String description) { + this.label = label; this.description = description; } - public String getCseName() { - return cseName; + @Override + public String getValue() { + return this.name(); } - public String getDescription() { - return description; + @Override + public String getDisplayName() { + return label; } @Override - public String toString() { + public String getDescription() { return description; } } + diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStore.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStore.java new file mode 100644 index 0000000000000..26a1eb7045f6e --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStore.java @@ -0,0 +1,333 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.core.util.CoreUtils; +import com.azure.messaging.eventhubs.CheckpointStore; +import com.azure.messaging.eventhubs.models.Checkpoint; +import com.azure.messaging.eventhubs.models.PartitionContext; +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.components.state.Scope; +import org.apache.nifi.components.state.StateManager; +import org.apache.nifi.components.state.StateMap; +import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.ClusterNodeDisconnectedException; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.ConcurrentStateModificationException; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.StateNotAvailableException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.retry.Retry; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; + +import static java.util.stream.Collectors.collectingAndThen; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKey.CLUSTERED; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKeyPrefix.CHECKPOINT; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKeyPrefix.OWNERSHIP; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.checkpointToString; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.convertOwnership; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.convertPartitionContext; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointValue; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipValue; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.ownershipListToString; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.ownershipToString; + +/** + * The {@link com.azure.messaging.eventhubs.CheckpointStore} is responsible for managing the storage of partition ownership and checkpoint information for Azure Event Hubs consumers. + * The underlying storage has to be persistent and centralized (shared across the consumer clients in the consumer group). + *

    + * There exist one ownership entry and one checkpoint entry for each partition in the store. They represent {@link com.azure.messaging.eventhubs.models.PartitionOwnership} + * and {@link com.azure.messaging.eventhubs.models.Checkpoint} entities in a storage-specific serialized form. + *

    + * The checkpoint store is plugged into {@link com.azure.messaging.eventhubs.EventProcessorClient} and directly used by the load balancer algorithm running in each consumer client instance. + *

    + * {@code ComponentStateCheckpointStore} stores the partition ownership and checkpoint information in the component's (that is {@link org.apache.nifi.processors.azure.eventhub.ConsumeAzureEventHub} + * processor's) state using NiFi's {@link org.apache.nifi.components.state.StateManager} in the background. + *

    + * The format of the ownership entry in the state map: + *

        ownership/event-hub-namespace/event-hub-name/consumer-group/partition-id -> client-id/last-modified-time/etag
    + *

    + * The format of the checkpoint entry in the state map: + *

        checkpoint/event-hub-namespace/event-hub-name/consumer-group/partition-id -> offset/sequence-number
    + *

    + * The checkpoint store is required to provide optimistic locking mechanism in order to avoid concurrent updating of the same ownership entry and therefore owning the same partition + * by multiple client instances at the same time. The optimistic locking is supposed to be based on the eTag field of {@link com.azure.messaging.eventhubs.models.PartitionOwnership} + * and should be supported at entry level (only updating the same partition ownership is conflicting, claiming ownership of 2 different partitions or updating 2 checkpoints in parallel are + * valid operations as they are independent changes). + *

    + * {@link org.apache.nifi.components.state.StateManager#replace(StateMap, Map, Scope)} method supports optimistic locking but only globally, in the scope of the whole state map (which may or may not + * contain conflicting changes after update). For this reason, the state update had to be implemented in 2 phases in {@link ComponentStateCheckpointStore#claimOwnership(List)}: + *

      + *
    • in the 1st phase the algorithm gets the current state and tries to set the ownership in memory based on eTag, the claim request is skipped if eTag + * does not match (the original eTag was retrieved in {@link ComponentStateCheckpointStore#listOwnership(String, String, String)})
    • + *
    • in the 2nd phase {@link org.apache.nifi.components.state.StateManager#replace(StateMap, Map, Scope)} is called to persist the new state and if it is not successful - meaning + * that another client instance changed the state in the meantime which may or may not be conflicting -, then the whole process needs to be started over with the 1st phase
    • + *
    + */ +public class ComponentStateCheckpointStore implements CheckpointStore { + + private static final Logger LOGGER = LoggerFactory.getLogger(ComponentStateCheckpointStore.class); + + private final String clientId; + + private final StateManager stateManager; + + public ComponentStateCheckpointStore(String clientId, StateManager stateManager) { + this.clientId = clientId; + this.stateManager = stateManager; + } + + /** + * Cleans up the underlying state map and retains only items matching the "EventHub coordinates" passed in ({@code fullyQualifiedNamespace}, {@code eventHubName} and {@code consumerGroup}). + * The method should be called once in the initialization phase in order to remove the obsolete items but the checkpoint store can operate properly without doing that too. + * + * @param fullyQualifiedNamespace the fullyQualifiedNamespace of the items to be retained + * @param eventHubName the eventHubName of the items to be retained + * @param consumerGroup the consumerGroup of the items to be retained + */ + public void cleanUp(String fullyQualifiedNamespace, String eventHubName, String consumerGroup) { + cleanUpMono(fullyQualifiedNamespace, eventHubName, consumerGroup) + .subscribe(); + } + + Mono cleanUpMono(String fullyQualifiedNamespace, String eventHubName, String consumerGroup) { + return getState() + .doFirst(() -> debug("cleanUp() -> Entering [{}, {}, {}]", fullyQualifiedNamespace, eventHubName, consumerGroup)) + .flatMap(oldState -> { + Map newMap = oldState.toMap().entrySet().stream() + .filter(e -> { + String key = e.getKey(); + if (!key.startsWith(OWNERSHIP.keyPrefix()) && !key.startsWith(CHECKPOINT.keyPrefix())) { + return true; + } + PartitionContext context = convertPartitionContext(key); + return context.getFullyQualifiedNamespace().equalsIgnoreCase(fullyQualifiedNamespace) + && context.getEventHubName().equalsIgnoreCase(eventHubName) + && context.getConsumerGroup().equalsIgnoreCase(consumerGroup); + }) + .collect(toMap(Map.Entry::getKey, Map.Entry::getValue)); + + int removed = oldState.toMap().size() - newMap.size(); + if (removed > 0) { + debug("cleanUp() -> Removed {} item(s)", removed); + return updateState(oldState, newMap); + } else { + debug("cleanUp() -> Nothing to clean up"); + return Mono.empty(); + } + }) + .doOnSuccess(__ -> debug("cleanUp() -> Succeeded")) + .retryWhen(createRetrySpec("cleanUp")) + .doOnError(throwable -> debug("cleanUp() -> Failed: {}", throwable.getMessage())); + } + + @Override + public Flux listOwnership(String fullyQualifiedNamespace, String eventHubName, String consumerGroup) { + return getState() + .doFirst(() -> debug("listOwnership() -> Entering [{}, {}, {}]", fullyQualifiedNamespace, eventHubName, consumerGroup)) + .flatMapMany(state -> { + checkDisconnectedNode(state); + + return getOwnerships(state); + }) + .filter(ownership -> + ownership.getFullyQualifiedNamespace().equalsIgnoreCase(fullyQualifiedNamespace) + && ownership.getEventHubName().equalsIgnoreCase(eventHubName) + && ownership.getConsumerGroup().equalsIgnoreCase(consumerGroup) + ) + .doOnNext(partitionOwnership -> debug("listOwnership() -> Returning {}", ownershipToString(partitionOwnership))) + .doOnComplete(() -> debug("listOwnership() -> Succeeded")) + .doOnError(throwable -> debug("listOwnership() -> Failed: {}", throwable.getMessage())); + } + + @Override + public Flux claimOwnership(List requestedPartitionOwnerships) { + return getState() + .doFirst(() -> debug("claimOwnership() -> Entering [{}]", ownershipListToString(requestedPartitionOwnerships))) + .flatMapMany(oldState -> { + checkDisconnectedNode(oldState); + + Map newMap = new HashMap<>(oldState.toMap()); + + List claimedOwnerships = new ArrayList<>(); + + long timestamp = System.currentTimeMillis(); + + for (PartitionOwnership requestedPartitionOwnership : requestedPartitionOwnerships) { + String key = createOwnershipKey(requestedPartitionOwnership); + + if (oldState.get(key) != null) { + PartitionOwnership oldPartitionOwnership = convertOwnership(key, oldState.get(key)); + + String oldETag = oldPartitionOwnership.getETag(); + String reqETag = requestedPartitionOwnership.getETag(); + if (StringUtils.isNotEmpty(oldETag) && !oldETag.equals(reqETag)) { + debug("claimOwnership() -> Already claimed {}", ownershipToString(oldPartitionOwnership)); + continue; + } + } + + String newETag = CoreUtils.randomUuid().toString(); + + PartitionOwnership partitionOwnership = new PartitionOwnership() + .setFullyQualifiedNamespace(requestedPartitionOwnership.getFullyQualifiedNamespace()) + .setEventHubName(requestedPartitionOwnership.getEventHubName()) + .setConsumerGroup(requestedPartitionOwnership.getConsumerGroup()) + .setPartitionId(requestedPartitionOwnership.getPartitionId()) + .setOwnerId(requestedPartitionOwnership.getOwnerId()) + .setLastModifiedTime(timestamp) + .setETag(newETag); + + claimedOwnerships.add(partitionOwnership); + + newMap.put(key, createOwnershipValue(partitionOwnership)); + + debug("claimOwnership() -> Claiming {}", ownershipToString(partitionOwnership)); + } + + if (claimedOwnerships.isEmpty()) { + return Flux.empty(); + } + + return updateState(oldState, newMap) + .thenMany(Flux.fromIterable(claimedOwnerships)); + }) + .doOnNext(partitionOwnership -> debug("claimOwnership() -> Returning {}", ownershipToString(partitionOwnership))) + .doOnComplete(() -> debug("claimOwnership() -> Succeeded")) + .retryWhen(createRetrySpec("claimOwnership")) + .doOnError(throwable -> debug("claimOwnership() -> Failed: {}", throwable.getMessage())); + } + + @Override + public Flux listCheckpoints(String fullyQualifiedNamespace, String eventHubName, String consumerGroup) { + return getState() + .doFirst(() -> debug("listCheckpoints() -> Entering [{}, {}, {}]", fullyQualifiedNamespace, eventHubName, consumerGroup)) + .flatMapMany(state -> { + checkDisconnectedNode(state); + + return getCheckpoints(state); + }) + .filter(checkpoint -> + checkpoint.getFullyQualifiedNamespace().equalsIgnoreCase(fullyQualifiedNamespace) + && checkpoint.getEventHubName().equalsIgnoreCase(eventHubName) + && checkpoint.getConsumerGroup().equalsIgnoreCase(consumerGroup) + ) + .doOnNext(checkpoint -> debug("listCheckpoints() -> Returning {}", checkpointToString(checkpoint))) + .doOnComplete(() -> debug("listCheckpoints() -> Succeeded")) + .doOnError(throwable -> debug("listCheckpoints() -> Failed: {}", throwable.getMessage())); + } + + @Override + public Mono updateCheckpoint(Checkpoint checkpoint) { + return getState() + .doFirst(() -> debug("updateCheckpoint() -> Entering [{}]", checkpointToString(checkpoint))) + .flatMap(oldState -> { + checkDisconnectedNode(oldState); + + Map newMap = new HashMap<>(oldState.toMap()); + + newMap.put(createCheckpointKey(checkpoint), createCheckpointValue(checkpoint)); + + return updateState(oldState, newMap); + }) + .doOnSuccess(__ -> debug("updateCheckpoint() -> Succeeded")) + .retryWhen(createRetrySpec("updateCheckpoint")) + .doOnError(throwable -> debug("updateCheckpoint() -> Failed: {}", throwable.getMessage())); + } + + private Retry createRetrySpec(String methodName) { + return Retry.max(10) + .filter(t -> t instanceof ConcurrentStateModificationException) + .doBeforeRetry(retrySignal -> debug(methodName + "() -> Retry: {}", retrySignal)) + .onRetryExhaustedThrow((retrySpec, retrySignal) -> new ConcurrentStateModificationException( + String.format("Retrials of concurrent state modifications has been exhausted (%d retrials)", 10))); + } + + private Flux getOwnerships(StateMap state) { + return getEntries(state, OWNERSHIP.keyPrefix(), ComponentStateCheckpointStoreUtils::convertOwnership); + } + + private Flux getCheckpoints(StateMap state) { + return getEntries(state, CHECKPOINT.keyPrefix(), ComponentStateCheckpointStoreUtils::convertCheckpoint); + } + + private Flux getEntries(StateMap state, String kind, BiFunction converter) throws ProcessException { + return state.toMap().entrySet().stream() + .filter(e -> e.getKey().startsWith(kind)) + .map(e -> converter.apply(e.getKey(), e.getValue())) + .collect(collectingAndThen(toList(), Flux::fromIterable)); + } + + private void checkDisconnectedNode(StateMap state) { + // if _isClustered key is available in the state (that is the local cache is accessed via cluster scope) and it is true, then it is a disconnected cluster node + boolean disconnectedNode = Boolean.parseBoolean(state.get(CLUSTERED.key())); + + if (disconnectedNode) { + throw new ClusterNodeDisconnectedException("The node has been disconnected from the cluster, the checkpoint store is not accessible"); + } + } + + private void debug(String message, Object... arguments) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("[clientId={}] " + message, ArrayUtils.addFirst(arguments, clientId)); + } + } + + private Mono getState() { + return Mono.defer( + () -> { + try { + StateMap state = stateManager.getState(Scope.CLUSTER); + return Mono.just(state); + } catch (Exception e) { + return Mono.error(new StateNotAvailableException(e)); + } + } + ); + } + + private Mono updateState(StateMap oldState, Map newMap) { + return Mono.defer( + () -> { + try { + boolean success = stateManager.replace(oldState, newMap, Scope.CLUSTER); + if (success) { + return Mono.empty(); + } else { + return Mono.error(new ConcurrentStateModificationException( + String.format("Component state with version [%s] has been modified by another instance" , oldState.getStateVersion().orElse("new")))); + } + } catch (Exception e) { + return Mono.error(new StateNotAvailableException(e)); + } + } + ); + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreUtils.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreUtils.java new file mode 100644 index 0000000000000..0960ab62c6187 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreUtils.java @@ -0,0 +1,163 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.messaging.eventhubs.models.Checkpoint; +import com.azure.messaging.eventhubs.models.PartitionContext; +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.processor.exception.ProcessException; + +import java.util.List; +import java.util.stream.Collectors; + +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKeyPrefix.CHECKPOINT; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKeyPrefix.OWNERSHIP; + +final class ComponentStateCheckpointStoreUtils { + + private ComponentStateCheckpointStoreUtils() { + } + + static PartitionOwnership convertOwnership(String key, String value) { + PartitionContext context = convertPartitionContext(key); + + final String[] parts = value.split("/", 3); + if (parts.length != 3) { + throw new ProcessException(String.format("Invalid ownership value: %s", value)); + } + + return new PartitionOwnership() + .setFullyQualifiedNamespace(context.getFullyQualifiedNamespace()) + .setEventHubName(context.getEventHubName()) + .setConsumerGroup(context.getConsumerGroup()) + .setPartitionId(context.getPartitionId()) + .setOwnerId(parts[0]) + .setLastModifiedTime(Long.parseLong(parts[1])) + .setETag(parts[2]); + } + + static Checkpoint convertCheckpoint(String key, String value) { + PartitionContext context = convertPartitionContext(key); + + final String[] parts = value.split("/", 2); + if (parts.length != 2) { + throw new ProcessException(String.format("Invalid checkpoint value: %s", value)); + } + + return new Checkpoint() + .setFullyQualifiedNamespace(context.getFullyQualifiedNamespace()) + .setEventHubName(context.getEventHubName()) + .setConsumerGroup(context.getConsumerGroup()) + .setPartitionId(context.getPartitionId()) + .setOffset(StringUtils.isNotEmpty(parts[0]) ? Long.parseLong(parts[0]) : null) + .setSequenceNumber(StringUtils.isNotEmpty(parts[1]) ? Long.parseLong(parts[1]): null); + } + + static PartitionContext convertPartitionContext(String key) { + final String[] parts = key.split("/", 5); + if (parts.length != 5) { + throw new ProcessException(String.format("Invalid entry key: %s", key)); + } + + final String fullyQualifiedNamespace = parts[1]; + final String eventHubName = parts[2]; + final String consumerGroup = parts[3]; + final String partitionId = parts[4]; + + return new PartitionContext( + fullyQualifiedNamespace, + eventHubName, + consumerGroup, + partitionId + ); + } + + static String createOwnershipKey(PartitionOwnership partitionOwnership) { + return createKey( + OWNERSHIP.keyPrefix(), + partitionOwnership.getFullyQualifiedNamespace(), + partitionOwnership.getEventHubName(), + partitionOwnership.getConsumerGroup(), + partitionOwnership.getPartitionId() + ); + } + + static String createCheckpointKey(Checkpoint checkpoint) { + return createKey( + CHECKPOINT.keyPrefix(), + checkpoint.getFullyQualifiedNamespace(), + checkpoint.getEventHubName(), + checkpoint.getConsumerGroup(), + checkpoint.getPartitionId() + ); + } + + private static String createKey(String kind, String fullyQualifiedNamespace, String eventHubName, String consumerGroup, String partitionId) { + return String.format( + "%s/%s/%s/%s/%s", + kind, + fullyQualifiedNamespace, + eventHubName, + consumerGroup, + partitionId + ); + } + + static String createOwnershipValue(PartitionOwnership partitionOwnership) { + return String.format("%s/%s/%s", + partitionOwnership.getOwnerId(), + partitionOwnership.getLastModifiedTime(), + partitionOwnership.getETag()); + } + + static String createCheckpointValue(Checkpoint checkpoint) { + return String.format("%s/%s", + checkpoint.getOffset() != null ? checkpoint.getOffset().toString() : "", + checkpoint.getSequenceNumber() != null ? checkpoint.getSequenceNumber().toString() : ""); + } + + static String ownershipToString(PartitionOwnership partitionOwnership) { + return "PartitionOwnership{" + + "fullyQualifiedNamespace='" + partitionOwnership.getFullyQualifiedNamespace() + '\'' + + ", eventHubName='" + partitionOwnership.getEventHubName() + '\'' + + ", consumerGroup='" + partitionOwnership.getConsumerGroup() + '\'' + + ", partitionId='" + partitionOwnership.getPartitionId() + '\'' + + ", ownerId='" + partitionOwnership.getOwnerId() + '\'' + + ", lastModifiedTime=" + partitionOwnership.getLastModifiedTime() + + ", eTag='" + partitionOwnership.getETag() + '\'' + + '}'; + } + + static List ownershipListToString(List partitionOwnershipList) { + return partitionOwnershipList.stream() + .map(ComponentStateCheckpointStoreUtils::ownershipToString) + .collect(Collectors.toList()); + } + + static String checkpointToString(Checkpoint checkpoint) { + return "Checkpoint{" + + "fullyQualifiedNamespace='" + checkpoint.getFullyQualifiedNamespace() + '\'' + + ", eventHubName='" + checkpoint.getEventHubName() + '\'' + + ", consumerGroup='" + checkpoint.getConsumerGroup() + '\'' + + ", partitionId='" + checkpoint.getPartitionId() + '\'' + + ", offset=" + checkpoint.getOffset() + + ", sequenceNumber=" + checkpoint.getSequenceNumber() + + '}'; + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ClusterNodeDisconnectedException.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ClusterNodeDisconnectedException.java new file mode 100644 index 0000000000000..374b2d2c477f3 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ClusterNodeDisconnectedException.java @@ -0,0 +1,24 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint.exception; + +public class ClusterNodeDisconnectedException extends ComponentStateCheckpointStoreException { + + public ClusterNodeDisconnectedException(String message) { + super(message); + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ComponentStateCheckpointStoreException.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ComponentStateCheckpointStoreException.java new file mode 100644 index 0000000000000..56c5ce1379c8d --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ComponentStateCheckpointStoreException.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint.exception; + +public class ComponentStateCheckpointStoreException extends RuntimeException { + + public ComponentStateCheckpointStoreException(String message) { + super(message); + } + + public ComponentStateCheckpointStoreException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ConcurrentStateModificationException.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ConcurrentStateModificationException.java new file mode 100644 index 0000000000000..efdc9aff35564 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/ConcurrentStateModificationException.java @@ -0,0 +1,24 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint.exception; + +public class ConcurrentStateModificationException extends ComponentStateCheckpointStoreException { + + public ConcurrentStateModificationException(String message) { + super(message); + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/StateNotAvailableException.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/StateNotAvailableException.java new file mode 100644 index 0000000000000..434ba6ed1c6f4 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/checkpoint/exception/StateNotAvailableException.java @@ -0,0 +1,24 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint.exception; + +public class StateNotAvailableException extends ComponentStateCheckpointStoreException { + + public StateNotAvailableException(Throwable cause) { + super("Failure when reading/writing the component state", cause); + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/utils/AzureEventHubUtils.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/utils/AzureEventHubUtils.java index 795f797269a17..fa445ca6d1026 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/utils/AzureEventHubUtils.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/eventhub/utils/AzureEventHubUtils.java @@ -57,7 +57,7 @@ public final class AzureEventHubUtils { .name("use-managed-identity") .displayName("Use Azure Managed Identity") .description("Choose whether or not to use the managed identity of Azure VM/VMSS") - .required(false).defaultValue("false").allowableValues("true", "false") + .required(true).defaultValue("false").allowableValues("true", "false") .addValidator(StandardValidators.BOOLEAN_VALIDATOR).build(); public static final PropertyDescriptor SERVICE_BUS_ENDPOINT = new PropertyDescriptor.Builder() @@ -67,14 +67,14 @@ public final class AzureEventHubUtils { .expressionLanguageSupported(ExpressionLanguageScope.NONE) .allowableValues(AzureEventHubUtils.AZURE_ENDPOINT, AzureEventHubUtils.AZURE_CHINA_ENDPOINT, AzureEventHubUtils.AZURE_GERMANY_ENDPOINT, AzureEventHubUtils.AZURE_US_GOV_ENDPOINT) - .defaultValue(AzureEventHubUtils.AZURE_ENDPOINT.getValue()) + .defaultValue(AzureEventHubUtils.AZURE_ENDPOINT) .required(true) .build(); public static List customValidate(PropertyDescriptor accessPolicyDescriptor, PropertyDescriptor policyKeyDescriptor, ValidationContext context) { - List retVal = new ArrayList<>(); + List validationResults = new ArrayList<>(); boolean accessPolicyIsSet = context.getProperty(accessPolicyDescriptor).isSet(); boolean policyKeyIsSet = context.getProperty(policyKeyDescriptor).isSet(); @@ -87,7 +87,7 @@ public static List customValidate(PropertyDescriptor accessPol accessPolicyDescriptor.getDisplayName(), POLICY_PRIMARY_KEY.getDisplayName() ); - retVal.add(new ValidationResult.Builder().subject("Credentials config").valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().subject("Credentials config").valid(false).explanation(msg).build()); } else if (!useManagedIdentity && (!accessPolicyIsSet || !policyKeyIsSet)) { final String msg = String.format( "either('%s') or (%s with '%s') must be set", @@ -95,10 +95,10 @@ public static List customValidate(PropertyDescriptor accessPol accessPolicyDescriptor.getDisplayName(), POLICY_PRIMARY_KEY.getDisplayName() ); - retVal.add(new ValidationResult.Builder().subject("Credentials config").valid(false).explanation(msg).build()); + validationResults.add(new ValidationResult.Builder().subject("Credentials config").valid(false).explanation(msg).build()); } - ProxyConfiguration.validateProxySpec(context, retVal, AzureEventHubComponent.PROXY_SPECS); - return retVal; + ProxyConfiguration.validateProxySpec(context, validationResults, AzureEventHubComponent.PROXY_SPECS); + return validationResults; } public static Map getApplicationProperties(final Map eventProperties) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/CopyAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/CopyAzureBlobStorage_v12.java index 89b26773f4969..a1c7b0701005e 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/CopyAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/CopyAzureBlobStorage_v12.java @@ -200,7 +200,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session ).orElse(sourceBlobName); final boolean createContainer = context.getProperty(AzureStorageUtils.CREATE_CONTAINER).asBoolean(); - final AzureStorageConflictResolutionStrategy conflictResolution = AzureStorageConflictResolutionStrategy.valueOf(context.getProperty(AzureStorageUtils.CONFLICT_RESOLUTION).getValue()); + final AzureStorageConflictResolutionStrategy conflictResolution = context.getProperty(AzureStorageUtils.CONFLICT_RESOLUTION).asAllowableValue(AzureStorageConflictResolutionStrategy.class); final long startNanos = System.nanoTime(); try { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureBlobStorage_v12.java index f5a927bddf0ef..f241ffd05aedc 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureBlobStorage_v12.java @@ -35,8 +35,6 @@ import org.apache.nifi.processors.azure.AbstractAzureBlobProcessor_v12; import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -51,9 +49,7 @@ public class DeleteAzureBlobStorage_v12 extends AbstractAzureBlobProcessor_v12 { public static final AllowableValue DELETE_SNAPSHOTS_NONE = new AllowableValue("NONE", "None", "Delete the blob only."); - public static final AllowableValue DELETE_SNAPSHOTS_ALSO = new AllowableValue(DeleteSnapshotsOptionType.INCLUDE.name(), "Include Snapshots", "Delete the blob and its snapshots."); - public static final AllowableValue DELETE_SNAPSHOTS_ONLY = new AllowableValue(DeleteSnapshotsOptionType.ONLY.name(), "Delete Snapshots Only", "Delete only the blob's snapshots."); public static final PropertyDescriptor CONTAINER = new PropertyDescriptor.Builder() @@ -72,17 +68,17 @@ public class DeleteAzureBlobStorage_v12 extends AbstractAzureBlobProcessor_v12 { .description("Specifies the snapshot deletion options to be used when deleting a blob.") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .allowableValues(DELETE_SNAPSHOTS_NONE, DELETE_SNAPSHOTS_ALSO, DELETE_SNAPSHOTS_ONLY) - .defaultValue(DELETE_SNAPSHOTS_NONE.getValue()) + .defaultValue(DELETE_SNAPSHOTS_NONE) .required(true) .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( STORAGE_CREDENTIALS_SERVICE, CONTAINER, BLOB_NAME, DELETE_SNAPSHOTS_OPTION, AzureStorageUtils.PROXY_CONFIGURATION_SERVICE - )); + ); @Override protected List getSupportedPropertyDescriptors() { @@ -135,16 +131,10 @@ private DeleteSnapshotsOptionType getDeleteSnapshotsOptionType(String deleteSnap } private String getProvenanceMessage(DeleteSnapshotsOptionType deleteSnapshotsOptionType) { - if (deleteSnapshotsOptionType == null) { - return "Blob deleted"; - } - switch (deleteSnapshotsOptionType) { - case INCLUDE: - return "Blob deleted along with its snapshots"; - case ONLY: - return "Blob's snapshots deleted"; - default: - throw new IllegalArgumentException("Unhandled DeleteSnapshotsOptionType: " + deleteSnapshotsOptionType); - } + return switch (deleteSnapshotsOptionType) { + case null -> "Blob deleted"; + case INCLUDE -> "Blob deleted along with its snapshots"; + case ONLY -> "Blob's snapshots deleted"; + }; } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureDataLakeStorage.java index cf1ef18f77fa8..11d09514d6477 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/DeleteAzureDataLakeStorage.java @@ -39,8 +39,6 @@ import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; import java.time.Duration; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import static org.apache.nifi.processors.azure.storage.utils.ADLSAttributes.ATTR_NAME_FILENAME; @@ -59,8 +57,8 @@ public class DeleteAzureDataLakeStorage extends AbstractAzureDataLakeStorageProc .displayName("Filesystem Object Type") .description("They type of the file system object to be deleted. It can be either folder or file.") .allowableValues(FS_TYPE_FILE, FS_TYPE_DIRECTORY) + .defaultValue(FS_TYPE_FILE) .required(true) - .defaultValue(FS_TYPE_FILE.toString()) .build(); public static final PropertyDescriptor FILE = new PropertyDescriptor.Builder() @@ -73,14 +71,14 @@ public class DeleteAzureDataLakeStorage extends AbstractAzureDataLakeStorageProc .dependsOn(FILESYSTEM_OBJECT_TYPE, FS_TYPE_FILE) .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ADLS_CREDENTIALS_SERVICE, FILESYSTEM, FILESYSTEM_OBJECT_TYPE, DIRECTORY, FILE, AzureStorageUtils.PROXY_CONFIGURATION_SERVICE - )); + ); @Override public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureBlobStorage_v12.java index 18ca4a6d0f2fb..45100a65c3030 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureBlobStorage_v12.java @@ -20,13 +20,6 @@ import com.azure.storage.blob.BlobContainerClient; import com.azure.storage.blob.BlobServiceClient; import com.azure.storage.blob.models.BlobRange; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; import org.apache.nifi.annotation.behavior.InputRequirement; import org.apache.nifi.annotation.behavior.InputRequirement.Requirement; import org.apache.nifi.annotation.behavior.WritesAttribute; @@ -49,6 +42,13 @@ import org.apache.nifi.processors.azure.AbstractAzureBlobProcessor_v12; import org.apache.nifi.processors.azure.ClientSideEncryptionSupport; import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import static org.apache.nifi.processors.azure.storage.utils.BlobAttributes.ATTR_DESCRIPTION_BLOBNAME; import static org.apache.nifi.processors.azure.storage.utils.BlobAttributes.ATTR_DESCRIPTION_BLOBTYPE; import static org.apache.nifi.processors.azure.storage.utils.BlobAttributes.ATTR_DESCRIPTION_CONTAINER; @@ -139,7 +139,7 @@ public class FetchAzureBlobStorage_v12 extends AbstractAzureBlobProcessor_v12 im .required(false) .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( STORAGE_CREDENTIALS_SERVICE, CONTAINER, BLOB_NAME, @@ -149,7 +149,7 @@ public class FetchAzureBlobStorage_v12 extends AbstractAzureBlobProcessor_v12 im CSE_KEY_TYPE, CSE_KEY_ID, CSE_LOCAL_KEY - )); + ); @Override protected Collection customValidate(ValidationContext validationContext) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureDataLakeStorage.java index d977120d33e6d..2018a90dc00c4 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/FetchAzureDataLakeStorage.java @@ -24,10 +24,6 @@ import com.azure.storage.file.datalake.models.DataLakeStorageException; import com.azure.storage.file.datalake.models.DownloadRetryOptions; import com.azure.storage.file.datalake.models.FileRange; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; import org.apache.nifi.annotation.behavior.InputRequirement; import org.apache.nifi.annotation.behavior.InputRequirement.Requirement; import org.apache.nifi.annotation.behavior.WritesAttribute; @@ -48,6 +44,9 @@ import org.apache.nifi.processors.azure.AbstractAzureDataLakeStorageProcessor; import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; +import java.util.List; +import java.util.concurrent.TimeUnit; + @Tags({"azure", "microsoft", "cloud", "storage", "adlsgen2", "datalake"}) @SeeAlso({PutAzureDataLakeStorage.class, DeleteAzureDataLakeStorage.class, ListAzureDataLakeStorage.class}) @CapabilityDescription("Fetch the specified file from Azure Data Lake Storage") @@ -118,7 +117,7 @@ public class FetchAzureDataLakeStorage extends AbstractAzureDataLakeStorageProce .defaultValue("0") .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ADLS_CREDENTIALS_SERVICE, FILESYSTEM, DIRECTORY, @@ -127,7 +126,7 @@ public class FetchAzureDataLakeStorage extends AbstractAzureDataLakeStorageProce RANGE_LENGTH, NUM_RETRIES, AzureStorageUtils.PROXY_CONFIGURATION_SERVICE - )); + ); @Override public List getSupportedPropertyDescriptors() { @@ -162,7 +161,6 @@ public void onTrigger(ProcessContext context, ProcessSession session) throws Pro throw new ProcessException(FILE.getDisplayName() + " (" + fileName + ") points to a directory. Full path: " + fileClient.getFilePath()); } - flowFile = session.write(flowFile, os -> fileClient.readWithResponse(os, fileRange, retryOptions, null, false, null, Context.NONE)); session.getProvenanceReporter().modifyContent(flowFile); session.transfer(flowFile, REL_SUCCESS); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureBlobStorage_v12.java index 4606504425325..20aa86c0ac516 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureBlobStorage_v12.java @@ -54,10 +54,8 @@ import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -136,7 +134,7 @@ public class ListAzureBlobStorage_v12 extends AbstractListAzureProcessor PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( STORAGE_CREDENTIALS_SERVICE, CONTAINER, BLOB_NAME_PREFIX, @@ -150,7 +148,7 @@ public class ListAzureBlobStorage_v12 extends AbstractListAzureProcessor performListing(final ProcessContext context, final Long final ListBlobsOptions options = new ListBlobsOptions() .setPrefix(prefix); - final Iterator result = containerClient.listBlobs(options, null).iterator(); - - while (result.hasNext()) { - final BlobItem blob = result.next(); + for (BlobItem blob : containerClient.listBlobs(options, null)) { final BlobItemProperties properties = blob.getProperties(); if (isFileInfoMatchesWithAgeAndSize(context, minimumTimestamp, properties.getLastModified().toInstant().toEpochMilli(), properties.getContentLength())) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureDataLakeStorage.java index bd9388e40f30e..425b86b4e9086 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/ListAzureDataLakeStorage.java @@ -51,16 +51,13 @@ import org.apache.nifi.services.azure.storage.ADLSCredentialsService; import java.io.IOException; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static org.apache.nifi.processor.util.list.ListedEntityTracker.INITIAL_LISTING_TARGET; import static org.apache.nifi.processor.util.list.ListedEntityTracker.TRACKING_STATE_CACHE; @@ -144,7 +141,7 @@ public class ListAzureDataLakeStorage extends AbstractListAzureProcessor PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ADLS_CREDENTIALS_SERVICE, FILESYSTEM, DIRECTORY, @@ -161,16 +158,18 @@ public class ListAzureDataLakeStorage extends AbstractListAzureProcessor LISTING_RESET_PROPERTIES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + private static final Set LISTING_RESET_PROPERTIES = Set.of( ADLS_CREDENTIALS_SERVICE, FILESYSTEM, DIRECTORY, RECURSE_SUBDIRECTORIES, FILE_FILTER, PATH_FILTER, - LISTING_STRATEGY))); + LISTING_STRATEGY + ); private volatile Pattern filePattern; private volatile Pattern pathPattern; @@ -288,7 +287,7 @@ private List performListing(final ProcessContext context, final Lo final boolean includeTempFiles = context.getProperty(INCLUDE_TEMPORARY_FILES).asBoolean(); final long minimumTimestamp = minTimestamp == null ? 0 : minTimestamp; - final List listing = fileSystemClient.listPaths(options, null).stream() + return fileSystemClient.listPaths(options, null).stream() .filter(pathItem -> !pathItem.isDirectory()) .filter(pathItem -> includeTempFiles || !pathItem.getName().contains(TEMP_FILE_DIRECTORY)) .filter(pathItem -> isFileInfoMatchesWithAgeAndSize(context, minimumTimestamp, pathItem.getLastModified().toInstant().toEpochMilli(), pathItem.getContentLength())) @@ -299,11 +298,10 @@ private List performListing(final ProcessContext context, final Lo .lastModified(pathItem.getLastModified().toInstant().toEpochMilli()) .etag(pathItem.getETag()) .build()) - .filter(fileInfo -> applyFilters && (filePattern == null || filePattern.matcher(fileInfo.getFilename()).matches())) - .filter(fileInfo -> applyFilters && (pathPattern == null || pathPattern.matcher(RegExUtils.removeFirst(fileInfo.getDirectory(), baseDirectoryPattern)).matches())) - .collect(Collectors.toList()); - - return listing; + .filter(fileInfo -> applyFilters) + .filter(fileInfo -> filePattern == null || filePattern.matcher(fileInfo.getFilename()).matches()) + .filter(fileInfo -> pathPattern == null || pathPattern.matcher(RegExUtils.removeFirst(fileInfo.getDirectory(), baseDirectoryPattern)).matches()) + .toList(); } catch (final Exception e) { getLogger().error("Failed to list directory on Azure Data Lake Storage", e); throw new IOException(ExceptionUtils.getRootCause(e)); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/MoveAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/MoveAzureDataLakeStorage.java index c5b38becf614e..4d4a11f9bcc78 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/MoveAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/MoveAzureDataLakeStorage.java @@ -38,8 +38,6 @@ import org.apache.nifi.processors.azure.AbstractAzureDataLakeStorageProcessor; import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -78,7 +76,6 @@ public class MoveAzureDataLakeStorage extends AbstractAzureDataLakeStorageProces public static final String REPLACE_RESOLUTION = "replace"; public static final String IGNORE_RESOLUTION = "ignore"; - public static final PropertyDescriptor CONFLICT_RESOLUTION = new PropertyDescriptor.Builder() .name("conflict-resolution-strategy") .displayName("Conflict Resolution Strategy") @@ -125,7 +122,7 @@ public class MoveAzureDataLakeStorage extends AbstractAzureDataLakeStorageProces .addValidator(new DirectoryValidator("Destination Directory")) .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ADLS_CREDENTIALS_SERVICE, SOURCE_FILESYSTEM, SOURCE_DIRECTORY, @@ -134,7 +131,7 @@ public class MoveAzureDataLakeStorage extends AbstractAzureDataLakeStorageProces FILE, CONFLICT_RESOLUTION, AzureStorageUtils.PROXY_CONFIGURATION_SERVICE - )); + ); @Override protected List getSupportedPropertyDescriptors() { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureBlobStorage_v12.java index 7b043299bf585..3d2a36e67d3c1 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureBlobStorage_v12.java @@ -50,9 +50,7 @@ import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -83,8 +81,8 @@ import static org.apache.nifi.processors.azure.storage.utils.BlobAttributes.ATTR_NAME_MIME_TYPE; import static org.apache.nifi.processors.azure.storage.utils.BlobAttributes.ATTR_NAME_PRIMARY_URI; import static org.apache.nifi.processors.azure.storage.utils.BlobAttributes.ATTR_NAME_TIMESTAMP; -import static org.apache.nifi.processors.transfer.ResourceTransferProperties.RESOURCE_TRANSFER_SOURCE; import static org.apache.nifi.processors.transfer.ResourceTransferProperties.FILE_RESOURCE_SERVICE; +import static org.apache.nifi.processors.transfer.ResourceTransferProperties.RESOURCE_TRANSFER_SOURCE; import static org.apache.nifi.processors.transfer.ResourceTransferUtils.getFileResource; @Tags({"azure", "microsoft", "cloud", "storage", "blob"}) @@ -104,7 +102,8 @@ @WritesAttribute(attribute = ATTR_NAME_ERROR_CODE, description = ATTR_DESCRIPTION_ERROR_CODE), @WritesAttribute(attribute = ATTR_NAME_IGNORED, description = ATTR_DESCRIPTION_IGNORED)}) public class PutAzureBlobStorage_v12 extends AbstractAzureBlobProcessor_v12 implements ClientSideEncryptionSupport { - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + + private static final List PROPERTIES = List.of( STORAGE_CREDENTIALS_SERVICE, AzureStorageUtils.CONTAINER, AzureStorageUtils.CREATE_CONTAINER, @@ -116,7 +115,7 @@ public class PutAzureBlobStorage_v12 extends AbstractAzureBlobProcessor_v12 impl CSE_KEY_TYPE, CSE_KEY_ID, CSE_LOCAL_KEY - )); + ); @Override protected Collection customValidate(ValidationContext validationContext) { @@ -139,7 +138,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session final String containerName = context.getProperty(AzureStorageUtils.CONTAINER).evaluateAttributeExpressions(flowFile).getValue(); final boolean createContainer = context.getProperty(AzureStorageUtils.CREATE_CONTAINER).asBoolean(); final String blobName = context.getProperty(BLOB_NAME).evaluateAttributeExpressions(flowFile).getValue(); - final AzureStorageConflictResolutionStrategy conflictResolution = AzureStorageConflictResolutionStrategy.valueOf(context.getProperty(AzureStorageUtils.CONFLICT_RESOLUTION).getValue()); + final AzureStorageConflictResolutionStrategy conflictResolution = context.getProperty(AzureStorageUtils.CONFLICT_RESOLUTION).asAllowableValue(AzureStorageConflictResolutionStrategy.class); final ResourceTransferSource resourceTransferSource = ResourceTransferSource.valueOf(context.getProperty(RESOURCE_TRANSFER_SOURCE).getValue()); long startNanos = System.nanoTime(); @@ -217,5 +216,4 @@ private static void applyUploadResultAttributes(final Map attrib attributes.put(ATTR_NAME_LANG, null); attributes.put(ATTR_NAME_MIME_TYPE, APPLICATION_OCTET_STREAM); } - } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureDataLakeStorage.java index cfd660c289116..817435ed2f5b7 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/PutAzureDataLakeStorage.java @@ -44,8 +44,6 @@ import java.io.BufferedInputStream; import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -63,8 +61,8 @@ import static org.apache.nifi.processors.azure.storage.utils.ADLSAttributes.ATTR_NAME_FILESYSTEM; import static org.apache.nifi.processors.azure.storage.utils.ADLSAttributes.ATTR_NAME_LENGTH; import static org.apache.nifi.processors.azure.storage.utils.ADLSAttributes.ATTR_NAME_PRIMARY_URI; -import static org.apache.nifi.processors.transfer.ResourceTransferProperties.RESOURCE_TRANSFER_SOURCE; import static org.apache.nifi.processors.transfer.ResourceTransferProperties.FILE_RESOURCE_SERVICE; +import static org.apache.nifi.processors.transfer.ResourceTransferProperties.RESOURCE_TRANSFER_SOURCE; import static org.apache.nifi.processors.transfer.ResourceTransferUtils.getFileResource; @Tags({"azure", "microsoft", "cloud", "storage", "adlsgen2", "datalake"}) @@ -104,7 +102,7 @@ public class PutAzureDataLakeStorage extends AbstractAzureDataLakeStorageProcess .addValidator(new DirectoryValidator("Base Temporary Path")) .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ADLS_CREDENTIALS_SERVICE, FILESYSTEM, DIRECTORY, @@ -114,7 +112,7 @@ public class PutAzureDataLakeStorage extends AbstractAzureDataLakeStorageProcess RESOURCE_TRANSFER_SOURCE, FILE_RESOURCE_SERVICE, AzureStorageUtils.PROXY_CONFIGURATION_SERVICE - )); + ); @Override protected List getSupportedPropertyDescriptors() { @@ -226,7 +224,7 @@ static void uploadContent(DataLakeFileClient fileClient, InputStream in, long le * This method serves as a "commit" for the upload process. Upon upload, a 0-byte file is created, then the payload is appended to it. * Because of that, a work-in-progress file is available for readers before the upload is complete. It is not an efficient approach in * case of conflicts because FlowFiles are uploaded unnecessarily, but it is a calculated risk because consistency is more important. - * + *

    * Visible for testing * * @param sourceFileClient client of the temporary file diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/AbstractAzureQueueStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/AbstractAzureQueueStorage_v12.java index ce1ad8f537c9f..0663490449a71 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/AbstractAzureQueueStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/AbstractAzureQueueStorage_v12.java @@ -43,10 +43,8 @@ import reactor.core.publisher.Mono; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -64,12 +62,7 @@ public abstract class AbstractAzureQueueStorage_v12 extends AbstractProcessor { public static final PropertyDescriptor ENDPOINT_SUFFIX = new PropertyDescriptor.Builder() .fromPropertyDescriptor(AzureStorageUtils.ENDPOINT_SUFFIX) - .displayName("Endpoint Suffix") - .description("Storage accounts in public Azure always use a common FQDN suffix. " + - "Override this endpoint suffix with a different suffix in certain circumstances (like Azure Stack or non-public Azure regions).") - .required(true) .defaultValue(AzureServiceEndpoints.DEFAULT_QUEUE_ENDPOINT_SUFFIX) - .expressionLanguageSupported(ExpressionLanguageScope.NONE) .build(); public static final PropertyDescriptor STORAGE_CREDENTIALS_SERVICE = new PropertyDescriptor.Builder() @@ -100,7 +93,7 @@ public abstract class AbstractAzureQueueStorage_v12 extends AbstractProcessor { .description("Unsuccessful operations will be transferred to the failure relationship.") .build(); - private static final Set RELATIONSHIPS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(REL_SUCCESS, REL_FAILURE))); + private static final Set RELATIONSHIPS = Set.of(REL_SUCCESS, REL_FAILURE); static final String URI_ATTRIBUTE = "azure.queue.uri"; static final String INSERTION_TIME_ATTRIBUTE = "azure.queue.insertionTime"; diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/GetAzureQueueStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/GetAzureQueueStorage_v12.java index c8ebf0f43b77c..d602a6a51e70c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/GetAzureQueueStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/GetAzureQueueStorage_v12.java @@ -40,9 +40,7 @@ import org.apache.nifi.proxy.ProxySpec; import java.time.Duration; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -98,20 +96,17 @@ public class GetAzureQueueStorage_v12 extends AbstractAzureQueueStorage_v12 { .build(); private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP, ProxySpec.SOCKS}; - private static final List PROPERTIES = Collections.unmodifiableList( - Arrays.asList( - QUEUE_NAME, - ENDPOINT_SUFFIX, - STORAGE_CREDENTIALS_SERVICE, - AUTO_DELETE, - MESSAGE_BATCH_SIZE, - VISIBILITY_TIMEOUT, - REQUEST_TIMEOUT, - ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS) - ) + private static final List PROPERTIES = List.of( + QUEUE_NAME, + ENDPOINT_SUFFIX, + STORAGE_CREDENTIALS_SERVICE, + AUTO_DELETE, + MESSAGE_BATCH_SIZE, + VISIBILITY_TIMEOUT, + REQUEST_TIMEOUT, + ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS) ); - - private static final Set RELATIONSHIPS = Collections.singleton(REL_SUCCESS); + private static final Set RELATIONSHIPS = Set.of(REL_SUCCESS); // 7 days is the maximum timeout as per https://learn.microsoft.com/en-us/rest/api/storageservices/get-messages private static final Duration MAX_VISIBILITY_TIMEOUT = Duration.ofDays(7); @@ -194,7 +189,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session flowFile = session.write(flowFile, out -> out.write(message.getBody().toString().getBytes())); session.transfer(flowFile, REL_SUCCESS); - session.getProvenanceReporter().receive(flowFile, queueClient.getQueueUrl().toString()); + session.getProvenanceReporter().receive(flowFile, queueClient.getQueueUrl()); } if (autoDelete) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/PutAzureQueueStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/PutAzureQueueStorage_v12.java index e6389504c51a9..88344ce73c8f1 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/PutAzureQueueStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/queue/PutAzureQueueStorage_v12.java @@ -36,9 +36,7 @@ import java.io.ByteArrayOutputStream; import java.time.Duration; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -67,16 +65,14 @@ public class PutAzureQueueStorage_v12 extends AbstractAzureQueueStorage_v12 { .build(); private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP, ProxySpec.SOCKS}; - private static final List PROPERTIES = Collections.unmodifiableList( - Arrays.asList( - QUEUE_NAME, - ENDPOINT_SUFFIX, - STORAGE_CREDENTIALS_SERVICE, - MESSAGE_TIME_TO_LIVE, - VISIBILITY_TIMEOUT, - REQUEST_TIMEOUT, - ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS) - ) + private static final List PROPERTIES = List.of( + QUEUE_NAME, + ENDPOINT_SUFFIX, + STORAGE_CREDENTIALS_SERVICE, + MESSAGE_TIME_TO_LIVE, + VISIBILITY_TIMEOUT, + REQUEST_TIMEOUT, + ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS) ); // 7 days is the maximum timeout as per https://learn.microsoft.com/en-us/rest/api/storageservices/get-messages diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/ADLSFileInfo.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/ADLSFileInfo.java index 77123814e90c0..c729fbe20ba20 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/ADLSFileInfo.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/ADLSFileInfo.java @@ -26,7 +26,6 @@ import org.apache.nifi.serialization.record.RecordSchema; import java.io.Serializable; -import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -35,7 +34,6 @@ public class ADLSFileInfo implements Comparable, Serializable, ListableEntity { - private static final RecordSchema SCHEMA; private static final String FILESYSTEM = "filesystem"; private static final String FILE_PATH = "filePath"; private static final String DIRECTORY = "directory"; @@ -44,17 +42,15 @@ public class ADLSFileInfo implements Comparable, Serializable, Lis private static final String LAST_MODIFIED = "lastModified"; private static final String ETAG = "etag"; - static { - List recordFields = new ArrayList<>(); - recordFields.add(new RecordField(FILESYSTEM, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(FILE_PATH, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(DIRECTORY, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(FILENAME, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(LENGTH, RecordFieldType.LONG.getDataType(), false)); - recordFields.add(new RecordField(LAST_MODIFIED, RecordFieldType.TIMESTAMP.getDataType(), false)); - recordFields.add(new RecordField(ETAG, RecordFieldType.STRING.getDataType())); - SCHEMA = new SimpleRecordSchema(recordFields); - } + private static final RecordSchema SCHEMA = new SimpleRecordSchema(List.of( + new RecordField(FILESYSTEM, RecordFieldType.STRING.getDataType(), false), + new RecordField(FILE_PATH, RecordFieldType.STRING.getDataType(), false), + new RecordField(DIRECTORY, RecordFieldType.STRING.getDataType(), false), + new RecordField(FILENAME, RecordFieldType.STRING.getDataType(), false), + new RecordField(LENGTH, RecordFieldType.LONG.getDataType(), false), + new RecordField(LAST_MODIFIED, RecordFieldType.TIMESTAMP.getDataType(), false), + new RecordField(ETAG, RecordFieldType.STRING.getDataType()) + )); private static final Comparator COMPARATOR = Comparator.comparing(ADLSFileInfo::getFileSystem).thenComparing(ADLSFileInfo::getFilePath); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java index 0c6cca192a319..ed79f4436d298 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/AzureStorageUtils.java @@ -17,10 +17,6 @@ package org.apache.nifi.processors.azure.storage.utils; import com.azure.core.http.ProxyOptions; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.util.Collection; - import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.ValidationContext; import org.apache.nifi.components.ValidationResult; @@ -31,73 +27,82 @@ import org.apache.nifi.proxy.ProxySpec; import org.apache.nifi.proxy.SocksVersion; import org.apache.nifi.services.azure.storage.AzureStorageConflictResolutionStrategy; +import org.apache.nifi.services.azure.storage.AzureStorageCredentialsType; import reactor.netty.http.client.HttpClient; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.util.Collection; +import java.util.EnumSet; + public final class AzureStorageUtils { public static final String STORAGE_ACCOUNT_NAME_PROPERTY_DESCRIPTOR_NAME = "storage-account-name"; public static final String STORAGE_ACCOUNT_KEY_PROPERTY_DESCRIPTOR_NAME = "storage-account-key"; public static final String STORAGE_SAS_TOKEN_PROPERTY_DESCRIPTOR_NAME = "storage-sas-token"; public static final String STORAGE_ENDPOINT_SUFFIX_PROPERTY_DESCRIPTOR_NAME = "storage-endpoint-suffix"; + public static final PropertyDescriptor CREDENTIALS_TYPE = new PropertyDescriptor.Builder() + .name("credentials-type") + .displayName("Credentials Type") + .description("Credentials type to be used for authenticating to Azure") + .required(true) + .allowableValues(EnumSet.of( + AzureStorageCredentialsType.ACCOUNT_KEY, + AzureStorageCredentialsType.SAS_TOKEN, + AzureStorageCredentialsType.MANAGED_IDENTITY, + AzureStorageCredentialsType.SERVICE_PRINCIPAL)) + .defaultValue(AzureStorageCredentialsType.SAS_TOKEN) + .build(); + public static final String ACCOUNT_KEY_BASE_DESCRIPTION = "The storage account key. This is an admin-like password providing access to every container in this account. It is recommended " + - "one uses Shared Access Signature (SAS) token instead for fine-grained control with policies."; + "one uses Shared Access Signature (SAS) token, Managed Identity or Service Principal instead for fine-grained control with policies."; public static final String ACCOUNT_KEY_SECURITY_DESCRIPTION = - " There are certain risks in allowing the account key to be stored as a flowfile " + + " There are certain risks in allowing the account key to be stored as a FlowFile " + "attribute. While it does provide for a more flexible flow by allowing the account key to " + - "be fetched dynamically from a flowfile attribute, care must be taken to restrict access to " + + "be fetched dynamically from a FlowFile attribute, care must be taken to restrict access to " + "the event provenance data (e.g., by strictly controlling the policies governing provenance for this processor). " + "In addition, the provenance repositories may be put on encrypted disk partitions."; public static final PropertyDescriptor ACCOUNT_KEY = new PropertyDescriptor.Builder() .name(STORAGE_ACCOUNT_KEY_PROPERTY_DESCRIPTOR_NAME) - .displayName("Storage Account Key") - .description(ACCOUNT_KEY_BASE_DESCRIPTION + ACCOUNT_KEY_SECURITY_DESCRIPTION) + .displayName("Account Key") + .description(ACCOUNT_KEY_BASE_DESCRIPTION) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .required(false) + .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .required(true) .sensitive(true) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY) .build(); public static final String ACCOUNT_NAME_BASE_DESCRIPTION = "The storage account name."; public static final String ACCOUNT_NAME_SECURITY_DESCRIPTION = - " There are certain risks in allowing the account name to be stored as a flowfile " + + " There are certain risks in allowing the account name to be stored as a FlowFile " + "attribute. While it does provide for a more flexible flow by allowing the account name to " + - "be fetched dynamically from a flowfile attribute, care must be taken to restrict access to " + + "be fetched dynamically from a FlowFile attribute, care must be taken to restrict access to " + "the event provenance data (e.g., by strictly controlling the policies governing provenance for this processor). " + "In addition, the provenance repositories may be put on encrypted disk partitions."; - public static final String ACCOUNT_NAME_CREDENTIAL_SERVICE_DESCRIPTION = - " Instead of defining the Storage Account Name, Storage Account Key and SAS Token properties directly on the processor, " + - "the preferred way is to configure them through a controller service specified in the Storage Credentials property. " + - "The controller service can provide a common/shared configuration for multiple/all Azure processors. Furthermore, the credentials " + - "can also be looked up dynamically with the 'Lookup' version of the service."; - public static final PropertyDescriptor ACCOUNT_NAME = new PropertyDescriptor.Builder() .name(STORAGE_ACCOUNT_NAME_PROPERTY_DESCRIPTOR_NAME) .displayName("Storage Account Name") - .description(ACCOUNT_NAME_BASE_DESCRIPTION + ACCOUNT_NAME_SECURITY_DESCRIPTION + ACCOUNT_NAME_CREDENTIAL_SERVICE_DESCRIPTION) + .description(ACCOUNT_NAME_BASE_DESCRIPTION) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .required(false) + .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .required(true) .sensitive(true) .build(); public static final PropertyDescriptor ENDPOINT_SUFFIX = new PropertyDescriptor.Builder() .name(STORAGE_ENDPOINT_SUFFIX_PROPERTY_DESCRIPTOR_NAME) - .displayName("Common Storage Account Endpoint Suffix") - .description( - "Storage accounts in public Azure always use a common FQDN suffix. " + - "Override this endpoint suffix with a different suffix in certain circumstances (like Azure Stack or non-public Azure regions). " + - "The preferred way is to configure them through a controller service specified in the Storage Credentials property. " + - "The controller service can provide a common/shared configuration for multiple/all Azure processors. Furthermore, the credentials " + - "can also be looked up dynamically with the 'Lookup' version of the service.") + .displayName("Endpoint Suffix") + .description("Storage accounts in public Azure always use a common FQDN suffix. " + + "Override this endpoint suffix with a different suffix in certain circumstances (like Azure Stack or non-public Azure regions).") .addValidator(StandardValidators.NON_BLANK_VALIDATOR) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) - .required(false) - .sensitive(false) + .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .required(true) .build(); public static final PropertyDescriptor CONTAINER = new PropertyDescriptor.Builder() @@ -128,27 +133,28 @@ public final class AzureStorageUtils { .expressionLanguageSupported(ExpressionLanguageScope.NONE) .required(true) .allowableValues(AzureStorageConflictResolutionStrategy.class) - .defaultValue(AzureStorageConflictResolutionStrategy.FAIL_RESOLUTION.getValue()) + .defaultValue(AzureStorageConflictResolutionStrategy.FAIL_RESOLUTION) .description("Specifies whether an existing blob will have its contents replaced upon conflict.") .build(); - public static final String SAS_TOKEN_BASE_DESCRIPTION = "Shared Access Signature token, including the leading '?'. Specify either SAS token (recommended) or Account Key."; + public static final String SAS_TOKEN_BASE_DESCRIPTION = "Shared Access Signature token (the leading '?' may be included)"; public static final String SAS_TOKEN_SECURITY_DESCRIPTION = - " There are certain risks in allowing the SAS token to be stored as a flowfile " + + " There are certain risks in allowing the SAS token to be stored as a FlowFile " + "attribute. While it does provide for a more flexible flow by allowing the SAS token to " + - "be fetched dynamically from a flowfile attribute, care must be taken to restrict access to " + + "be fetched dynamically from a FlowFile attribute, care must be taken to restrict access to " + "the event provenance data (e.g., by strictly controlling the policies governing provenance for this processor). " + "In addition, the provenance repositories may be put on encrypted disk partitions."; - public static final PropertyDescriptor PROP_SAS_TOKEN = new PropertyDescriptor.Builder() + public static final PropertyDescriptor SAS_TOKEN = new PropertyDescriptor.Builder() .name(STORAGE_SAS_TOKEN_PROPERTY_DESCRIPTOR_NAME) .displayName("SAS Token") - .description(SAS_TOKEN_BASE_DESCRIPTION + SAS_TOKEN_SECURITY_DESCRIPTION) - .required(false) - .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .description(SAS_TOKEN_BASE_DESCRIPTION) + .required(true) + .expressionLanguageSupported(ExpressionLanguageScope.NONE) .sensitive(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SAS_TOKEN) .build(); public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = new PropertyDescriptor.Builder() @@ -160,36 +166,40 @@ public final class AzureStorageUtils { .required(false) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.MANAGED_IDENTITY) .build(); public static final PropertyDescriptor SERVICE_PRINCIPAL_TENANT_ID = new PropertyDescriptor.Builder() .name("service-principal-tenant-id") .displayName("Service Principal Tenant ID") - .description("Tenant ID of the Azure Active Directory hosting the Service Principal. The property is required when Service Principal authentication is used.") + .description("Tenant ID of the Azure Active Directory hosting the Service Principal.") .sensitive(true) - .required(false) + .required(true) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL) .build(); public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_ID = new PropertyDescriptor.Builder() .name("service-principal-client-id") .displayName("Service Principal Client ID") - .description("Client ID (or Application ID) of the Client/Application having the Service Principal. The property is required when Service Principal authentication is used.") + .description("Client ID (or Application ID) of the Client/Application having the Service Principal.") .sensitive(true) - .required(false) + .required(true) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL) .build(); public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_SECRET = new PropertyDescriptor.Builder() .name("service-principal-client-secret") .displayName("Service Principal Client Secret") - .description("Password of the Client/Application. The property is required when Service Principal authentication is used.") + .description("Password of the Client/Application.") .sensitive(true) - .required(false) + .required(true) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.NONE) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL) .build(); private AzureStorageUtils() { @@ -197,8 +207,9 @@ private AzureStorageUtils() { } private static final ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP, ProxySpec.SOCKS}; - public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE - = ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS); + public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE = new PropertyDescriptor.Builder() + .fromPropertyDescriptor(ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS)) + .build(); public static void validateProxySpec(ValidationContext context, Collection results) { ProxyConfiguration.validateProxySpec(context, results, PROXY_SPECS); @@ -215,7 +226,6 @@ public static ProxyOptions getProxyOptions(final PropertyContext propertyContext final ProxyConfiguration proxyConfiguration = ProxyConfiguration.getConfiguration(propertyContext); if (proxyConfiguration != ProxyConfiguration.DIRECT_CONFIGURATION) { - final ProxyOptions proxyOptions = new ProxyOptions( getProxyType(proxyConfiguration), new InetSocketAddress(proxyConfiguration.getProxyServerHost(), proxyConfiguration.getProxyServerPort())); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/BlobInfo.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/BlobInfo.java index 96e1c8cdee55e..542b0827fb2d9 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/BlobInfo.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/BlobInfo.java @@ -16,12 +16,6 @@ */ package org.apache.nifi.processors.azure.storage.utils; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.apache.nifi.processor.util.list.ListableEntity; import org.apache.nifi.serialization.SimpleRecordSchema; import org.apache.nifi.serialization.record.MapRecord; @@ -30,10 +24,14 @@ import org.apache.nifi.serialization.record.RecordFieldType; import org.apache.nifi.serialization.record.RecordSchema; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + public class BlobInfo implements Comparable, Serializable, ListableEntity { private static final long serialVersionUID = 1L; - private static final RecordSchema SCHEMA; private static final String BLOB_NAME = "blobName"; private static final String BLOB_TYPE = "blobType"; private static final String FILENAME = "filename"; @@ -46,22 +44,19 @@ public class BlobInfo implements Comparable, Serializable, ListableEnt private static final String PRIMARY_URI = "primaryUri"; private static final String SECONDARY_URI = "secondaryUri"; - static { - final List recordFields = new ArrayList<>(); - recordFields.add(new RecordField(BLOB_NAME, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(BLOB_TYPE, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(FILENAME, RecordFieldType.STRING.getDataType(), false)); - recordFields.add(new RecordField(CONTAINER_NAME, RecordFieldType.BOOLEAN.getDataType(), false)); - recordFields.add(new RecordField(LENGTH, RecordFieldType.LONG.getDataType(), false)); - recordFields.add(new RecordField(LAST_MODIFIED, RecordFieldType.TIMESTAMP.getDataType(), false)); - recordFields.add(new RecordField(ETAG, RecordFieldType.STRING.getDataType())); - recordFields.add(new RecordField(CONTENT_LANGUAGE, RecordFieldType.STRING.getDataType())); - recordFields.add(new RecordField(CONTENT_TYPE, RecordFieldType.STRING.getDataType())); - recordFields.add(new RecordField(PRIMARY_URI, RecordFieldType.STRING.getDataType())); - recordFields.add(new RecordField(SECONDARY_URI, RecordFieldType.STRING.getDataType())); - SCHEMA = new SimpleRecordSchema(recordFields); - } - + private static final RecordSchema SCHEMA = new SimpleRecordSchema(List.of( + new RecordField(BLOB_NAME, RecordFieldType.STRING.getDataType(), false), + new RecordField(BLOB_TYPE, RecordFieldType.STRING.getDataType(), false), + new RecordField(FILENAME, RecordFieldType.STRING.getDataType(), false), + new RecordField(CONTAINER_NAME, RecordFieldType.BOOLEAN.getDataType(), false), + new RecordField(LENGTH, RecordFieldType.LONG.getDataType(), false), + new RecordField(LAST_MODIFIED, RecordFieldType.TIMESTAMP.getDataType(), false), + new RecordField(ETAG, RecordFieldType.STRING.getDataType()), + new RecordField(CONTENT_LANGUAGE, RecordFieldType.STRING.getDataType()), + new RecordField(CONTENT_TYPE, RecordFieldType.STRING.getDataType()), + new RecordField(PRIMARY_URI, RecordFieldType.STRING.getDataType()), + new RecordField(SECONDARY_URI, RecordFieldType.STRING.getDataType()) + )); private final String primaryUri; private final String secondaryUri; diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/FlowFileResultCarrier.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/FlowFileResultCarrier.java index 7c49b990518ab..85feaf294fe35 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/FlowFileResultCarrier.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/processors/azure/storage/utils/FlowFileResultCarrier.java @@ -18,34 +18,8 @@ import org.apache.nifi.flowfile.FlowFile; -public class FlowFileResultCarrier { - - final private FlowFile flowFile; - final private T result; - final private Throwable exception; - +public record FlowFileResultCarrier(FlowFile flowFile, T result, Throwable exception) { public FlowFileResultCarrier(FlowFile flowFile, T result) { - this.flowFile = flowFile; - this.result = result; - this.exception = null; - } - - public FlowFileResultCarrier(FlowFile flowFile, T result, Throwable exception) { - this.flowFile = flowFile; - this.result = result; - this.exception = exception; - } - - public FlowFile getFlowFile() { - return flowFile; + this(flowFile, result, null); } - - public T getResult() { - return result; - } - - public Throwable getException() { - return exception; - } - } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/StandardAzureCredentialsControllerService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/StandardAzureCredentialsControllerService.java index e36b4d27fbe51..3295fd5c996e4 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/StandardAzureCredentialsControllerService.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/StandardAzureCredentialsControllerService.java @@ -30,8 +30,6 @@ import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; -import java.util.ArrayList; -import java.util.Collections; import java.util.List; /** @@ -55,7 +53,7 @@ public class StandardAzureCredentialsControllerService extends AbstractControlle .required(true) .sensitive(false) .allowableValues(DEFAULT_CREDENTIAL, MANAGED_IDENTITY) - .defaultValue(DEFAULT_CREDENTIAL.toString()) + .defaultValue(DEFAULT_CREDENTIAL) .build(); public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = new PropertyDescriptor.Builder() @@ -70,14 +68,9 @@ public class StandardAzureCredentialsControllerService extends AbstractControlle .dependsOn(CREDENTIAL_CONFIGURATION_STRATEGY, MANAGED_IDENTITY) .build(); - private static final List PROPERTIES; - - static { - final List props = new ArrayList<>(); - props.add(CREDENTIAL_CONFIGURATION_STRATEGY); - props.add(MANAGED_IDENTITY_CLIENT_ID); - PROPERTIES = Collections.unmodifiableList(props); - } + private static final List PROPERTIES = List.of( + CREDENTIAL_CONFIGURATION_STRATEGY, MANAGED_IDENTITY_CLIENT_ID + ); private TokenCredential credentials; @@ -95,9 +88,9 @@ public TokenCredential getCredentials() throws ProcessException { public void onConfigured(final ConfigurationContext context) { final String configurationStrategy = context.getProperty(CREDENTIAL_CONFIGURATION_STRATEGY).getValue(); - if (DEFAULT_CREDENTIAL.equals(configurationStrategy)) { + if (DEFAULT_CREDENTIAL.getValue().equals(configurationStrategy)) { credentials = getDefaultAzureCredential(); - } else if (MANAGED_IDENTITY.equals(configurationStrategy)) { + } else if (MANAGED_IDENTITY.getValue().equals(configurationStrategy)) { credentials = getManagedIdentityCredential(context); } else { final String errorMsg = String.format("Configuration Strategy [%s] not recognized", configurationStrategy); @@ -113,10 +106,9 @@ private TokenCredential getDefaultAzureCredential() { private TokenCredential getManagedIdentityCredential(final ConfigurationContext context) { final String clientId = context.getProperty(MANAGED_IDENTITY_CLIENT_ID).getValue(); - final TokenCredential managedIdentityCredential = new ManagedIdentityCredentialBuilder() + return new ManagedIdentityCredentialBuilder() .clientId(clientId) .build(); - return managedIdentityCredential; } @Override diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/cosmos/document/AzureCosmosDBClientService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/cosmos/document/AzureCosmosDBClientService.java index c448ebdaae89b..33ad3d3e1e585 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/cosmos/document/AzureCosmosDBClientService.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/cosmos/document/AzureCosmosDBClientService.java @@ -17,15 +17,10 @@ package org.apache.nifi.services.azure.cosmos.document; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - import com.azure.cosmos.ConsistencyLevel; import com.azure.cosmos.CosmosClient; import com.azure.cosmos.CosmosClientBuilder; import com.azure.cosmos.CosmosException; - import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.annotation.lifecycle.OnEnabled; @@ -39,6 +34,10 @@ import org.apache.nifi.services.azure.cosmos.AzureCosmosDBConnectionService; import org.apache.nifi.util.StringUtils; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + @Tags({"azure", "cosmos", "document", "service"}) @CapabilityDescription( "Provides a controller service that configures a connection to Cosmos DB (Core SQL API) " + @@ -54,37 +53,15 @@ public class AzureCosmosDBClientService extends AbstractControllerService implem public void onEnabled(final ConfigurationContext context) { this.uri = context.getProperty(AzureCosmosDBUtils.URI).getValue(); this.accessKey = context.getProperty(AzureCosmosDBUtils.DB_ACCESS_KEY).getValue(); - final ConsistencyLevel clevel; final String selectedConsistency = context.getProperty(AzureCosmosDBUtils.CONSISTENCY).getValue(); - - switch(selectedConsistency) { - case AzureCosmosDBUtils.CONSISTENCY_STRONG: - clevel = ConsistencyLevel.STRONG; - break; - case AzureCosmosDBUtils.CONSISTENCY_CONSISTENT_PREFIX: - clevel = ConsistencyLevel.CONSISTENT_PREFIX; - break; - case AzureCosmosDBUtils.CONSISTENCY_SESSION: - clevel = ConsistencyLevel.SESSION; - break; - case AzureCosmosDBUtils.CONSISTENCY_BOUNDED_STALENESS: - clevel = ConsistencyLevel.BOUNDED_STALENESS; - break; - case AzureCosmosDBUtils.CONSISTENCY_EVENTUAL: - clevel = ConsistencyLevel.EVENTUAL; - break; - default: - clevel = ConsistencyLevel.SESSION; - } - + final ConsistencyLevel consistencyLevel = AzureCosmosDBUtils.determineConsistencyLevel(selectedConsistency); if (this.cosmosClient != null) { onStopped(); } - consistencyLevel = clevel.toString(); - createCosmosClient(uri, accessKey, clevel); + this.consistencyLevel = consistencyLevel.toString(); + createCosmosClient(uri, accessKey, consistencyLevel); } - @OnStopped public final void onStopped() { if (this.cosmosClient != null) { @@ -106,13 +83,11 @@ protected void createCosmosClient(final String uri, final String accessKey, fina .buildClient(); } - static List descriptors = new ArrayList<>(); - - static { - descriptors.add(AzureCosmosDBUtils.URI); - descriptors.add(AzureCosmosDBUtils.DB_ACCESS_KEY); - descriptors.add(AzureCosmosDBUtils.CONSISTENCY); - } + static List descriptors = List.of( + AzureCosmosDBUtils.URI, + AzureCosmosDBUtils.DB_ACCESS_KEY, + AzureCosmosDBUtils.CONSISTENCY + ); @Override protected List getSupportedPropertyDescriptors() { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoAuthenticationStrategy.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoAuthenticationStrategy.java index 01946fe6258a0..5182bbef1af60 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoAuthenticationStrategy.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoAuthenticationStrategy.java @@ -18,9 +18,8 @@ import org.apache.nifi.components.DescribedValue; -enum KustoAuthenticationStrategy implements DescribedValue { +public enum KustoAuthenticationStrategy implements DescribedValue { APPLICATION_CREDENTIALS("Application Credentials", "Azure Application Registration with Application Key"), - MANAGED_IDENTITY("Managed Identity", "Azure Managed Identity"); private final String displayName; diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestQueryResponse.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestQueryResponse.java new file mode 100644 index 0000000000000..8e52b92a426e1 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestQueryResponse.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package org.apache.nifi.services.azure.data.explorer; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class KustoIngestQueryResponse { + + private boolean error; + + private Map> queryResult; + + public boolean isError() { + return error; + } + + public void setError(boolean error) { + this.error = error; + } + + public Map> getQueryResult() { + return queryResult; + } + + public KustoIngestQueryResponse(final Map> queryResult) { + this.error = false; + this.queryResult = Collections.unmodifiableMap(queryResult); + } + + public KustoIngestQueryResponse(final boolean error) { + this.error = error; + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoIngestService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoIngestService.java new file mode 100644 index 0000000000000..f384497bb4f72 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoIngestService.java @@ -0,0 +1,409 @@ +/* + * 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. + */ +package org.apache.nifi.services.azure.data.explorer; + +import com.microsoft.azure.kusto.data.Client; +import com.microsoft.azure.kusto.data.ClientFactory; +import com.microsoft.azure.kusto.data.KustoResultColumn; +import com.microsoft.azure.kusto.data.KustoResultSetTable; +import com.microsoft.azure.kusto.data.auth.ConnectionStringBuilder; +import com.microsoft.azure.kusto.data.exceptions.DataClientException; +import com.microsoft.azure.kusto.data.exceptions.DataServiceException; +import com.microsoft.azure.kusto.ingest.IngestClientFactory; +import com.microsoft.azure.kusto.ingest.IngestionMapping; +import com.microsoft.azure.kusto.ingest.IngestionProperties; +import com.microsoft.azure.kusto.ingest.ManagedStreamingIngestClient; +import com.microsoft.azure.kusto.ingest.QueuedIngestClient; +import com.microsoft.azure.kusto.ingest.exceptions.IngestionClientException; +import com.microsoft.azure.kusto.ingest.exceptions.IngestionServiceException; +import com.microsoft.azure.kusto.ingest.result.IngestionResult; +import com.microsoft.azure.kusto.ingest.result.IngestionStatus; +import com.microsoft.azure.kusto.ingest.result.OperationStatus; +import com.microsoft.azure.kusto.ingest.source.StreamSourceInfo; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.nifi.annotation.documentation.CapabilityDescription; +import org.apache.nifi.annotation.documentation.Tags; +import org.apache.nifi.annotation.lifecycle.OnEnabled; +import org.apache.nifi.annotation.lifecycle.OnStopped; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.controller.AbstractControllerService; +import org.apache.nifi.controller.ConfigurationContext; +import org.apache.nifi.processor.exception.ProcessException; +import org.apache.nifi.processor.util.StandardValidators; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@Tags({"Azure", "Data", "Explorer", "ADX", "Kusto", "ingest", "azure"}) +@CapabilityDescription("Sends batches of flowfile content or stream flowfile content to an Azure ADX cluster.") +public class StandardKustoIngestService extends AbstractControllerService implements KustoIngestService { + + public static final PropertyDescriptor AUTHENTICATION_STRATEGY = new PropertyDescriptor.Builder() + .name("Authentication Strategy") + .displayName("Authentication Strategy") + .description("Authentication method for access to Azure Data Explorer") + .required(true) + .defaultValue(KustoAuthenticationStrategy.MANAGED_IDENTITY.getValue()) + .allowableValues(KustoAuthenticationStrategy.class) + .build(); + + public static final PropertyDescriptor APPLICATION_CLIENT_ID = new PropertyDescriptor.Builder() + .name("Application Client ID") + .displayName("Application Client ID") + .description("Azure Data Explorer Application Client Identifier for Authentication") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .build(); + + public static final PropertyDescriptor APPLICATION_KEY = new PropertyDescriptor.Builder() + .name("Application Key") + .displayName("Application Key") + .description("Azure Data Explorer Application Key for Authentication") + .required(true) + .sensitive(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS.getValue()) + .build(); + + public static final PropertyDescriptor APPLICATION_TENANT_ID = new PropertyDescriptor.Builder() + .name("Application Tenant ID") + .displayName("Application Tenant ID") + .description("Azure Data Explorer Application Tenant Identifier for Authentication") + .required(true) + .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) + .dependsOn(AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS.getValue()) + .build(); + + public static final PropertyDescriptor CLUSTER_URI = new PropertyDescriptor.Builder() + .name("Cluster URI") + .displayName("Cluster URI") + .description("Azure Data Explorer Cluster URI") + .required(true) + .addValidator(StandardValidators.URL_VALIDATOR) + .build(); + + private static final List PROPERTY_DESCRIPTORS = List.of( + AUTHENTICATION_STRATEGY, + APPLICATION_CLIENT_ID, + APPLICATION_KEY, + APPLICATION_TENANT_ID, + CLUSTER_URI + ); + + private static final String STREAMING_POLICY_SHOW_COMMAND = ".show database %s policy streamingingestion"; + + private static final String COUNT_TABLE_COMMAND = "%s | count"; + + private static final Pair NIFI_SINK = Pair.of("processor", StandardKustoIngestService.class.getSimpleName()); + + private volatile QueuedIngestClient queuedIngestClient; + + private volatile ManagedStreamingIngestClient managedStreamingIngestClient; + + private volatile Client executionClient; + + @Override + public List getSupportedPropertyDescriptors() { + return PROPERTY_DESCRIPTORS; + } + + @OnEnabled + public void onEnabled(final ConfigurationContext context) throws ProcessException, URISyntaxException { + final String applicationClientId = context.getProperty(APPLICATION_CLIENT_ID).getValue(); + final String applicationKey = context.getProperty(APPLICATION_KEY).getValue(); + final String applicationTenantId = context.getProperty(APPLICATION_TENANT_ID).getValue(); + final String clusterUri = context.getProperty(CLUSTER_URI).getValue(); + final KustoAuthenticationStrategy kustoAuthenticationStrategy = KustoAuthenticationStrategy.valueOf(context.getProperty(AUTHENTICATION_STRATEGY).getValue()); + + this.queuedIngestClient = createKustoQueuedIngestClient(clusterUri, applicationClientId, applicationKey, applicationTenantId, kustoAuthenticationStrategy); + this.managedStreamingIngestClient = createKustoStreamingIngestClient(clusterUri, applicationClientId, applicationKey, applicationTenantId, kustoAuthenticationStrategy); + this.executionClient = createKustoExecutionClient(clusterUri, applicationClientId, applicationKey, applicationTenantId, kustoAuthenticationStrategy); + } + + @OnStopped + public final void onStopped() { + if (this.queuedIngestClient != null) { + try { + this.queuedIngestClient.close(); + } catch (IOException e) { + getLogger().error("Closing Azure Data Explorer Queued Ingest Client failed", e); + } finally { + this.queuedIngestClient = null; + } + } + if (this.managedStreamingIngestClient != null) { + try { + this.managedStreamingIngestClient.close(); + } catch (IOException e) { + getLogger().error("Closing Azure Data Explorer Managed Streaming Ingest Client failed", e); + } finally { + this.managedStreamingIngestClient = null; + } + } + if (this.executionClient != null) { + try { + this.executionClient.close(); + } catch (IOException e) { + getLogger().error("Closing Azure Data Explorer Execution Client failed", e); + } finally { + this.executionClient = null; + } + } + } + + + protected QueuedIngestClient createKustoQueuedIngestClient(final String clusterUrl, + final String appId, + final String appKey, + final String appTenant, + final KustoAuthenticationStrategy kustoAuthStrategy) throws URISyntaxException { + ConnectionStringBuilder ingestConnectionStringBuilder = createKustoEngineConnectionString(clusterUrl, appId, appKey, appTenant, kustoAuthStrategy); + return IngestClientFactory.createClient(ingestConnectionStringBuilder); + } + + protected ManagedStreamingIngestClient createKustoStreamingIngestClient(final String clusterUrl, + final String appId, + final String appKey, + final String appTenant, + final KustoAuthenticationStrategy kustoAuthStrategy) throws URISyntaxException { + ConnectionStringBuilder ingestConnectionStringBuilder = createKustoEngineConnectionString(clusterUrl, appId, appKey, appTenant, kustoAuthStrategy); + ConnectionStringBuilder streamingConnectionStringBuilder = createKustoEngineConnectionString(clusterUrl, appId, appKey, appTenant, kustoAuthStrategy); + return IngestClientFactory.createManagedStreamingIngestClient(ingestConnectionStringBuilder, streamingConnectionStringBuilder); + } + + @Override + public KustoIngestionResult ingestData(final KustoIngestionRequest kustoIngestionRequest) { + final StreamSourceInfo info = new StreamSourceInfo(kustoIngestionRequest.getInputStream()); + + IngestionProperties ingestionProperties = new IngestionProperties(kustoIngestionRequest.getDatabaseName(), + kustoIngestionRequest.getTableName()); + + IngestionMapping.IngestionMappingKind ingestionMappingKind = setDataFormatAndMapping(kustoIngestionRequest.getDataFormat(), ingestionProperties); + if (StringUtils.isNotEmpty(kustoIngestionRequest.getMappingName()) && ingestionMappingKind != null) { + ingestionProperties.setIngestionMapping(kustoIngestionRequest.getMappingName(), ingestionMappingKind); + } + + ingestionProperties.setReportLevel(IngestionProperties.IngestionReportLevel.FAILURES_AND_SUCCESSES); + ingestionProperties.setReportMethod(IngestionProperties.IngestionReportMethod.TABLE); + ingestionProperties.setFlushImmediately(false); + ingestionProperties.setIgnoreFirstRecord(kustoIngestionRequest.isIgnoreFirstRecord()); + + final IngestionResult ingestionResult; + try { + if (kustoIngestionRequest.isStreamingEnabled()) { + ingestionResult = managedStreamingIngestClient.ingestFromStream(info, ingestionProperties); + } else { + ingestionResult = queuedIngestClient.ingestFromStream(info, ingestionProperties); + } + if (kustoIngestionRequest.pollOnIngestionStatus()) { + long timeoutMillis = kustoIngestionRequest.getIngestionStatusPollingTimeout().toMillis(); + long ingestionStatusPollingInterval = kustoIngestionRequest.getIngestionStatusPollingInterval().toMillis(); + return pollOnIngestionStatus(ingestionResult, timeoutMillis, ingestionStatusPollingInterval); + } else { + return KustoIngestionResult.SUCCEEDED; + } + } catch (IngestionClientException | IngestionServiceException | URISyntaxException e) { + throw new ProcessException("Azure Data Explorer Ingest failed", e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); //Restore interrupted status + throw new ProcessException("Azure Data Explorer Ingest interrupted", e); + } + } + + private KustoIngestionResult pollOnIngestionStatus(IngestionResult ingestionResult, long timeoutMillis, long ingestionStatusPollingInterval) throws URISyntaxException, InterruptedException { + List statuses = initializeKustoIngestionStatusAsPending(); + final long startTime = System.currentTimeMillis(); + // Calculate the end time based on the timeout duration + final long endTime = startTime + timeoutMillis; + while (System.currentTimeMillis() < endTime) { + // Get the status of the ingestion operation + final List currentStatuses = ingestionResult.getIngestionStatusCollection(); + final OperationStatus operationStatus = currentStatuses.getFirst().status; + if (operationStatus == OperationStatus.Succeeded + || operationStatus == OperationStatus.Failed + || operationStatus == OperationStatus.PartiallySucceeded) { + statuses = currentStatuses; + break; + } + // Sleep for before checking again + Thread.sleep(ingestionStatusPollingInterval); + } + // Check if the timeout has been exceeded + if (System.currentTimeMillis() - startTime >= timeoutMillis) { + throw new ProcessException(String.format("Timeout of %s exceeded while waiting for ingestion status", ingestionStatusPollingInterval)); + } + return KustoIngestionResult.fromString(statuses.getFirst().status.toString()); + } + + @Override + public boolean isStreamingPolicyEnabled(final String databaseName) { + final String query = String.format(STREAMING_POLICY_SHOW_COMMAND, databaseName); + final KustoIngestQueryResponse kustoIngestQueryResponse = executeQuery(databaseName, query); + + boolean streamingPolicyEnabled = false; + if (!kustoIngestQueryResponse.getQueryResult().isEmpty()) { + final List row = kustoIngestQueryResponse.getQueryResult().get(0); + if (!row.isEmpty()) { + final String streamingPolicy = row.get(2); + if (!streamingPolicy.isEmpty()) { + streamingPolicyEnabled = true; + } + } + } + return streamingPolicyEnabled; + } + + @Override + public boolean isTableReadable(final String databaseName, final String tableName) { + final String query = String.format(COUNT_TABLE_COMMAND, tableName); + final KustoIngestQueryResponse kustoIngestQueryResponse = executeQuery(databaseName, query); + return !kustoIngestQueryResponse.isError(); + } + + protected List initializeKustoIngestionStatusAsPending(){ + IngestionStatus ingestionStatus = new IngestionStatus(); + ingestionStatus.status = OperationStatus.Pending; + return Collections.singletonList(ingestionStatus); + } + + protected Client createKustoExecutionClient(final String clusterUrl, + final String appId, + final String appKey, + final String appTenant, + final KustoAuthenticationStrategy kustoAuthStrategy) throws URISyntaxException { + return ClientFactory.createClient(createKustoEngineConnectionString(clusterUrl, appId, appKey, appTenant, kustoAuthStrategy)); + } + + private ConnectionStringBuilder createKustoEngineConnectionString(final String clusterUrl, + final String appId, + final String appKey, + final String appTenant, + final KustoAuthenticationStrategy kustoAuthStrategy) { + final ConnectionStringBuilder builder; + if (KustoAuthenticationStrategy.APPLICATION_CREDENTIALS == kustoAuthStrategy) { + builder = ConnectionStringBuilder.createWithAadApplicationCredentials(clusterUrl, appId, appKey, appTenant); + } else { + builder = ConnectionStringBuilder.createWithAadManagedIdentity(clusterUrl, appId); + } + + builder.setConnectorDetails("Kusto.Nifi.Sink", StandardKustoIngestService.class.getPackage().getImplementationVersion(), null, null, false, null, NIFI_SINK); + return builder; + } + + private KustoIngestQueryResponse executeQuery(final String databaseName, final String query) { + Objects.requireNonNull(databaseName, "Database Name required"); + Objects.requireNonNull(query, "Query required"); + + KustoIngestQueryResponse kustoIngestQueryResponse; + try { + KustoResultSetTable kustoResultSetTable = this.executionClient.execute(databaseName, query).getPrimaryResults(); + Map> response = new HashMap<>(); + int rowCount = 0; + + // Add the received values to the new ingestion resources + while (kustoResultSetTable.hasNext()) { + kustoResultSetTable.next(); + List rowData = new ArrayList<>(); + for (KustoResultColumn columnName : kustoResultSetTable.getColumns()) { + String data = kustoResultSetTable.getString(columnName.getOrdinal()); + rowData.add(data); + } + response.put(rowCount++, rowData); + } + kustoIngestQueryResponse = new KustoIngestQueryResponse(response); + } catch (final DataServiceException | DataClientException e) { + getLogger().error("Azure Data Explorer Ingest execution failed", e); + kustoIngestQueryResponse = new KustoIngestQueryResponse(true); + } + return kustoIngestQueryResponse; + } + + private IngestionMapping.IngestionMappingKind setDataFormatAndMapping(String dataFormat, IngestionProperties ingestionProperties) { + final IngestionProperties.DataFormat dataFormatFound = getDataFormat(dataFormat); + return switch (dataFormatFound) { + case AVRO -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.AVRO); + yield IngestionProperties.DataFormat.AVRO.getIngestionMappingKind(); + } + case APACHEAVRO -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.APACHEAVRO); + yield IngestionProperties.DataFormat.APACHEAVRO.getIngestionMappingKind(); + } + case CSV -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.CSV); + yield IngestionProperties.DataFormat.CSV.getIngestionMappingKind(); + } + case JSON -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.JSON); + yield IngestionProperties.DataFormat.JSON.getIngestionMappingKind(); + } + case MULTIJSON -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.MULTIJSON); + yield IngestionProperties.DataFormat.MULTIJSON.getIngestionMappingKind(); + } + case ORC -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.ORC); + yield IngestionProperties.DataFormat.ORC.getIngestionMappingKind(); + } + case PARQUET -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.PARQUET); + yield IngestionProperties.DataFormat.PARQUET.getIngestionMappingKind(); + } + case PSV -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.PSV); + yield IngestionProperties.DataFormat.PSV.getIngestionMappingKind(); + } + case SCSV -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.SCSV); + yield IngestionProperties.DataFormat.SCSV.getIngestionMappingKind(); + } + case SOHSV -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.SOHSV); + yield IngestionProperties.DataFormat.SOHSV.getIngestionMappingKind(); + } + case TSV -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.TSV); + yield IngestionProperties.DataFormat.TSV.getIngestionMappingKind(); + } + case TSVE -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.TSVE); + yield IngestionProperties.DataFormat.TSVE.getIngestionMappingKind(); + } + case TXT -> { + ingestionProperties.setDataFormat(IngestionProperties.DataFormat.TXT); + yield IngestionProperties.DataFormat.TXT.getIngestionMappingKind(); + } + default -> null; + }; + } + + private IngestionProperties.DataFormat getDataFormat(final String dataFormat) { + final Optional dataFormatFound = Arrays.stream(IngestionProperties.DataFormat.values()) + .filter(value -> value.getKustoValue().equalsIgnoreCase(dataFormat)) + .findFirst(); + return dataFormatFound.orElseThrow(() -> new IllegalArgumentException("Data Format [%s] not supported".formatted(dataFormat))); + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryService.java index a7eb5db4dccab..05f639da8e3ea 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryService.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryService.java @@ -20,6 +20,7 @@ import com.microsoft.azure.kusto.data.StreamingClient; import com.microsoft.azure.kusto.data.auth.ConnectionStringBuilder; +import org.apache.commons.lang3.tuple.Pair; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.annotation.lifecycle.OnEnabled; @@ -32,7 +33,6 @@ import java.io.InputStream; import java.net.URISyntaxException; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -53,7 +53,7 @@ public class StandardKustoQueryService extends AbstractControllerService impleme .displayName("Authentication Strategy") .description("Authentication method for access to Azure Data Explorer") .required(true) - .defaultValue(KustoAuthenticationStrategy.MANAGED_IDENTITY.getValue()) + .defaultValue(KustoAuthenticationStrategy.MANAGED_IDENTITY) .allowableValues(KustoAuthenticationStrategy.class) .build(); @@ -71,7 +71,7 @@ public class StandardKustoQueryService extends AbstractControllerService impleme .description("Azure Data Explorer Application Tenant Identifier for Authentication") .required(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .dependsOn(AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS.getValue()) + .dependsOn(AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS) .build(); public static final PropertyDescriptor APPLICATION_KEY = new PropertyDescriptor.Builder() @@ -81,10 +81,10 @@ public class StandardKustoQueryService extends AbstractControllerService impleme .required(true) .sensitive(true) .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) - .dependsOn(AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS.getValue()) + .dependsOn(AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS) .build(); - private static final List PROPERTY_DESCRIPTORS = Arrays.asList( + private static final List PROPERTY_DESCRIPTORS = List.of( CLUSTER_URI, AUTHENTICATION_STRATEGY, APPLICATION_CLIENT_ID, @@ -99,6 +99,8 @@ public List getSupportedPropertyDescriptors() { return PROPERTY_DESCRIPTORS; } + public static final Pair NIFI_SOURCE = Pair.of("processor", "nifi-source"); + @OnEnabled public void onEnabled(final ConfigurationContext context) throws ProcessException, URISyntaxException { if (this.kustoClient == null) { @@ -144,25 +146,20 @@ protected StreamingClient createClient(final ConfigurationContext context) throw @SuppressWarnings("unchecked") private ConnectionStringBuilder getConnectionStringBuilder(final ConfigurationContext context) { - final ConnectionStringBuilder builder; - final String clusterUrl = context.getProperty(CLUSTER_URI).getValue(); final String clientId = context.getProperty(APPLICATION_CLIENT_ID).getValue(); + final KustoAuthenticationStrategy kustoAuthenticationStrategy = context.getProperty(AUTHENTICATION_STRATEGY).asAllowableValue(KustoAuthenticationStrategy.class); - final KustoAuthenticationStrategy kustoAuthenticationStrategy = KustoAuthenticationStrategy.valueOf(context.getProperty(AUTHENTICATION_STRATEGY).getValue()); - - if (KustoAuthenticationStrategy.MANAGED_IDENTITY == kustoAuthenticationStrategy) { - builder = ConnectionStringBuilder.createWithAadManagedIdentity(clusterUrl, clientId); - } else { - final String applicationKey = context.getProperty(APPLICATION_KEY).getValue(); - final String tenantId = context.getProperty(APPLICATION_TENANT_ID).getValue(); - builder = ConnectionStringBuilder.createWithAadApplicationCredentials(clusterUrl, clientId, applicationKey, tenantId); - } - - final String vendor = System.getProperty("java.vendor"); - final String version = System.getProperty("java.version"); + final ConnectionStringBuilder builder = switch (kustoAuthenticationStrategy) { + case APPLICATION_CREDENTIALS -> { + final String applicationKey = context.getProperty(APPLICATION_KEY).getValue(); + final String tenantId = context.getProperty(APPLICATION_TENANT_ID).getValue(); + yield ConnectionStringBuilder.createWithAadApplicationCredentials(clusterUrl, clientId, applicationKey, tenantId); + } + case MANAGED_IDENTITY -> ConnectionStringBuilder.createWithAadManagedIdentity(clusterUrl, clientId); + }; - builder.setConnectorDetails(vendor, version, null, null, false, null); + builder.setConnectorDetails("Kusto.Nifi.Source", StandardKustoQueryService.class.getPackage().getImplementationVersion(), null, null, false, null, NIFI_SOURCE); return builder; } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/eventhub/AzureEventHubRecordSink.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/eventhub/AzureEventHubRecordSink.java index 9345a4692da02..de143e7c4f7f2 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/eventhub/AzureEventHubRecordSink.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/eventhub/AzureEventHubRecordSink.java @@ -20,7 +20,6 @@ import com.azure.core.credential.AzureNamedKeyCredential; import com.azure.identity.DefaultAzureCredential; import com.azure.identity.DefaultAzureCredentialBuilder; - import com.azure.messaging.eventhubs.EventData; import com.azure.messaging.eventhubs.EventDataBatch; import com.azure.messaging.eventhubs.EventHubClientBuilder; @@ -46,11 +45,10 @@ import org.apache.nifi.serialization.record.Record; import org.apache.nifi.serialization.record.RecordSet; import org.apache.nifi.shared.azure.eventhubs.AzureEventHubComponent; +import org.apache.nifi.shared.azure.eventhubs.AzureEventHubTransportType; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -60,11 +58,8 @@ public class AzureEventHubRecordSink extends AbstractControllerService implements RecordSinkService, AzureEventHubComponent { static final AllowableValue AZURE_ENDPOINT = new AllowableValue(".servicebus.windows.net","Azure", "Default Service Bus Endpoint"); - static final AllowableValue AZURE_CHINA_ENDPOINT = new AllowableValue(".servicebus.chinacloudapi.cn", "Azure China", "China Service Bus Endpoint"); - static final AllowableValue AZURE_GERMANY_ENDPOINT = new AllowableValue(".servicebus.cloudapi.de", "Azure Germany", "Germany Service Bus Endpoint"); - static final AllowableValue AZURE_US_GOV_ENDPOINT = new AllowableValue(".servicebus.usgovcloudapi.net", "Azure US Government", "United States Government Endpoint"); static final PropertyDescriptor SERVICE_BUS_ENDPOINT = new PropertyDescriptor.Builder() @@ -78,7 +73,7 @@ public class AzureEventHubRecordSink extends AbstractControllerService implement AZURE_GERMANY_ENDPOINT, AZURE_US_GOV_ENDPOINT ) - .defaultValue(AZURE_ENDPOINT.getValue()) + .defaultValue(AZURE_ENDPOINT) .required(true) .build(); @@ -102,7 +97,7 @@ public class AzureEventHubRecordSink extends AbstractControllerService implement .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .allowableValues(AzureAuthenticationStrategy.class) .required(true) - .defaultValue(AzureAuthenticationStrategy.DEFAULT_AZURE_CREDENTIAL.getValue()) + .defaultValue(AzureAuthenticationStrategy.DEFAULT_AZURE_CREDENTIAL) .build(); static final PropertyDescriptor SHARED_ACCESS_POLICY = new PropertyDescriptor.Builder() @@ -110,7 +105,7 @@ public class AzureEventHubRecordSink extends AbstractControllerService implement .description("The name of the shared access policy. This policy must have Send claims") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .required(false) - .dependsOn(AUTHENTICATION_STRATEGY, AzureAuthenticationStrategy.SHARED_ACCESS_KEY.getValue()) + .dependsOn(AUTHENTICATION_STRATEGY, AzureAuthenticationStrategy.SHARED_ACCESS_KEY) .build(); static final PropertyDescriptor SHARED_ACCESS_POLICY_KEY = new PropertyDescriptor.Builder() @@ -119,7 +114,7 @@ public class AzureEventHubRecordSink extends AbstractControllerService implement .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .sensitive(true) .required(false) - .dependsOn(AUTHENTICATION_STRATEGY, AzureAuthenticationStrategy.SHARED_ACCESS_KEY.getValue()) + .dependsOn(AUTHENTICATION_STRATEGY, AzureAuthenticationStrategy.SHARED_ACCESS_KEY) .build(); static final PropertyDescriptor PARTITION_KEY = new PropertyDescriptor.Builder() @@ -130,18 +125,16 @@ public class AzureEventHubRecordSink extends AbstractControllerService implement .required(false) .build(); - private static final List PROPERTY_DESCRIPTORS = Collections.unmodifiableList( - Arrays.asList( - SERVICE_BUS_ENDPOINT, - EVENT_HUB_NAMESPACE, - EVENT_HUB_NAME, - TRANSPORT_TYPE, - RECORD_WRITER_FACTORY, - AUTHENTICATION_STRATEGY, - SHARED_ACCESS_POLICY, - SHARED_ACCESS_POLICY_KEY, - PARTITION_KEY - ) + private static final List PROPERTY_DESCRIPTORS = List.of( + SERVICE_BUS_ENDPOINT, + EVENT_HUB_NAMESPACE, + EVENT_HUB_NAME, + TRANSPORT_TYPE, + RECORD_WRITER_FACTORY, + AUTHENTICATION_STRATEGY, + SHARED_ACCESS_POLICY, + SHARED_ACCESS_POLICY_KEY, + PARTITION_KEY ); private volatile ConfigurationContext context; @@ -184,9 +177,8 @@ public void onEnabled(final ConfigurationContext context) { final String eventHubName = context.getProperty(EVENT_HUB_NAME).evaluateAttributeExpressions().getValue(); final String policyName = context.getProperty(SHARED_ACCESS_POLICY).getValue(); final String policyKey = context.getProperty(SHARED_ACCESS_POLICY_KEY).getValue(); - final String authenticationStrategy = context.getProperty(AUTHENTICATION_STRATEGY).getValue(); - final AzureAuthenticationStrategy azureAuthenticationStrategy = AzureAuthenticationStrategy.valueOf(authenticationStrategy); - final AmqpTransportType transportType = AmqpTransportType.fromString(context.getProperty(TRANSPORT_TYPE).getValue()); + final AzureAuthenticationStrategy azureAuthenticationStrategy = context.getProperty(AUTHENTICATION_STRATEGY).asAllowableValue(AzureAuthenticationStrategy.class); + final AmqpTransportType transportType = context.getProperty(TRANSPORT_TYPE).asAllowableValue(AzureEventHubTransportType.class).asAmqpTransportType(); client = createEventHubClient(namespace, serviceBusEndpoint, eventHubName, policyName, policyKey, azureAuthenticationStrategy, transportType); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java index a6b5e959e1b15..c5b8b3fd1e33e 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/ADLSCredentialsControllerService.java @@ -16,30 +16,29 @@ */ package org.apache.nifi.services.azure.storage; -import org.apache.commons.lang3.StringUtils; import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.annotation.lifecycle.OnEnabled; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.PropertyValue; -import org.apache.nifi.components.ValidationContext; -import org.apache.nifi.components.ValidationResult; import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.controller.ConfigurationContext; import org.apache.nifi.expression.ExpressionLanguageScope; -import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.migration.PropertyConfiguration; import org.apache.nifi.processors.azure.AzureServiceEndpoints; import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Function; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.CREDENTIALS_TYPE; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_SECRET; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID; + /** * Provides credentials details for ADLS * @@ -52,51 +51,44 @@ public class ADLSCredentialsControllerService extends AbstractControllerService public static final PropertyDescriptor ACCOUNT_NAME = new PropertyDescriptor.Builder() .fromPropertyDescriptor(AzureStorageUtils.ACCOUNT_NAME) .description(AzureStorageUtils.ACCOUNT_NAME_BASE_DESCRIPTION + AzureStorageUtils.ACCOUNT_NAME_SECURITY_DESCRIPTION) - .required(true) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor ACCOUNT_KEY = new PropertyDescriptor.Builder() + .fromPropertyDescriptor(AzureStorageUtils.ACCOUNT_KEY) + .description(AzureStorageUtils.ACCOUNT_KEY_BASE_DESCRIPTION + AzureStorageUtils.ACCOUNT_KEY_SECURITY_DESCRIPTION) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) + .build(); + + public static final PropertyDescriptor SAS_TOKEN = new PropertyDescriptor.Builder() + .fromPropertyDescriptor(AzureStorageUtils.SAS_TOKEN) + .description(AzureStorageUtils.SAS_TOKEN_BASE_DESCRIPTION + AzureStorageUtils.SAS_TOKEN_SECURITY_DESCRIPTION) + .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) .build(); public static final PropertyDescriptor ENDPOINT_SUFFIX = new PropertyDescriptor.Builder() .fromPropertyDescriptor(AzureStorageUtils.ENDPOINT_SUFFIX) - .displayName("Endpoint Suffix") - .description("Storage accounts in public Azure always use a common FQDN suffix. " + - "Override this endpoint suffix with a different suffix in certain circumstances (like Azure Stack or non-public Azure regions).") - .required(true) .defaultValue(AzureServiceEndpoints.DEFAULT_ADLS_ENDPOINT_SUFFIX) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .build(); - public static final PropertyDescriptor USE_MANAGED_IDENTITY = new PropertyDescriptor.Builder() - .name("storage-use-managed-identity") - .displayName("Use Azure Managed Identity") - .description("Choose whether or not to use the managed identity of Azure VM/VMSS") - .required(false) - .defaultValue("false") - .allowableValues("true", "false") - .addValidator(StandardValidators.BOOLEAN_VALIDATOR) + public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE = new PropertyDescriptor.Builder() + .fromPropertyDescriptor(AzureStorageUtils.PROXY_CONFIGURATION_SERVICE) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL, AzureStorageCredentialsType.MANAGED_IDENTITY) .build(); - public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID; - - public static final PropertyDescriptor SERVICE_PRINCIPAL_TENANT_ID = AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID; - - public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_ID = AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID; - - public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_SECRET = AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_SECRET; - - public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE = AzureStorageUtils.PROXY_CONFIGURATION_SERVICE; - - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ACCOUNT_NAME, ENDPOINT_SUFFIX, - AzureStorageUtils.ACCOUNT_KEY, - AzureStorageUtils.PROP_SAS_TOKEN, - USE_MANAGED_IDENTITY, + CREDENTIALS_TYPE, + ACCOUNT_KEY, + SAS_TOKEN, MANAGED_IDENTITY_CLIENT_ID, SERVICE_PRINCIPAL_TENANT_ID, SERVICE_PRINCIPAL_CLIENT_ID, SERVICE_PRINCIPAL_CLIENT_SECRET, PROXY_CONFIGURATION_SERVICE - )); + ); private ConfigurationContext context; @@ -106,66 +98,26 @@ protected List getSupportedPropertyDescriptors() { } @Override - protected Collection customValidate(ValidationContext validationContext) { - final List results = new ArrayList<>(); - - final boolean accountKeySet = StringUtils.isNotBlank(validationContext.getProperty(AzureStorageUtils.ACCOUNT_KEY).getValue()); - final boolean sasTokenSet = StringUtils.isNotBlank(validationContext.getProperty(AzureStorageUtils.PROP_SAS_TOKEN).getValue()); - final boolean useManagedIdentitySet = validationContext.getProperty(USE_MANAGED_IDENTITY).asBoolean(); - - final boolean servicePrincipalTenantIdSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_TENANT_ID).getValue()); - final boolean servicePrincipalClientIdSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_CLIENT_ID).getValue()); - final boolean servicePrincipalClientSecretSet = StringUtils.isNotBlank(validationContext.getProperty(SERVICE_PRINCIPAL_CLIENT_SECRET).getValue()); - - final boolean servicePrincipalSet = servicePrincipalTenantIdSet || servicePrincipalClientIdSet || servicePrincipalClientSecretSet; - - final String managedIdentityClientId = validationContext.getProperty(MANAGED_IDENTITY_CLIENT_ID).getValue(); - - if (!onlyOneSet(accountKeySet, sasTokenSet, useManagedIdentitySet, servicePrincipalSet)) { - results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName()) - .valid(false) - .explanation("one and only one authentication method of [Account Key, SAS Token, Managed Identity, Service Principal] should be used") - .build()); - } else { - if (servicePrincipalSet) { - final String template = "'%s' must be set when Service Principal authentication is being configured"; - if (!servicePrincipalTenantIdSet) { - results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName()) - .valid(false) - .explanation(String.format(template, SERVICE_PRINCIPAL_TENANT_ID.getDisplayName())) - .build()); - } - if (!servicePrincipalClientIdSet) { - results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName()) - .valid(false) - .explanation(String.format(template, SERVICE_PRINCIPAL_CLIENT_ID.getDisplayName())) - .build()); - } - if (!servicePrincipalClientSecretSet) { - results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName()) - .valid(false) - .explanation(String.format(template, SERVICE_PRINCIPAL_CLIENT_SECRET.getDisplayName())) - .build()); - } + public void migrateProperties(PropertyConfiguration config) { + if (!config.hasProperty(CREDENTIALS_TYPE)) { + final String propNameUseManagedIdentity = "storage-use-managed-identity"; + + if (config.isPropertySet(ACCOUNT_KEY)) { + config.setProperty(CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY.getValue()); + } else if (config.isPropertySet(SAS_TOKEN)) { + config.setProperty(CREDENTIALS_TYPE, AzureStorageCredentialsType.SAS_TOKEN.getValue()); + } else if (config.isPropertySet(SERVICE_PRINCIPAL_TENANT_ID)) { + config.setProperty(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL.getValue()); + } else { + config.getPropertyValue(propNameUseManagedIdentity).ifPresent(value -> { + if ("true".equals(value)) { + config.setProperty(CREDENTIALS_TYPE, AzureStorageCredentialsType.MANAGED_IDENTITY.getValue()); + } + }); } - if (!useManagedIdentitySet && StringUtils.isNotEmpty(managedIdentityClientId)) { - results.add(new ValidationResult.Builder().subject(this.getClass().getSimpleName()) - .valid(false) - .explanation(String.format("'%s' can only be configured when '%s' is set to true", MANAGED_IDENTITY_CLIENT_ID.getDisplayName(), USE_MANAGED_IDENTITY.getDisplayName())) - .build()); - } + config.removeProperty(propNameUseManagedIdentity); } - - return results; - } - - private boolean onlyOneSet(Boolean... checks) { - long nrOfSet = Arrays.stream(checks) - .filter(check -> check) - .count(); - - return nrOfSet == 1; } @OnEnabled @@ -178,10 +130,11 @@ public ADLSCredentialsDetails getCredentialsDetails(Map attribut ADLSCredentialsDetails.Builder credentialsBuilder = ADLSCredentialsDetails.Builder.newBuilder(); setValue(credentialsBuilder, ACCOUNT_NAME, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setAccountName, attributes); - setValue(credentialsBuilder, AzureStorageUtils.ACCOUNT_KEY, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setAccountKey, attributes); - setValue(credentialsBuilder, AzureStorageUtils.PROP_SAS_TOKEN, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setSasToken, attributes); + setValue(credentialsBuilder, ACCOUNT_KEY, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setAccountKey, attributes); + setValue(credentialsBuilder, SAS_TOKEN, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setSasToken, attributes); setValue(credentialsBuilder, ENDPOINT_SUFFIX, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setEndpointSuffix, attributes); - setValue(credentialsBuilder, USE_MANAGED_IDENTITY, PropertyValue::asBoolean, ADLSCredentialsDetails.Builder::setUseManagedIdentity, attributes); + setValue(credentialsBuilder, CREDENTIALS_TYPE, property -> property.asAllowableValue(AzureStorageCredentialsType.class) == AzureStorageCredentialsType.MANAGED_IDENTITY, + ADLSCredentialsDetails.Builder::setUseManagedIdentity, attributes); setValue(credentialsBuilder, MANAGED_IDENTITY_CLIENT_ID, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setManagedIdentityClientId, attributes); setValue(credentialsBuilder, SERVICE_PRINCIPAL_TENANT_ID, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setServicePrincipalTenantId, attributes); setValue(credentialsBuilder, SERVICE_PRINCIPAL_CLIENT_ID, PropertyValue::getValue, ADLSCredentialsDetails.Builder::setServicePrincipalClientId, attributes); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java index 79278dc6c02df..f2503413aa4b2 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsControllerService_v12.java @@ -23,15 +23,21 @@ import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.controller.AbstractControllerService; import org.apache.nifi.controller.ConfigurationContext; -import org.apache.nifi.expression.ExpressionLanguageScope; import org.apache.nifi.processors.azure.AzureServiceEndpoints; import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.ACCOUNT_KEY; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.ACCOUNT_NAME; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.CREDENTIALS_TYPE; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SAS_TOKEN; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_SECRET; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID; + /** * Provides credentials details for Azure Storage processors * @@ -41,81 +47,17 @@ @CapabilityDescription("Provides credentials for Azure Storage processors using Azure Storage client library v12.") public class AzureStorageCredentialsControllerService_v12 extends AbstractControllerService implements AzureStorageCredentialsService_v12 { - public static final PropertyDescriptor ACCOUNT_NAME = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.ACCOUNT_NAME) - .description(AzureStorageUtils.ACCOUNT_NAME_BASE_DESCRIPTION) - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .build(); - public static final PropertyDescriptor ENDPOINT_SUFFIX = new PropertyDescriptor.Builder() .fromPropertyDescriptor(AzureStorageUtils.ENDPOINT_SUFFIX) - .displayName("Endpoint Suffix") - .description("Storage accounts in public Azure always use a common FQDN suffix. " + - "Override this endpoint suffix with a different suffix in certain circumstances (like Azure Stack or non-public Azure regions).") - .required(true) .defaultValue(AzureServiceEndpoints.DEFAULT_BLOB_ENDPOINT_SUFFIX) - .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .build(); - - public static final PropertyDescriptor CREDENTIALS_TYPE = new PropertyDescriptor.Builder() - .name("credentials-type") - .displayName("Credentials Type") - .description("Credentials type to be used for authenticating to Azure") - .required(true) - .allowableValues(AzureStorageCredentialsType.ACCOUNT_KEY.getAllowableValue(), - AzureStorageCredentialsType.SAS_TOKEN.getAllowableValue(), - AzureStorageCredentialsType.MANAGED_IDENTITY.getAllowableValue(), - AzureStorageCredentialsType.SERVICE_PRINCIPAL.getAllowableValue()) - .defaultValue(AzureStorageCredentialsType.SAS_TOKEN.name()) - .build(); - - public static final PropertyDescriptor ACCOUNT_KEY = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.ACCOUNT_KEY) - .displayName("Account Key") - .description(AzureStorageUtils.ACCOUNT_KEY_BASE_DESCRIPTION) - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY.getAllowableValue()) - .build(); - - public static final PropertyDescriptor SAS_TOKEN = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.PROP_SAS_TOKEN) - .description(AzureStorageUtils.SAS_TOKEN_BASE_DESCRIPTION) - .required(true) - .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SAS_TOKEN.getAllowableValue()) - .build(); - - public static final PropertyDescriptor MANAGED_IDENTITY_CLIENT_ID = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.MANAGED_IDENTITY.getAllowableValue()) - .build(); - - public static final PropertyDescriptor SERVICE_PRINCIPAL_TENANT_ID = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID) - .required(true) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL.getAllowableValue()) - .build(); - - public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_ID = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID) - .required(true) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL.getAllowableValue()) - .build(); - - public static final PropertyDescriptor SERVICE_PRINCIPAL_CLIENT_SECRET = new PropertyDescriptor.Builder() - .fromPropertyDescriptor(AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_SECRET) - .required(true) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL.getAllowableValue()) .build(); public static final PropertyDescriptor PROXY_CONFIGURATION_SERVICE = new PropertyDescriptor.Builder() .fromPropertyDescriptor(AzureStorageUtils.PROXY_CONFIGURATION_SERVICE) - .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL.getAllowableValue(), AzureStorageCredentialsType.MANAGED_IDENTITY.getAllowableValue()) + .dependsOn(CREDENTIALS_TYPE, AzureStorageCredentialsType.SERVICE_PRINCIPAL, AzureStorageCredentialsType.MANAGED_IDENTITY) .build(); - private static final List PROPERTIES = Collections.unmodifiableList(Arrays.asList( + private static final List PROPERTIES = List.of( ACCOUNT_NAME, ENDPOINT_SUFFIX, CREDENTIALS_TYPE, @@ -126,7 +68,7 @@ public class AzureStorageCredentialsControllerService_v12 extends AbstractContro SERVICE_PRINCIPAL_CLIENT_ID, SERVICE_PRINCIPAL_CLIENT_SECRET, PROXY_CONFIGURATION_SERVICE - )); + ); private ConfigurationContext context; @@ -144,7 +86,7 @@ public void onEnabled(ConfigurationContext context) { public AzureStorageCredentialsDetails_v12 getCredentialsDetails(Map attributes) { String accountName = context.getProperty(ACCOUNT_NAME).getValue(); String endpointSuffix = context.getProperty(ENDPOINT_SUFFIX).getValue(); - AzureStorageCredentialsType credentialsType = AzureStorageCredentialsType.valueOf(context.getProperty(CREDENTIALS_TYPE).getValue()); + AzureStorageCredentialsType credentialsType = context.getProperty(CREDENTIALS_TYPE).asAllowableValue(AzureStorageCredentialsType.class); ProxyOptions proxyOptions = AzureStorageUtils.getProxyOptions(context); switch (credentialsType) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubComponent.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubComponent.java index 11a51b7783e37..613a757b4472a 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubComponent.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubComponent.java @@ -31,15 +31,14 @@ public interface AzureEventHubComponent { .displayName("Transport Type") .description("Advanced Message Queuing Protocol Transport Type for communication with Azure Event Hubs") .allowableValues(AzureEventHubTransportType.class) - .defaultValue(AzureEventHubTransportType.AMQP.getValue()) + .defaultValue(AzureEventHubTransportType.AMQP) .required(true) .addValidator(StandardValidators.NON_BLANK_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.NONE) .build(); ProxySpec[] PROXY_SPECS = {ProxySpec.HTTP, ProxySpec.HTTP_AUTH}; - PropertyDescriptor PROXY_CONFIGURATION_SERVICE - = new PropertyDescriptor.Builder() + PropertyDescriptor PROXY_CONFIGURATION_SERVICE = new PropertyDescriptor.Builder() .fromPropertyDescriptor(ProxyConfiguration.createProxyConfigPropertyDescriptor(false, PROXY_SPECS)) - .dependsOn(TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()) + .dependsOn(TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS) .build(); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubTransportType.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubTransportType.java index 7d5ec13352a8e..c4748a497c838 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubTransportType.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/java/org/apache/nifi/shared/azure/eventhubs/AzureEventHubTransportType.java @@ -16,23 +16,24 @@ */ package org.apache.nifi.shared.azure.eventhubs; +import com.azure.core.amqp.AmqpTransportType; import org.apache.nifi.components.DescribedValue; /** * Azure Event Hubs Transport Type allowable values based on AmqpTransportType values from the Azure SDK */ public enum AzureEventHubTransportType implements DescribedValue { - AMQP("Amqp", "AMQP over TCP on ports 5671 and 5672"), - - AMQP_WEB_SOCKETS("AmqpWebSockets", "AMQP over HTTPS with WebSockets on port 443"); + AMQP("Amqp", "AMQP over TCP on ports 5671 and 5672", AmqpTransportType.AMQP), + AMQP_WEB_SOCKETS("AmqpWebSockets", "AMQP over HTTPS with WebSockets on port 443", AmqpTransportType.AMQP_WEB_SOCKETS); private final String value; - private final String description; + private final AmqpTransportType amqpTransportType; - AzureEventHubTransportType(final String value, final String description) { + AzureEventHubTransportType(final String value, final String description, final AmqpTransportType amqpTransportType) { this.value = value; this.description = description; + this.amqpTransportType = amqpTransportType; } @Override @@ -49,4 +50,8 @@ public String getDisplayName() { public String getDescription() { return description; } + + public AmqpTransportType asAmqpTransportType() { + return this.amqpTransportType; + } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService index c529f9efd06e9..92f9ddbe5f7aa 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService @@ -17,6 +17,7 @@ org.apache.nifi.services.azure.storage.ADLSCredentialsControllerService org.apache.nifi.services.azure.storage.ADLSCredentialsControllerServiceLookup org.apache.nifi.services.azure.cosmos.document.AzureCosmosDBClientService org.apache.nifi.services.azure.data.explorer.StandardKustoQueryService +org.apache.nifi.services.azure.data.explorer.StandardKustoIngestService org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12 org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerServiceLookup_v12 org.apache.nifi.services.azure.StandardAzureCredentialsControllerService diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor index fc0a63ee91789..f7ef2f3707057 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/main/resources/META-INF/services/org.apache.nifi.processor.Processor @@ -21,6 +21,7 @@ org.apache.nifi.processors.azure.storage.FetchAzureDataLakeStorage org.apache.nifi.processors.azure.storage.ListAzureDataLakeStorage org.apache.nifi.processors.azure.cosmos.document.PutAzureCosmosDBRecord org.apache.nifi.processors.azure.data.explorer.QueryAzureDataExplorer +org.apache.nifi.processors.azure.data.explorer.PutAzureDataExplorer org.apache.nifi.processors.azure.storage.ListAzureBlobStorage_v12 org.apache.nifi.processors.azure.storage.FetchAzureBlobStorage_v12 org.apache.nifi.processors.azure.storage.PutAzureBlobStorage_v12 diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITAbstractAzureCosmosDBDocument.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITAbstractAzureCosmosDBDocument.java index e2165a2a01470..dc917883b3b76 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITAbstractAzureCosmosDBDocument.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITAbstractAzureCosmosDBDocument.java @@ -59,7 +59,6 @@ public abstract class ITAbstractAzureCosmosDBDocument { protected static CosmosContainer container; static { - CONFIG = new Properties(); assertDoesNotThrow(() -> { final FileInputStream fis = new FileInputStream(CREDENTIALS_FILE); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITPutAzureCosmosDBRecord.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITPutAzureCosmosDBRecord.java index 3b80b87a4e35c..d596fa5ad7a4c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITPutAzureCosmosDBRecord.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/ITPutAzureCosmosDBRecord.java @@ -17,7 +17,6 @@ package org.apache.nifi.processors.azure.cosmos.document; import com.azure.cosmos.models.CosmosQueryRequestOptions; -import com.azure.cosmos.util.CosmosPagedIterable; import com.fasterxml.jackson.databind.JsonNode; import org.apache.nifi.processor.Processor; import org.apache.nifi.reporting.InitializationException; @@ -53,25 +52,21 @@ public void setUp() throws Exception { @AfterEach public void cleanupTestCase() { - try{ + try { clearTestData(); closeClient(); - } catch(Exception e) { + } catch (Exception ignored) { } } + private List getDataFromTestDB() { logger.info("getDataFromTestDB for test result validation"); CosmosQueryRequestOptions queryOptions = new CosmosQueryRequestOptions(); - List results = new ArrayList<>(); - - CosmosPagedIterable response = container.queryItems( - "select * from c order by c._ts", queryOptions, JsonNode.class ); - response.forEach(data -> { - results.add(data); - }); - return results; + return container + .queryItems("select * from c order by c._ts", queryOptions, JsonNode.class) + .stream().toList(); } private MockRecordParser recordReader; @@ -99,32 +94,36 @@ public void testOnTriggerWithNestedRecords() throws InitializationException { final RecordSchema personSchema = new SimpleRecordSchema(personFields); recordReader.addSchemaField("person", RecordFieldType.RECORD); - recordReader.addRecord("1", "A", new MapRecord(personSchema, new HashMap() { + recordReader.addRecord("1", "A", new MapRecord(personSchema, new HashMap() { private static final long serialVersionUID = -3185956498135742190L; + { put("name", "John Doe"); put("age", 48); put("sport", "Soccer"); } })); - recordReader.addRecord("2", "B", new MapRecord(personSchema, new HashMap() { + recordReader.addRecord("2", "B", new MapRecord(personSchema, new HashMap() { private static final long serialVersionUID = 1L; + { put("name", "Jane Doe"); put("age", 47); put("sport", "Tennis"); } })); - recordReader.addRecord("3", "A", new MapRecord(personSchema, new HashMap() { + recordReader.addRecord("3", "A", new MapRecord(personSchema, new HashMap() { private static final long serialVersionUID = -1329194249439570573L; + { put("name", "Sally Doe"); put("age", 47); put("sport", "Curling"); } })); - recordReader.addRecord("4", "C", new MapRecord(personSchema, new HashMap() { + recordReader.addRecord("4", "C", new MapRecord(personSchema, new HashMap() { private static final long serialVersionUID = -1329194249439570574L; + { put("name", "Jimmy Doe"); put("age", 14); @@ -148,10 +147,10 @@ public void testOnTriggerWithFlatRecords() throws InitializationException { recordReader.addSchemaField("sport", RecordFieldType.STRING); recordReader.addRecord("1", "A", "John Doe", 48, "Soccer"); - recordReader.addRecord("2", "B","Jane Doe", 47, "Tennis"); + recordReader.addRecord("2", "B", "Jane Doe", 47, "Tennis"); recordReader.addRecord("3", "B", "Sally Doe", 47, "Curling"); recordReader.addRecord("4", "A", "Jimmy Doe", 14, null); - recordReader.addRecord("5", "C","Pizza Doe", 14, null); + recordReader.addRecord("5", "C", "Pizza Doe", 14, null); runner.enqueue(""); runner.run(); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/MockTestBase.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/MockTestBase.java index c09fdca2f2cbe..8dd66a6393801 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/MockTestBase.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/MockTestBase.java @@ -23,8 +23,6 @@ import org.apache.nifi.services.azure.cosmos.document.AzureCosmosDBClientService; import org.apache.nifi.util.TestRunner; -import java.util.Random; - import static org.mockito.Mockito.mock; public class MockTestBase { @@ -57,11 +55,6 @@ protected void setBasicMockProperties(boolean withConnectionService) throws Init } } - private static Random random = new Random(); - public static int getRandomInt(int min, int max){ - return random.nextInt((max-min)+1) + min; - } - private class MockConnectionService extends AzureCosmosDBClientService { @Override protected void createCosmosClient(final String uri, final String accessKey, final ConsistencyLevel clevel){ diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecordTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecordTest.java index de2d85e2cceed..64e4360dfa2a1 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecordTest.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/cosmos/document/PutAzureCosmosDBRecordTest.java @@ -248,7 +248,7 @@ public void testArrayConversion() throws Exception { List> backendData = processor.getTestResults(); assertEquals(1, backendData.size()); //validate array data - final Map arrayTestResult = backendData.get(0); + final Map arrayTestResult = backendData.getFirst(); Object[] check = (Object []) arrayTestResult.get("arrayTest"); assertArrayEquals(new Object[]{"a", "b", "c"}, check); } @@ -265,7 +265,7 @@ class MockPutAzureCosmosDBRecord extends PutAzureCosmosDBRecord { private final List> mockBackend = new ArrayList<>(); @Override - protected void createCosmosClient(final String uri, final String accessKey, final ConsistencyLevel clevel) { + protected void createCosmosClient(final String uri, final String accessKey, final ConsistencyLevel consistencyLevel) { this.setCosmosClient(mockClient); } @Override diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/PutAzureDataExplorerTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/PutAzureDataExplorerTest.java new file mode 100644 index 0000000000000..b0088582d12c8 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/PutAzureDataExplorerTest.java @@ -0,0 +1,168 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.data.explorer; + +import org.apache.nifi.reporting.InitializationException; +import org.apache.nifi.services.azure.data.explorer.KustoIngestService; +import org.apache.nifi.services.azure.data.explorer.KustoIngestionResult; +import org.apache.nifi.util.TestRunner; +import org.apache.nifi.util.TestRunners; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class PutAzureDataExplorerTest { + + private static final String SERVICE_ID = KustoIngestService.class.getName(); + + private static final String DATABASE_NAME = "records"; + + private static final String TABLE_NAME = "records"; + + private static final String MAPPING_NAME = "records"; + + private static final String DATA_FORMAT = "csv"; + + private static final byte[] EMPTY = new byte[]{}; + + @Mock + private KustoIngestService kustoIngestService; + + @Mock + private Map> queryResult; + + private TestRunner runner; + + @BeforeEach + void setRunner() throws InitializationException { + runner = TestRunners.newTestRunner(PutAzureDataExplorer.class); + runner.setValidateExpressionUsage(false); + when(kustoIngestService.getIdentifier()).thenReturn(SERVICE_ID); + runner.addControllerService(SERVICE_ID, kustoIngestService); + runner.enableControllerService(kustoIngestService); + queryResult = new HashMap<>(); + List row = new ArrayList<>(); + row.add("test1"); + row.add("test2"); + row.add("test3"); + queryResult.put(0,row); + } + + @Test + void testProperties() { + runner.assertNotValid(); + + runner.setProperty(PutAzureDataExplorer.DATABASE_NAME, DATABASE_NAME); + runner.setProperty(PutAzureDataExplorer.TABLE_NAME, TABLE_NAME); + runner.setProperty(PutAzureDataExplorer.MAPPING_NAME, MAPPING_NAME); + runner.setProperty(PutAzureDataExplorer.DATA_FORMAT, DATA_FORMAT); + runner.setProperty(PutAzureDataExplorer.INGEST_SERVICE, SERVICE_ID); + + runner.assertValid(); + } + + @Test + void testRunSuccessQueuedIngestion() { + runner.setProperty(PutAzureDataExplorer.DATABASE_NAME, DATABASE_NAME); + runner.setProperty(PutAzureDataExplorer.TABLE_NAME, TABLE_NAME); + runner.setProperty(PutAzureDataExplorer.MAPPING_NAME, MAPPING_NAME); + runner.setProperty(PutAzureDataExplorer.DATA_FORMAT, DATA_FORMAT); + runner.setProperty(PutAzureDataExplorer.INGEST_SERVICE, SERVICE_ID); + + runner.enqueue(EMPTY); + + when(kustoIngestService.isTableReadable(Mockito.anyString(), Mockito.anyString())).thenReturn(true); + final KustoIngestionResult kustoIngestionResult = KustoIngestionResult.SUCCEEDED; + when(kustoIngestService.ingestData(Mockito.any())).thenReturn(kustoIngestionResult); + + runner.run(); + + runner.assertAllFlowFilesTransferred(PutAzureDataExplorer.SUCCESS); + } + + @Test + void testRunFailureQueuedIngestion() { + runner.setProperty(PutAzureDataExplorer.DATABASE_NAME, DATABASE_NAME); + runner.setProperty(PutAzureDataExplorer.TABLE_NAME, TABLE_NAME); + runner.setProperty(PutAzureDataExplorer.MAPPING_NAME, MAPPING_NAME); + runner.setProperty(PutAzureDataExplorer.DATA_FORMAT, DATA_FORMAT); + runner.setProperty(PutAzureDataExplorer.INGEST_SERVICE, SERVICE_ID); + + runner.enqueue(EMPTY); + + when(kustoIngestService.isTableReadable(Mockito.anyString(), Mockito.anyString())).thenReturn(true); + final KustoIngestionResult kustoIngestionResult = KustoIngestionResult.FAILED; + when(kustoIngestService.ingestData(Mockito.any())).thenReturn(kustoIngestionResult); + + runner.run(); + + runner.assertAllFlowFilesTransferred(PutAzureDataExplorer.FAILURE); + } + + @Test + void testRunSuccessStreamingIngestion() { + runner.setProperty(PutAzureDataExplorer.DATABASE_NAME, DATABASE_NAME); + runner.setProperty(PutAzureDataExplorer.TABLE_NAME, TABLE_NAME); + runner.setProperty(PutAzureDataExplorer.MAPPING_NAME, MAPPING_NAME); + runner.setProperty(PutAzureDataExplorer.DATA_FORMAT, DATA_FORMAT); + runner.setProperty(PutAzureDataExplorer.INGEST_SERVICE, SERVICE_ID); + runner.setProperty(PutAzureDataExplorer.STREAMING_ENABLED, Boolean.TRUE.toString()); + + runner.enqueue(EMPTY); + + when(kustoIngestService.isStreamingPolicyEnabled(Mockito.anyString())).thenReturn(true); + when(kustoIngestService.isTableReadable(Mockito.anyString(), Mockito.anyString())).thenReturn(true); + final KustoIngestionResult kustoIngestionResult = KustoIngestionResult.SUCCEEDED; + when(kustoIngestService.ingestData(Mockito.any())).thenReturn(kustoIngestionResult); + + runner.run(); + + runner.assertAllFlowFilesTransferred(PutAzureDataExplorer.SUCCESS); + } + + @Test + void testRunFailureStreamingIngestion() { + runner.setProperty(PutAzureDataExplorer.DATABASE_NAME, DATABASE_NAME); + runner.setProperty(PutAzureDataExplorer.TABLE_NAME, TABLE_NAME); + runner.setProperty(PutAzureDataExplorer.MAPPING_NAME, MAPPING_NAME); + runner.setProperty(PutAzureDataExplorer.DATA_FORMAT, DATA_FORMAT); + runner.setProperty(PutAzureDataExplorer.INGEST_SERVICE, SERVICE_ID); + runner.setProperty(PutAzureDataExplorer.STREAMING_ENABLED, Boolean.TRUE.toString()); + + runner.enqueue(EMPTY); + + when(kustoIngestService.isStreamingPolicyEnabled(Mockito.anyString())).thenReturn(true); + when(kustoIngestService.isTableReadable(Mockito.anyString(), Mockito.anyString())).thenReturn(true); + final KustoIngestionResult kustoIngestionResult = KustoIngestionResult.FAILED; + when(kustoIngestService.ingestData(Mockito.any())).thenReturn(kustoIngestionResult); + + runner.run(); + + runner.assertAllFlowFilesTransferred(PutAzureDataExplorer.FAILURE); + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorerTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorerTest.java index fd7e702f29f03..11a9c9273a1d0 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorerTest.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/data/explorer/QueryAzureDataExplorerTest.java @@ -89,7 +89,7 @@ void testRunFailure() { runner.assertAllFlowFilesTransferred(QueryAzureDataExplorer.FAILURE); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(QueryAzureDataExplorer.FAILURE).iterator().next(); + final MockFlowFile flowFile = runner.getFlowFilesForRelationship(QueryAzureDataExplorer.FAILURE).getFirst(); flowFile.assertAttributeEquals(QueryAzureDataExplorer.QUERY_ERROR_MESSAGE, ERROR_MESSAGE); flowFile.assertAttributeEquals(QueryAzureDataExplorer.QUERY_EXECUTED, QUERY); } @@ -110,7 +110,7 @@ void testRunSuccess() { runner.assertAllFlowFilesTransferred(QueryAzureDataExplorer.SUCCESS); - final MockFlowFile flowFile = runner.getFlowFilesForRelationship(QueryAzureDataExplorer.SUCCESS).iterator().next(); + final MockFlowFile flowFile = runner.getFlowFilesForRelationship(QueryAzureDataExplorer.SUCCESS).getFirst(); flowFile.assertAttributeEquals(QueryAzureDataExplorer.QUERY_EXECUTED, QUERY); flowFile.assertAttributeEquals(CoreAttributes.MIME_TYPE.key(), QueryAzureDataExplorer.APPLICATION_JSON); flowFile.assertContentEquals(EMPTY_ARRAY); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHubTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHubTest.java index cb0e2331fa267..0a8142cfd905c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHubTest.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/GetAzureEventHubTest.java @@ -85,7 +85,7 @@ public void testProperties() throws InitializationException { testRunner.assertValid(); testRunner.setProperty(GetAzureEventHub.RECEIVER_FETCH_TIMEOUT, "10000"); testRunner.assertValid(); - testRunner.setProperty(GetAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()); + testRunner.setProperty(GetAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS); testRunner.assertValid(); configureProxyControllerService(); testRunner.assertValid(); @@ -132,7 +132,7 @@ public void testRunEventsReceived() { testRunner.run(); testRunner.assertAllFlowFilesTransferred(GetAzureEventHub.REL_SUCCESS, 1); - final MockFlowFile flowFile = testRunner.getFlowFilesForRelationship(GetAzureEventHub.REL_SUCCESS).get(0); + final MockFlowFile flowFile = testRunner.getFlowFilesForRelationship(GetAzureEventHub.REL_SUCCESS).getFirst(); flowFile.assertContentEquals(CONTENT); flowFile.assertAttributeEquals("eventhub.enqueued.timestamp", ENQUEUED_TIME.toString()); flowFile.assertAttributeEquals("eventhub.offset", Long.toString(OFFSET)); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHubTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHubTest.java index cb3c18ef656fa..459c303e6903a 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHubTest.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/PutAzureEventHubTest.java @@ -79,7 +79,7 @@ public void testProperties() throws InitializationException { testRunner.assertNotValid(); testRunner.setProperty(PutAzureEventHub.POLICY_PRIMARY_KEY, POLICY_KEY); testRunner.assertValid(); - testRunner.setProperty(PutAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()); + testRunner.setProperty(PutAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS); testRunner.assertValid(); configureProxyControllerService(); testRunner.assertValid(); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/TestConsumeAzureEventHub.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/TestConsumeAzureEventHub.java index af88d19d58307..3ab13ee1d4423 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/TestConsumeAzureEventHub.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/TestConsumeAzureEventHub.java @@ -24,6 +24,7 @@ import com.azure.messaging.eventhubs.models.PartitionContext; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.processor.ProcessContext; +import org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStrategy; import org.apache.nifi.provenance.ProvenanceEventRecord; import org.apache.nifi.provenance.ProvenanceEventType; import org.apache.nifi.proxy.ProxyConfiguration; @@ -153,7 +154,7 @@ public void testProcessorConfigValidityWithManagedIdentityFlag() throws Initiali testRunner.assertNotValid(); testRunner.setProperty(ConsumeAzureEventHub.USE_MANAGED_IDENTITY,"true"); testRunner.assertValid(); - testRunner.setProperty(ConsumeAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()); + testRunner.setProperty(ConsumeAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS); testRunner.assertValid(); configureProxyControllerService(); testRunner.assertValid(); @@ -199,7 +200,7 @@ public void testProcessorConfigValidityWithTokenSet() throws InitializationExcep testRunner.setProperty(ConsumeAzureEventHub.STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_NAME); testRunner.setProperty(ConsumeAzureEventHub.STORAGE_SAS_TOKEN, STORAGE_TOKEN); testRunner.assertValid(); - testRunner.setProperty(ConsumeAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()); + testRunner.setProperty(ConsumeAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS); testRunner.assertValid(); configureProxyControllerService(); testRunner.assertValid(); @@ -217,12 +218,25 @@ public void testProcessorConfigValidityWithStorageKeySet() throws Initialization testRunner.setProperty(ConsumeAzureEventHub.STORAGE_ACCOUNT_NAME, STORAGE_ACCOUNT_NAME); testRunner.setProperty(ConsumeAzureEventHub.STORAGE_ACCOUNT_KEY, STORAGE_ACCOUNT_KEY); testRunner.assertValid(); - testRunner.setProperty(ConsumeAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()); + testRunner.setProperty(ConsumeAzureEventHub.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS); testRunner.assertValid(); configureProxyControllerService(); testRunner.assertValid(); } + @Test + public void testProcessorConfigValidityWithComponentStateCheckpointStrategy() throws InitializationException { + testRunner.setProperty(ConsumeAzureEventHub.EVENT_HUB_NAME, EVENT_HUB_NAME); + testRunner.assertNotValid(); + testRunner.setProperty(ConsumeAzureEventHub.NAMESPACE, EVENT_HUB_NAMESPACE); + testRunner.assertNotValid(); + testRunner.setProperty(ConsumeAzureEventHub.ACCESS_POLICY_NAME, POLICY_NAME); + testRunner.setProperty(ConsumeAzureEventHub.POLICY_PRIMARY_KEY, POLICY_KEY); + testRunner.assertNotValid(); + testRunner.setProperty(ConsumeAzureEventHub.CHECKPOINT_STRATEGY, CheckpointStrategy.COMPONENT_STATE.getValue()); + testRunner.assertValid(); + } + @Test public void testReceiveOne() { setProperties(); @@ -234,13 +248,13 @@ public void testReceiveOne() { final List flowFiles = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_SUCCESS); assertEquals(1, flowFiles.size()); - final MockFlowFile flowFile = flowFiles.get(0); + final MockFlowFile flowFile = flowFiles.getFirst(); flowFile.assertContentEquals(FIRST_CONTENT); assertEventHubAttributesFound(flowFile); final List provenanceEvents = testRunner.getProvenanceEvents(); assertEquals(1, provenanceEvents.size()); - final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.get(0); + final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.getFirst(); assertEquals(ProvenanceEventType.RECEIVE, provenanceEvent1.getEventType()); assertEquals(EXPECTED_TRANSIT_URI, provenanceEvent1.getTransitUri()); } @@ -280,13 +294,13 @@ public void testReceiveRecords() throws Exception { final List flowFiles = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_SUCCESS); assertEquals(1, flowFiles.size()); - final MockFlowFile ff1 = flowFiles.get(0); + final MockFlowFile ff1 = flowFiles.getFirst(); ff1.assertContentEquals(FIRST_CONTENT + SECOND_CONTENT); assertEventHubAttributesFound(ff1); final List provenanceEvents = testRunner.getProvenanceEvents(); assertEquals(1, provenanceEvents.size()); - final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.get(0); + final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.getFirst(); assertEquals(ProvenanceEventType.RECEIVE, provenanceEvent1.getEventType()); assertEquals(EXPECTED_TRANSIT_URI, provenanceEvent1.getTransitUri()); } @@ -306,20 +320,20 @@ public void testReceiveRecordReaderFailure() throws Exception { final List flowFiles = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_SUCCESS); assertEquals(1, flowFiles.size()); - final MockFlowFile ff1 = flowFiles.get(0); + final MockFlowFile ff1 = flowFiles.getFirst(); ff1.assertContentEquals(FIRST_CONTENT + SECOND_CONTENT + FOURTH_CONTENT); assertEventHubAttributesFound(ff1); final List failedFFs = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_PARSE_FAILURE); assertEquals(1, failedFFs.size()); - final MockFlowFile failed1 = failedFFs.get(0); + final MockFlowFile failed1 = failedFFs.getFirst(); failed1.assertContentEquals(THIRD_CONTENT); assertEventHubAttributesFound(failed1); final List provenanceEvents = testRunner.getProvenanceEvents(); assertEquals(2, provenanceEvents.size()); - final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.get(0); + final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.getFirst(); assertEquals(ProvenanceEventType.RECEIVE, provenanceEvent1.getEventType()); assertEquals(EXPECTED_TRANSIT_URI, provenanceEvent1.getTransitUri()); @@ -346,14 +360,14 @@ public void testReceiveAllRecordFailure() throws Exception { final List failedFFs = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_PARSE_FAILURE); assertEquals(1, failedFFs.size()); - final MockFlowFile failed1 = failedFFs.get(0); + final MockFlowFile failed1 = failedFFs.getFirst(); failed1.assertContentEquals(FIRST_CONTENT); assertEventHubAttributesFound(failed1); final List provenanceEvents = testRunner.getProvenanceEvents(); assertEquals(1, provenanceEvents.size()); - final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.get(0); + final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.getFirst(); assertEquals(ProvenanceEventType.RECEIVE, provenanceEvent1.getEventType()); assertEquals(EXPECTED_TRANSIT_URI, provenanceEvent1.getTransitUri()); } @@ -373,20 +387,20 @@ public void testReceiveRecordWriterFailure() throws Exception { final List flowFiles = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_SUCCESS); assertEquals(1, flowFiles.size()); - final MockFlowFile ff1 = flowFiles.get(0); + final MockFlowFile ff1 = flowFiles.getFirst(); ff1.assertContentEquals(FIRST_CONTENT + THIRD_CONTENT + FOURTH_CONTENT); assertEventHubAttributesFound(ff1); final List failedFFs = testRunner.getFlowFilesForRelationship(ConsumeAzureEventHub.REL_PARSE_FAILURE); assertEquals(1, failedFFs.size()); - final MockFlowFile failed1 = failedFFs.get(0); + final MockFlowFile failed1 = failedFFs.getFirst(); failed1.assertContentEquals(SECOND_CONTENT); assertEventHubAttributesFound(failed1); final List provenanceEvents = testRunner.getProvenanceEvents(); assertEquals(2, provenanceEvents.size()); - final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.get(0); + final ProvenanceEventRecord provenanceEvent1 = provenanceEvents.getFirst(); assertEquals(ProvenanceEventType.RECEIVE, provenanceEvent1.getEventType()); assertEquals(EXPECTED_TRANSIT_URI, provenanceEvent1.getTransitUri()); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/AbstractCheckpointStoreTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/AbstractCheckpointStoreTest.java new file mode 100644 index 0000000000000..97eef55ef40ca --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/AbstractCheckpointStoreTest.java @@ -0,0 +1,220 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.messaging.eventhubs.models.Checkpoint; +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.junit.jupiter.api.BeforeEach; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +abstract class AbstractCheckpointStoreTest { + + static final String EVENT_HUB_NAMESPACE = "my-event-hub-namespace"; + static final String EVENT_HUB_NAME = "my-event-hub-name"; + static final String CONSUMER_GROUP = "my-consumer-group"; + + static final String PARTITION_ID_1 = "1"; + static final String PARTITION_ID_2 = "2"; + + static final String CLIENT_ID_1 = "client-id-1"; + static final String CLIENT_ID_2 = "client-id-2"; + + static final Long LAST_MODIFIED_TIME = 1234567890L; + static final String ETAG = "my-etag"; + + static final Long OFFSET = 10L; + static final Long SEQUENCE_NUMBER = 1L; + + PartitionOwnership partitionOwnership1; + PartitionOwnership partitionOwnership2; + + Checkpoint checkpoint1; + Checkpoint checkpoint2; + + @BeforeEach + void initTestData() { + partitionOwnership1 = createPartitionOwnership(PARTITION_ID_1, CLIENT_ID_1); + partitionOwnership2 = createPartitionOwnership(PARTITION_ID_2, CLIENT_ID_2); + + checkpoint1 = createCheckpoint(PARTITION_ID_1, OFFSET, SEQUENCE_NUMBER); + checkpoint2 = createCheckpoint(PARTITION_ID_2, OFFSET, SEQUENCE_NUMBER); + } + + PartitionOwnership createPartitionOwnership(String partitionId, String ownerId) { + return createPartitionOwnership( + EVENT_HUB_NAMESPACE, + EVENT_HUB_NAME, + CONSUMER_GROUP, + partitionId, + ownerId + ); + } + + PartitionOwnership createPartitionOwnership( + String fullyQualifiedNamespace, + String eventHubName, + String consumerGroup, + String partitionId, + String ownerId) { + return new TestablePartitionOwnership() + .setFullyQualifiedNamespace(fullyQualifiedNamespace) + .setEventHubName(eventHubName) + .setConsumerGroup(consumerGroup) + .setPartitionId(partitionId) + .setOwnerId(ownerId) + .setLastModifiedTime(null) + .setETag(null); + } + + Checkpoint createCheckpoint(String partitionId, Long offset, Long sequenceNumber) { + return createCheckpoint( + EVENT_HUB_NAMESPACE, + EVENT_HUB_NAME, + CONSUMER_GROUP, + partitionId, + offset, + sequenceNumber + ); + } + + Checkpoint createCheckpoint( + String fullyQualifiedNamespace, + String eventHubName, + String consumerGroup, + String partitionId, + Long offset, + Long sequenceNumber) { + return new TestableCheckpoint() + .setFullyQualifiedNamespace(fullyQualifiedNamespace) + .setEventHubName(eventHubName) + .setConsumerGroup(consumerGroup) + .setPartitionId(partitionId) + .setOffset(offset) + .setSequenceNumber(sequenceNumber); + } + + PartitionOwnership copy(PartitionOwnership original) { + return convertToTestable(original); + } + + Checkpoint copy(Checkpoint original) { + return convertToTestable(original); + } + + PartitionOwnership convertToTestable(PartitionOwnership original) { + return new TestablePartitionOwnership() + .setFullyQualifiedNamespace(original.getFullyQualifiedNamespace()) + .setEventHubName(original.getEventHubName()) + .setConsumerGroup(original.getConsumerGroup()) + .setPartitionId(original.getPartitionId()) + .setOwnerId(original.getOwnerId()) + .setLastModifiedTime(original.getLastModifiedTime()) + .setETag(original.getETag()); + } + + Checkpoint convertToTestable(Checkpoint original) { + return new TestableCheckpoint() + .setFullyQualifiedNamespace(original.getFullyQualifiedNamespace()) + .setEventHubName(original.getEventHubName()) + .setConsumerGroup(original.getConsumerGroup()) + .setPartitionId(original.getPartitionId()) + .setOffset(original.getOffset()) + .setSequenceNumber(original.getSequenceNumber()); + } + + List convertToTestablePartitionOwnerships(List partitionOwnerships) { + return partitionOwnerships.stream() + .map(this::convertToTestable) + .collect(Collectors.toList()); + } + + List convertToTestableCheckpoints(List checkpoints) { + return checkpoints.stream() + .map(this::convertToTestable) + .collect(Collectors.toList()); + } + + static class TestablePartitionOwnership extends PartitionOwnership { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TestablePartitionOwnership that = (TestablePartitionOwnership) o; + return Objects.equals(getFullyQualifiedNamespace(), that.getFullyQualifiedNamespace()) + && Objects.equals(getEventHubName(), that.getEventHubName()) + && Objects.equals(getConsumerGroup(), that.getConsumerGroup()) + && Objects.equals(getPartitionId(), that.getPartitionId()) + && Objects.equals(getOwnerId(), that.getOwnerId()) + && Objects.equals(getLastModifiedTime(), that.getLastModifiedTime()) + && Objects.equals(getETag(), that.getETag()); + } + + @Override + public int hashCode() { + return Objects.hash( + getFullyQualifiedNamespace(), + getEventHubName(), + getConsumerGroup(), + getPartitionId(), + getOwnerId(), + getLastModifiedTime(), + getETag() + ); + } + } + + static class TestableCheckpoint extends Checkpoint { + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TestableCheckpoint that = (TestableCheckpoint) o; + return Objects.equals(getFullyQualifiedNamespace(), that.getFullyQualifiedNamespace()) + && Objects.equals(getEventHubName(), that.getEventHubName()) + && Objects.equals(getConsumerGroup(), that.getConsumerGroup()) + && Objects.equals(getPartitionId(), that.getPartitionId()) + && Objects.equals(getOffset(), that.getOffset()) + && Objects.equals(getSequenceNumber(), that.getSequenceNumber()); + } + + @Override + public int hashCode() { + return Objects.hash( + getFullyQualifiedNamespace(), + getEventHubName(), + getConsumerGroup(), + getPartitionId(), + getOffset(), + getSequenceNumber() + ); + } + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/AbstractComponentStateCheckpointStoreTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/AbstractComponentStateCheckpointStoreTest.java new file mode 100644 index 0000000000000..9341cca72f520 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/AbstractComponentStateCheckpointStoreTest.java @@ -0,0 +1,72 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.core.util.CoreUtils; +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.apache.nifi.components.state.StateManager; +import org.junit.jupiter.api.BeforeEach; + +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +abstract class AbstractComponentStateCheckpointStoreTest extends AbstractCheckpointStoreTest { + + ComponentStateCheckpointStore checkpointStore; + + @BeforeEach + void initCheckpointStore() { + checkpointStore = new ComponentStateCheckpointStore(CLIENT_ID_1, getStateManager()); + } + + abstract StateManager getStateManager(); + + PartitionOwnership setETagAndLastModified(PartitionOwnership partitionOwnership) { + return partitionOwnership.setETag(CoreUtils.randomUuid().toString()) + .setLastModifiedTime(System.currentTimeMillis() - 1000); + } + + void assertClaimedOwnership(PartitionOwnership requestedOwnership, PartitionOwnership claimedOwnership) { + assertEquals(requestedOwnership.getFullyQualifiedNamespace(), claimedOwnership.getFullyQualifiedNamespace()); + assertEquals(requestedOwnership.getEventHubName(), claimedOwnership.getEventHubName()); + assertEquals(requestedOwnership.getConsumerGroup(), claimedOwnership.getConsumerGroup()); + assertEquals(requestedOwnership.getPartitionId(), claimedOwnership.getPartitionId()); + + assertEquals(requestedOwnership.getOwnerId(), claimedOwnership.getOwnerId()); + + assertNotNull(claimedOwnership.getLastModifiedTime()); + assertThat(claimedOwnership.getLastModifiedTime(), greaterThan(requestedOwnership.getLastModifiedTime() != null ? requestedOwnership.getLastModifiedTime() : 0)); + + assertNotNull(claimedOwnership.getETag()); + assertNotEquals(requestedOwnership.getETag(), claimedOwnership.getETag()); + } + + Map initMap(PartitionOwnership... partitionOwnerships) { + return Stream.of(partitionOwnerships) + .map(this::copy) + .map(this::setETagAndLastModified) + .collect(Collectors.toMap(ComponentStateCheckpointStoreUtils::createOwnershipKey, ComponentStateCheckpointStoreUtils::createOwnershipValue)); + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreConcurrencyTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreConcurrencyTest.java new file mode 100644 index 0000000000000..f10aa761c4fdc --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreConcurrencyTest.java @@ -0,0 +1,182 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.apache.nifi.components.state.Scope; +import org.apache.nifi.components.state.StateManager; +import org.apache.nifi.components.state.StateMap; +import org.apache.nifi.state.MockStateMap; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointValue; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipKey; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ComponentStateCheckpointStoreConcurrencyTest extends AbstractComponentStateCheckpointStoreTest { + + @Mock(strictness = Mock.Strictness.WARN) + private StateManager stateManager; + + @Captor + private ArgumentCaptor> updatedMapCaptor; + + @Override + StateManager getStateManager() { + return stateManager; + } + + @Test + void testConcurrentClaimDifferentOwnerships() throws IOException { + StateMap state1 = new MockStateMap(initMap(), 1); + StateMap state2 = new MockStateMap(initMap(partitionOwnership1), 2); + + when(stateManager.getState(Scope.CLUSTER)) + .thenReturn(state1) + .thenReturn(state2); + + when(stateManager.replace(eq(state1), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + when(stateManager.replace(eq(state2), anyMap(), eq(Scope.CLUSTER))).thenReturn(true); + + List requestedOwnerships = Collections.singletonList(partitionOwnership2); + + List claimedOwnerships = new ArrayList<>(); + checkpointStore.claimOwnership(requestedOwnerships).subscribe(claimedOwnerships::add); + + assertThat(claimedOwnerships, hasSize(1)); + PartitionOwnership claimedOwnership = claimedOwnerships.get(0); + assertClaimedOwnership(partitionOwnership2, claimedOwnership); + + verify(stateManager, times(2)).getState(eq(Scope.CLUSTER)); + verify(stateManager, times(2)).replace(any(StateMap.class), updatedMapCaptor.capture(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + + Map updatedMap1 = updatedMapCaptor.getAllValues().get(0); + assertThat(updatedMap1.size(), is(equalTo(1))); + assertThat(updatedMap1, hasEntry(equalTo(createOwnershipKey(partitionOwnership2)), startsWith(partitionOwnership2.getOwnerId()))); + + Map updatedMap2 = updatedMapCaptor.getAllValues().get(1); + assertThat(updatedMap2.size(), is(equalTo(2))); + assertThat(updatedMap2, hasEntry(equalTo(createOwnershipKey(partitionOwnership1)), startsWith(partitionOwnership1.getOwnerId()))); + assertThat(updatedMap2, hasEntry(equalTo(createOwnershipKey(partitionOwnership2)), startsWith(partitionOwnership2.getOwnerId()))); + } + + @Test + void testConcurrentClaimSameOwnership() throws IOException { + StateMap state1 = new MockStateMap(initMap(), 1); + StateMap state2 = new MockStateMap(initMap(partitionOwnership1), 2); + + when(stateManager.getState(Scope.CLUSTER)) + .thenReturn(state1) + .thenReturn(state2); + + when(stateManager.replace(eq(state1), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + + List requestedOwnerships = Collections.singletonList(partitionOwnership1); + + List claimedOwnerships = new ArrayList<>(); + checkpointStore.claimOwnership(requestedOwnerships).subscribe(claimedOwnerships::add); + + assertThat(claimedOwnerships, hasSize(0)); + + verify(stateManager, times(2)).getState(eq(Scope.CLUSTER)); + verify(stateManager, times(1)).replace(any(StateMap.class), updatedMapCaptor.capture(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + + Map updatedMap1 = updatedMapCaptor.getAllValues().get(0); + assertThat(updatedMap1.size(), is(equalTo(1))); + assertThat(updatedMap1, hasEntry(equalTo(createOwnershipKey(partitionOwnership1)), startsWith(partitionOwnership1.getOwnerId()))); + } + + @Test + void testConcurrentUpdateCheckpoint() throws IOException { + StateMap state1 = new MockStateMap(initMap(partitionOwnership1), 1); + StateMap state2 = new MockStateMap(initMap(partitionOwnership1, partitionOwnership2), 2); + + when(stateManager.getState(Scope.CLUSTER)) + .thenReturn(state1) + .thenReturn(state2); + + when(stateManager.replace(eq(state1), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + when(stateManager.replace(eq(state2), anyMap(), eq(Scope.CLUSTER))).thenReturn(true); + + checkpointStore.updateCheckpoint(checkpoint1).subscribe(); + + verify(stateManager, times(2)).getState(eq(Scope.CLUSTER)); + verify(stateManager, times(2)).replace(any(StateMap.class), updatedMapCaptor.capture(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + + Map updatedMap1 = updatedMapCaptor.getAllValues().get(0); + assertThat(updatedMap1.size(), is(equalTo(2))); + assertThat(updatedMap1, hasEntry(equalTo(createOwnershipKey(partitionOwnership1)), startsWith(partitionOwnership1.getOwnerId()))); + assertThat(updatedMap1, hasEntry(createCheckpointKey(checkpoint1), createCheckpointValue(checkpoint1))); + + Map updatedMap2 = updatedMapCaptor.getAllValues().get(1); + assertThat(updatedMap2.size(), is(equalTo(3))); + assertThat(updatedMap2, hasEntry(equalTo(createOwnershipKey(partitionOwnership1)), startsWith(partitionOwnership1.getOwnerId()))); + assertThat(updatedMap2, hasEntry(equalTo(createOwnershipKey(partitionOwnership2)), startsWith(partitionOwnership2.getOwnerId()))); + assertThat(updatedMap1, hasEntry(createCheckpointKey(checkpoint1), createCheckpointValue(checkpoint1))); + } + + @Test + void testConcurrentCleanUp() throws IOException { + StateMap state1 = new MockStateMap(initMap(partitionOwnership1), 1); + StateMap state2 = new MockStateMap(initMap(), 2); + + when(stateManager.getState(Scope.CLUSTER)) + .thenReturn(state1) + .thenReturn(state2); + + when(stateManager.replace(eq(state1), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + + checkpointStore.cleanUp(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2"); + + verify(stateManager, times(2)).getState(eq(Scope.CLUSTER)); + verify(stateManager, times(1)).replace(any(StateMap.class), updatedMapCaptor.capture(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + + Map updatedMap1 = updatedMapCaptor.getAllValues().get(0); + assertTrue(updatedMap1.isEmpty()); + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreFailureTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreFailureTest.java new file mode 100644 index 0000000000000..0812bbf18ea6d --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreFailureTest.java @@ -0,0 +1,255 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import org.apache.nifi.components.state.Scope; +import org.apache.nifi.components.state.StateManager; +import org.apache.nifi.components.state.StateMap; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.ConcurrentStateModificationException; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.StateNotAvailableException; +import org.apache.nifi.state.MockStateMap; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.test.StepVerifier; + +import java.io.IOException; +import java.time.Duration; +import java.util.Collections; +import java.util.HashMap; + +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ComponentStateCheckpointStoreFailureTest extends AbstractComponentStateCheckpointStoreTest { + + @Mock(strictness = Mock.Strictness.WARN) + private StateManager stateManager; + + @Override + StateManager getStateManager() { + return stateManager; + } + + @Test + void testListOwnership_GetState_IOException() throws IOException { + when(stateManager.getState(Scope.CLUSTER)).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.listOwnership(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP)) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager).getState(Scope.CLUSTER); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testListCheckpoints_GetState_IOException() throws IOException { + when(stateManager.getState(Scope.CLUSTER)).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.listCheckpoints(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP)) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager).getState(Scope.CLUSTER); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testClaimOwnership_GetState_IOException() throws IOException { + when(stateManager.getState(Scope.CLUSTER)).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.claimOwnership(Collections.singletonList(partitionOwnership1))) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager, times(1)).getState(Scope.CLUSTER); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testClaimOwnership_ReplaceState_IOException() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.claimOwnership(Collections.singletonList(partitionOwnership1))) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager).getState(Scope.CLUSTER); + verify(stateManager).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testUpdateCheckpoint_GetState_IOException() throws IOException { + when(stateManager.getState(Scope.CLUSTER)).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.updateCheckpoint(checkpoint1)) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager, times(1)).getState(Scope.CLUSTER); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testUpdateCheckpoint_ReplaceState_IOException() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.updateCheckpoint(checkpoint1)) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager, times(1)).getState(Scope.CLUSTER); + verify(stateManager).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testCleanUp_GetState_IOException() throws IOException { + when(stateManager.getState(Scope.CLUSTER)).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.cleanUpMono(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2")) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager).getState(Scope.CLUSTER); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testCleanUp_ReplaceState_IOException() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(initMap(partitionOwnership1)), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenThrow(IOException.class); + + StepVerifier.create(checkpointStore.cleanUpMono(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2")) + .expectError(StateNotAvailableException.class) + .verify(); + + verify(stateManager, times(1)).getState(Scope.CLUSTER); + verify(stateManager).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testClaimOwnership_ReplaceState_ConcurrentStateModificationException_Success() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenReturn(false, false, true); + + StepVerifier.withVirtualTime(() -> checkpointStore.claimOwnership(Collections.singletonList(partitionOwnership1))) + .thenAwait(Duration.ofSeconds(1)) + .expectNextCount(1) + .verifyComplete(); + + verify(stateManager, times(3)).getState(Scope.CLUSTER); + verify(stateManager, times(3)).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testClaimOwnership_ReplaceState_ConcurrentStateModificationException_Failure() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + + StepVerifier.withVirtualTime(() -> checkpointStore.claimOwnership(Collections.singletonList(partitionOwnership1))) + .thenAwait(Duration.ofSeconds(10)) + .expectError(ConcurrentStateModificationException.class) + .verify(); + + verify(stateManager, times(11)).getState(Scope.CLUSTER); + verify(stateManager, times(11)).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testUpdateCheckpoint_ReplaceState_ConcurrentStateModificationException_Success() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenReturn(false, false, true); + + StepVerifier.withVirtualTime(() -> checkpointStore.updateCheckpoint(checkpoint1)) + .thenAwait(Duration.ofSeconds(1)) + .expectNext() + .verifyComplete(); + + verify(stateManager, times(3)).getState(Scope.CLUSTER); + verify(stateManager, times(3)).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testUpdateCheckpoint_ReplaceState_ConcurrentStateModificationException_Failure() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + + StepVerifier.withVirtualTime(() -> checkpointStore.updateCheckpoint(checkpoint1)) + .thenAwait(Duration.ofSeconds(10)) + .expectError(ConcurrentStateModificationException.class) + .verify(); + + verify(stateManager, times(11)).getState(Scope.CLUSTER); + verify(stateManager, times(11)).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testCleanUp_ReplaceState_ConcurrentStateModificationException_Success() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(initMap(partitionOwnership1)), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenReturn(false, false, true); + + StepVerifier.withVirtualTime(() -> checkpointStore.cleanUpMono(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2")) + .thenAwait(Duration.ofSeconds(1)) + .expectNext() + .verifyComplete(); + + verify(stateManager, times(3)).getState(Scope.CLUSTER); + verify(stateManager, times(3)).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + + @Test + void testCleanUp_ReplaceState_ConcurrentStateModificationException_Failure() throws IOException { + StateMap state = new MockStateMap(new HashMap<>(initMap(partitionOwnership1)), 1); + when(stateManager.getState(Scope.CLUSTER)).thenReturn(state); + when(stateManager.replace(eq(state), anyMap(), eq(Scope.CLUSTER))).thenReturn(false); + + StepVerifier.withVirtualTime(() -> checkpointStore.cleanUpMono(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2")) + .thenAwait(Duration.ofSeconds(10)) + .expectError(ConcurrentStateModificationException.class) + .verify(); + + verify(stateManager, times(11)).getState(Scope.CLUSTER); + verify(stateManager, times(11)).replace(eq(state), anyMap(), eq(Scope.CLUSTER)); + verifyNoMoreInteractions(stateManager); + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreTest.java new file mode 100644 index 0000000000000..33e68ed141f66 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreTest.java @@ -0,0 +1,403 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.messaging.eventhubs.models.Checkpoint; +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.apache.nifi.components.state.Scope; +import org.apache.nifi.components.state.StateManager; +import org.apache.nifi.processors.azure.eventhub.checkpoint.exception.ClusterNodeDisconnectedException; +import org.apache.nifi.state.MockStateManager; +import org.apache.nifi.state.MockStateManager.ExecutionMode; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKey.CLIENT_ID; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.CheckpointStoreKey.CLUSTERED; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointValue; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class ComponentStateCheckpointStoreTest extends AbstractComponentStateCheckpointStoreTest { + + private MockStateManager stateManager; + + @Override + StateManager getStateManager() { + stateManager = new MockStateManager(new Object()); + stateManager.setIgnoreAnnotations(true); + return stateManager; + } + + @BeforeEach + void beforeEach() throws IOException { + stateManager.setExecutionMode(ExecutionMode.CLUSTERED); + + addToState(CLIENT_ID.key(), CLIENT_ID_1, Scope.LOCAL); + addToState(CLUSTERED.key(), "true", Scope.LOCAL); + } + + @Test + void testOwnershipStoredInState() throws IOException { + checkpointStore.claimOwnership(Collections.singletonList(partitionOwnership1)).blockLast(); + + String expectedOwnershipKey = "ownership/my-event-hub-namespace/my-event-hub-name/my-consumer-group/1"; + stateManager.assertStateSet(expectedOwnershipKey, Scope.CLUSTER); + + String ownershipValue = stateManager.getState(Scope.CLUSTER).get(expectedOwnershipKey); + assertTrue(ownershipValue.matches("client-id-1/\\d+/.+")); + } + + @Test + void testCheckpointStoredInState() { + checkpointStore.updateCheckpoint(checkpoint1).block(); + + String expectedCheckpointKey = "checkpoint/my-event-hub-namespace/my-event-hub-name/my-consumer-group/1"; + String expectedCheckpointValue = "10/1"; + stateManager.assertStateEquals(expectedCheckpointKey, expectedCheckpointValue, Scope.CLUSTER); + } + + @Test + void testListing() throws IOException { + initStateWithAllItems(); + + testListOwnerships(partitionOwnership1, partitionOwnership2); + testListCheckpoints(checkpoint1, checkpoint2); + } + + @ParameterizedTest + @EnumSource(ExecutionMode.class) + void testCleanUp(ExecutionMode executionMode) throws IOException { + setExecutionMode(executionMode); + + initStateWithAllItems(); + + int expectedBefore = executionMode == ExecutionMode.CLUSTERED ? 10 : 12; + assertEquals(expectedBefore, stateManager.getState(Scope.CLUSTER).toMap().size()); + + checkpointStore.cleanUp(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP); + + int expectedAfter = executionMode == ExecutionMode.CLUSTERED ? 4 : 6; + assertEquals(expectedAfter, stateManager.getState(Scope.CLUSTER).toMap().size()); + + testListOwnerships(partitionOwnership1, partitionOwnership2); + testListCheckpoints(checkpoint1, checkpoint2); + + assertLocalScope(executionMode); + } + + @ParameterizedTest + @EnumSource(ExecutionMode.class) + void testClaimOwnership(ExecutionMode executionMode) throws IOException { + setExecutionMode(executionMode); + + addToState(partitionOwnership1); + + addToState(checkpoint1); + + List requestedOwnerships = Collections.singletonList(partitionOwnership2); + + List claimedOwnerships = checkpointStore.claimOwnership(requestedOwnerships).collectList().block(); + + assertNotNull(claimedOwnerships); + assertEquals(1, claimedOwnerships.size()); + + PartitionOwnership claimedOwnership = claimedOwnerships.get(0); + assertClaimedOwnership(partitionOwnership2, claimedOwnership); + + assertStoredOwnerships(partitionOwnership1, convertToTestable(claimedOwnership)); + assertStoredCheckpoints(checkpoint1); + + assertLocalScope(executionMode); + } + + @Test + void testRenewOwnership() throws IOException { + addToState(partitionOwnership1); + addToState(partitionOwnership2); + + addToState(checkpoint1); + addToState(checkpoint2); + + List requestedOwnerships = Collections.singletonList(partitionOwnership2); + + List claimedOwnerships = checkpointStore.claimOwnership(requestedOwnerships).collectList().block(); + + assertNotNull(claimedOwnerships); + assertEquals(1, claimedOwnerships.size()); + + PartitionOwnership claimedOwnership = claimedOwnerships.get(0); + assertClaimedOwnership(partitionOwnership2, claimedOwnership); + + assertStoredOwnerships(partitionOwnership1, convertToTestable(claimedOwnership)); + assertStoredCheckpoints(checkpoint1, checkpoint2); + } + + @Test + void testStealOwnership() throws IOException { + addToState(partitionOwnership1); + + addToState(checkpoint1); + + PartitionOwnership newOwnership = copy(partitionOwnership1) + .setOwnerId(CLIENT_ID_2); + + List requestedOwnerships = Collections.singletonList(newOwnership); + + List claimedOwnerships = checkpointStore.claimOwnership(requestedOwnerships).collectList().block(); + + assertNotNull(claimedOwnerships); + assertEquals(1, claimedOwnerships.size()); + + PartitionOwnership claimedOwnership = claimedOwnerships.get(0); + assertClaimedOwnership(newOwnership, claimedOwnership); + + assertStoredOwnerships(convertToTestable(claimedOwnership)); + assertStoredCheckpoints(checkpoint1); + } + + @Test + void testClaimMultipleOwnerships() { + partitionOwnership2.setOwnerId(CLIENT_ID_1); + + List requestedOwnerships = Arrays.asList(partitionOwnership1, partitionOwnership2); + + List claimedOwnerships = checkpointStore.claimOwnership(requestedOwnerships).collectList().block(); + + assertNotNull(claimedOwnerships); + assertEquals(2, claimedOwnerships.size()); + + PartitionOwnership claimedOwnership1; + PartitionOwnership claimedOwnership2; + + if (claimedOwnerships.get(0).getPartitionId().equals(PARTITION_ID_1)) { + claimedOwnership1 = claimedOwnerships.get(0); + claimedOwnership2 = claimedOwnerships.get(1); + } else { + claimedOwnership1 = claimedOwnerships.get(1); + claimedOwnership2 = claimedOwnerships.get(2); + } + + assertClaimedOwnership(partitionOwnership1, claimedOwnership1); + assertClaimedOwnership(partitionOwnership2, claimedOwnership2); + + assertStoredOwnerships(convertToTestable(claimedOwnership1), convertToTestable(claimedOwnership2)); + } + + @Test + void testClaimOwnershipUnsuccessful() { + List requestedOwnershipsA = Collections.singletonList(partitionOwnership1); + List requestedOwnershipsB = Collections.singletonList(partitionOwnership1); + + List claimedOwnershipsA = checkpointStore.claimOwnership(requestedOwnershipsA).collectList().block(); + + List claimedOwnershipsB = checkpointStore.claimOwnership(requestedOwnershipsB).collectList().block(); + + assertNotNull(claimedOwnershipsB); + assertEquals(0, claimedOwnershipsB.size()); + + assertStoredOwnerships(convertToTestable(claimedOwnershipsA.get(0))); + } + + @Test + void testClaimMultipleOwnershipsPartialSuccess() { + List requestedOwnershipsA = Collections.singletonList(partitionOwnership1); + List requestedOwnershipsB = Arrays.asList(partitionOwnership1, partitionOwnership2); + + List claimedOwnershipsA = checkpointStore.claimOwnership(requestedOwnershipsA).collectList().block(); + + List claimedOwnershipsB = checkpointStore.claimOwnership(requestedOwnershipsB).collectList().block(); + + assertNotNull(claimedOwnershipsB); + assertEquals(1, claimedOwnershipsB.size()); + + assertStoredOwnerships(convertToTestable(claimedOwnershipsA.get(0)), convertToTestable(claimedOwnershipsB.get(0))); + } + + @Test + void testUnclaimOwnership() throws IOException { + addToState(partitionOwnership1); + + addToState(checkpoint1); + + PartitionOwnership ownershipToUnclaim = copy(partitionOwnership1) + .setOwnerId(""); + + List requestedOwnerships = Collections.singletonList(ownershipToUnclaim); + + List returnedOwnerships = checkpointStore.claimOwnership(requestedOwnerships).collectList().block(); + + assertNotNull(returnedOwnerships); + assertEquals(1, returnedOwnerships.size()); + + PartitionOwnership unclaimedOwnership = returnedOwnerships.get(0); + assertClaimedOwnership(ownershipToUnclaim, unclaimedOwnership); + + assertStoredOwnerships(convertToTestable(unclaimedOwnership)); + assertStoredCheckpoints(checkpoint1); + } + + @ParameterizedTest + @EnumSource(ExecutionMode.class) + void testNewCheckpoint(ExecutionMode executionMode) throws IOException { + setExecutionMode(executionMode); + + addToState(partitionOwnership1); + addToState(partitionOwnership2); + + addToState(checkpoint1); + + Checkpoint newCheckpoint = createCheckpoint(PARTITION_ID_2, 20L, 2L); + + checkpointStore.updateCheckpoint(newCheckpoint).block(); + + assertStoredCheckpoints(checkpoint1, newCheckpoint); + assertStoredOwnerships(partitionOwnership1, partitionOwnership2); + + assertLocalScope(executionMode); + } + + @Test + void testUpdatedCheckpoint() throws IOException { + addToState(partitionOwnership1); + addToState(partitionOwnership2); + + addToState(checkpoint1); + addToState(checkpoint2); + + Checkpoint updatedCheckpoint = copy(checkpoint2) + .setOffset(20L) + .setSequenceNumber(2L); + + checkpointStore.updateCheckpoint(updatedCheckpoint).block(); + + assertStoredCheckpoints(checkpoint1, updatedCheckpoint); + assertStoredOwnerships(partitionOwnership1, partitionOwnership2); + } + + @Test + void testCheckpointWithNullOffset() { + checkpoint1.setOffset(null); + + checkpointStore.updateCheckpoint(checkpoint1).block(); + + assertStoredCheckpoints(checkpoint1); + } + + @Test + void testCheckpointWithNullSequenceNumber() { + checkpoint1.setSequenceNumber(null); + + checkpointStore.updateCheckpoint(checkpoint1).block(); + + assertStoredCheckpoints(checkpoint1); + } + + @Test + void testDisconnectedNode() { + stateManager.setExecutionMode(ExecutionMode.STANDALONE); + + assertThrows(ClusterNodeDisconnectedException.class, () -> checkpointStore.claimOwnership(Collections.singletonList(partitionOwnership1)).collectList().block()); + + assertThrows(ClusterNodeDisconnectedException.class, () -> checkpointStore.updateCheckpoint(checkpoint1).block()); + } + + private void setExecutionMode(ExecutionMode executionMode) throws IOException { + stateManager.setExecutionMode(executionMode); + addToState(CLUSTERED.key(), Boolean.toString(executionMode == ExecutionMode.CLUSTERED), Scope.LOCAL); + } + + private void testListOwnerships(PartitionOwnership... expectedPartitionOwnerships) { + List partitionOwnerships = checkpointStore.listOwnership(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP).collectList().block(); + + assertNotNull(partitionOwnerships); + assertEquals(expectedPartitionOwnerships.length, partitionOwnerships.size()); + assertThat(convertToTestablePartitionOwnerships(partitionOwnerships), containsInAnyOrder(expectedPartitionOwnerships)); + } + + private void testListCheckpoints(Checkpoint... expectedCheckpoints) { + List checkpoints = checkpointStore.listCheckpoints(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP).collectList().block(); + + assertNotNull(checkpoints); + assertEquals(expectedCheckpoints.length, checkpoints.size()); + assertThat(convertToTestableCheckpoints(checkpoints), containsInAnyOrder(expectedCheckpoints)); + } + + private void assertStoredOwnerships(PartitionOwnership... expectedPartitionOwnerships) { + testListOwnerships(expectedPartitionOwnerships); + } + + private void assertStoredCheckpoints(Checkpoint... expectedCheckpoints) { + testListCheckpoints(expectedCheckpoints); + } + + private void assertLocalScope(ExecutionMode executionMode) { + stateManager.assertStateEquals(CLIENT_ID.key(), CLIENT_ID_1, Scope.LOCAL); + stateManager.assertStateEquals(CLUSTERED.key(), Boolean.toString(executionMode == ExecutionMode.CLUSTERED), Scope.LOCAL); + } + + private void addToState(PartitionOwnership partitionOwnership) throws IOException { + setETagAndLastModified(partitionOwnership); + + addToState(createOwnershipKey(partitionOwnership), createOwnershipValue(partitionOwnership), Scope.CLUSTER); + } + + private void addToState(Checkpoint checkpoint) throws IOException { + addToState(createCheckpointKey(checkpoint), createCheckpointValue(checkpoint), Scope.CLUSTER); + } + + private void addToState(String key, String value, Scope scope) throws IOException { + Map map = new HashMap<>(stateManager.getState(scope).toMap()); + + map.put(key, value); + + stateManager.setState(map, scope); + } + + private void initStateWithAllItems() throws IOException { + addToState(partitionOwnership1); + addToState(partitionOwnership2); + + addToState(checkpoint1); + addToState(checkpoint2); + + addToState(createPartitionOwnership(EVENT_HUB_NAMESPACE + "-2", EVENT_HUB_NAME, CONSUMER_GROUP, PARTITION_ID_1, CLIENT_ID_1)); + addToState(createPartitionOwnership(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME + "-2", CONSUMER_GROUP, PARTITION_ID_1, CLIENT_ID_1)); + addToState(createPartitionOwnership(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2", PARTITION_ID_1, CLIENT_ID_1)); + + addToState(createCheckpoint(EVENT_HUB_NAMESPACE + "-2", EVENT_HUB_NAME, CONSUMER_GROUP, PARTITION_ID_1, OFFSET, SEQUENCE_NUMBER)); + addToState(createCheckpoint(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME + "-2", CONSUMER_GROUP, PARTITION_ID_1, OFFSET, SEQUENCE_NUMBER)); + addToState(createCheckpoint(EVENT_HUB_NAMESPACE, EVENT_HUB_NAME, CONSUMER_GROUP + "-2", PARTITION_ID_1, OFFSET, SEQUENCE_NUMBER)); + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreUtilsTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreUtilsTest.java new file mode 100644 index 0000000000000..5bfcf7ac347cb --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/eventhub/checkpoint/ComponentStateCheckpointStoreUtilsTest.java @@ -0,0 +1,129 @@ +/* + * 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. + */ +package org.apache.nifi.processors.azure.eventhub.checkpoint; + +import com.azure.messaging.eventhubs.models.Checkpoint; +import com.azure.messaging.eventhubs.models.PartitionContext; +import com.azure.messaging.eventhubs.models.PartitionOwnership; +import org.junit.jupiter.api.Test; + +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.convertCheckpoint; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.convertOwnership; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.convertPartitionContext; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createCheckpointValue; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipKey; +import static org.apache.nifi.processors.azure.eventhub.checkpoint.ComponentStateCheckpointStoreUtils.createOwnershipValue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class ComponentStateCheckpointStoreUtilsTest extends AbstractCheckpointStoreTest { + + private static final String OWNERSHIP_KEY = "ownership/my-event-hub-namespace/my-event-hub-name/my-consumer-group/1"; + private static final String OWNERSHIP_VALUE = "client-id-1/1234567890/my-etag"; + + private static final String CHECKPOINT_KEY = "checkpoint/my-event-hub-namespace/my-event-hub-name/my-consumer-group/1"; + private static final String CHECKPOINT_VALUE = "10/1"; + + @Test + void testConvertOwnership() { + PartitionOwnership partitionOwnership = convertOwnership(OWNERSHIP_KEY, OWNERSHIP_VALUE); + + assertNotNull(partitionOwnership); + + assertEquals(EVENT_HUB_NAMESPACE, partitionOwnership.getFullyQualifiedNamespace()); + assertEquals(EVENT_HUB_NAME, partitionOwnership.getEventHubName()); + assertEquals(CONSUMER_GROUP, partitionOwnership.getConsumerGroup()); + assertEquals(PARTITION_ID_1, partitionOwnership.getPartitionId()); + + assertEquals(CLIENT_ID_1, partitionOwnership.getOwnerId()); + assertEquals(LAST_MODIFIED_TIME, partitionOwnership.getLastModifiedTime()); + assertEquals(ETAG, partitionOwnership.getETag()); + } + + @Test + void testConvertCheckpoint() { + Checkpoint checkpoint = convertCheckpoint(CHECKPOINT_KEY, CHECKPOINT_VALUE); + + assertNotNull(checkpoint); + + assertEquals(EVENT_HUB_NAMESPACE, checkpoint.getFullyQualifiedNamespace()); + assertEquals(EVENT_HUB_NAME, checkpoint.getEventHubName()); + assertEquals(CONSUMER_GROUP, checkpoint.getConsumerGroup()); + assertEquals(PARTITION_ID_1, checkpoint.getPartitionId()); + + assertEquals(OFFSET, checkpoint.getOffset()); + assertEquals(SEQUENCE_NUMBER, checkpoint.getSequenceNumber()); + } + + @Test + void testConvertPartitionContextFromOwnershipKey() { + PartitionContext partitionContext = convertPartitionContext(OWNERSHIP_KEY); + + assertNotNull(partitionContext); + + assertEquals(EVENT_HUB_NAMESPACE, partitionContext.getFullyQualifiedNamespace()); + assertEquals(EVENT_HUB_NAME, partitionContext.getEventHubName()); + assertEquals(CONSUMER_GROUP, partitionContext.getConsumerGroup()); + assertEquals(PARTITION_ID_1, partitionContext.getPartitionId()); + } + + @Test + void testConvertPartitionContextFromCheckpointKey() { + PartitionContext partitionContext = convertPartitionContext(CHECKPOINT_KEY); + + assertNotNull(partitionContext); + + assertEquals(EVENT_HUB_NAMESPACE, partitionContext.getFullyQualifiedNamespace()); + assertEquals(EVENT_HUB_NAME, partitionContext.getEventHubName()); + assertEquals(CONSUMER_GROUP, partitionContext.getConsumerGroup()); + assertEquals(PARTITION_ID_1, partitionContext.getPartitionId()); + } + + @Test + void testOwnershipKey() { + String ownershipKey = createOwnershipKey(partitionOwnership1); + + assertEquals(OWNERSHIP_KEY, ownershipKey); + } + + @Test + void testOwnershipValue() { + partitionOwnership1 + .setLastModifiedTime(LAST_MODIFIED_TIME) + .setETag(ETAG); + + String ownershipValue = createOwnershipValue(partitionOwnership1); + + assertEquals(OWNERSHIP_VALUE, ownershipValue); + } + + @Test + void testCheckpointKey() { + String checkpointKey = createCheckpointKey(checkpoint1); + + assertEquals(CHECKPOINT_KEY, checkpointKey); + } + + @Test + void testCheckpointValue() { + String checkpointValue = createCheckpointValue(checkpoint1); + + assertEquals(CHECKPOINT_VALUE, checkpointValue); + } + +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/AbstractAzureBlobStorage_v12IT.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/AbstractAzureBlobStorage_v12IT.java index eb53d9edd9372..058ee2f0a71a3 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/AbstractAzureBlobStorage_v12IT.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/AbstractAzureBlobStorage_v12IT.java @@ -80,15 +80,14 @@ protected String getDefaultEndpointSuffix() { @Override protected void setUpCredentials() throws Exception { - String serviceId = "credentials-service"; AzureStorageCredentialsService_v12 service = new AzureStorageCredentialsControllerService_v12(); runner.addControllerService(SERVICE_ID, service); - runner.setProperty(service, AzureStorageCredentialsControllerService_v12.ACCOUNT_NAME, getAccountName()); + runner.setProperty(service, AzureStorageUtils.ACCOUNT_NAME, getAccountName()); if (getEndpointSuffix() != null) { - runner.setProperty(service, AzureStorageCredentialsControllerService_v12.ENDPOINT_SUFFIX, getEndpointSuffix()); + runner.setProperty(service, AzureStorageUtils.ENDPOINT_SUFFIX, getEndpointSuffix()); } - runner.setProperty(service, AzureStorageCredentialsControllerService_v12.CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY.getAllowableValue()); - runner.setProperty(service, AzureStorageCredentialsControllerService_v12.ACCOUNT_KEY, getAccountKey()); + runner.setProperty(service, AzureStorageUtils.CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY); + runner.setProperty(service, AzureStorageUtils.ACCOUNT_KEY, getAccountKey()); runner.enableControllerService(service); runner.setProperty(AbstractAzureBlobProcessor_v12.STORAGE_CREDENTIALS_SERVICE, SERVICE_ID); @@ -179,7 +178,7 @@ protected void assertFlowFileCommonBlobAttributes(MockFlowFile flowFile, String flowFile.assertAttributeEquals(BlobAttributes.ATTR_NAME_PRIMARY_URI, String.format("https://%s.blob.core.windows.net/%s/%s", getAccountName(), containerName, URLEncoder.encode( blobName, - StandardCharsets.US_ASCII.name() + StandardCharsets.US_ASCII ).replace("+", "%20").replace("%2F", "/")) ); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITCopyAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITCopyAzureBlobStorage_v12.java index 3e2d233546fc3..d71b421ada15d 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITCopyAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITCopyAzureBlobStorage_v12.java @@ -94,7 +94,7 @@ private void assertSuccess(String containerName, String blobName, byte[] blobDat private void assertFlowFile(String containerName, String blobName, byte[] blobData) throws Exception { runner.assertAllFlowFilesTransferred(CopyAzureBlobStorage_v12.REL_SUCCESS, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(CopyAzureBlobStorage_v12.REL_SUCCESS).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(CopyAzureBlobStorage_v12.REL_SUCCESS).getFirst(); assertFlowFileCommonBlobAttributes(flowFile, containerName, blobName); if (blobData != null) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureBlobStorage_v12.java index 2d7e4f13c4a0d..c39baa224e3f2 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureBlobStorage_v12.java @@ -172,7 +172,7 @@ private void assertFailure(String blobName) throws Exception { private void assertFlowFile(Relationship relationship) throws Exception { runner.assertAllFlowFilesTransferred(relationship, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(relationship).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(relationship).getFirst(); flowFile.assertContentEquals(EMPTY_CONTENT); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureDataLakeStorage.java index 0c7864d96387b..0443e78ac570c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITDeleteAzureDataLakeStorage.java @@ -424,7 +424,7 @@ private void testFailedDelete(String fileSystem, String directory, String filena startRunner(inputFlowFileContent, Collections.emptyMap()); // THEN - DataLakeStorageException e = (DataLakeStorageException) runner.getLogger().getErrorMessages().get(0).getThrowable(); + DataLakeStorageException e = (DataLakeStorageException) runner.getLogger().getErrorMessages().getFirst().getThrowable(); assertEquals(expectedErrorCode, e.getStatusCode()); assertFailure(expectedFlowFileContent); @@ -439,7 +439,7 @@ private void testFailedDeleteWithProcessException(String fileSystem, String dire startRunner(inputFlowFileContent, attributes); // THEN - Throwable exception = runner.getLogger().getErrorMessages().get(0).getThrowable(); + Throwable exception = runner.getLogger().getErrorMessages().getFirst().getThrowable(); assertEquals(ProcessException.class, exception.getClass()); assertFailure(expectedFlowFileContent); @@ -459,7 +459,7 @@ private boolean directoryExists(String directory) { } private void setRunnerProperties(String fileSystem, String directory, String filename) { - runner.setProperty(DeleteAzureDataLakeStorage.FILESYSTEM_OBJECT_TYPE, filename != null ? FS_TYPE_FILE.getValue() : FS_TYPE_DIRECTORY.getValue()); + runner.setProperty(DeleteAzureDataLakeStorage.FILESYSTEM_OBJECT_TYPE, filename != null ? FS_TYPE_FILE : FS_TYPE_DIRECTORY); runner.setProperty(DeleteAzureDataLakeStorage.FILESYSTEM, fileSystem); runner.setProperty(DeleteAzureDataLakeStorage.DIRECTORY, directory); if (filename != null) { @@ -475,13 +475,13 @@ private void startRunner(String inputFlowFileContent, Map attrib private void assertSuccess(String directory, String filename, String expectedFlowFileContent, int expectedNumberOfProvenanceEvents, ProvenanceEventType expectedEventType) { runner.assertAllFlowFilesTransferred(DeleteAzureDataLakeStorage.REL_SUCCESS, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(DeleteAzureDataLakeStorage.REL_SUCCESS).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(DeleteAzureDataLakeStorage.REL_SUCCESS).getFirst(); flowFile.assertContentEquals(expectedFlowFileContent); int actualNumberOfProvenanceEvents = runner.getProvenanceEvents().size(); assertEquals(expectedNumberOfProvenanceEvents, actualNumberOfProvenanceEvents); - ProvenanceEventType actualEventType = runner.getProvenanceEvents().get(0).getEventType(); + ProvenanceEventType actualEventType = runner.getProvenanceEvents().getFirst().getEventType(); assertEquals(expectedEventType, actualEventType); if (filename != null) { @@ -493,7 +493,7 @@ private void assertSuccess(String directory, String filename, String expectedFlo private void assertFailure(String expectedFlowFileContent) { runner.assertAllFlowFilesTransferred(DeleteAzureDataLakeStorage.REL_FAILURE, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(DeleteAzureDataLakeStorage.REL_FAILURE).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(DeleteAzureDataLakeStorage.REL_FAILURE).getFirst(); flowFile.assertContentEquals(expectedFlowFileContent); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureBlobStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureBlobStorage_v12.java index 7f7e91bea469f..b076217434a9c 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureBlobStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureBlobStorage_v12.java @@ -58,7 +58,7 @@ public void testFetchBlobWithSimpleName() throws Exception { @Test public void testFetchBlobWithCSE() throws Exception { - runner.setProperty(ClientSideEncryptionSupport.CSE_KEY_TYPE, ClientSideEncryptionMethod.LOCAL.name()); + runner.setProperty(ClientSideEncryptionSupport.CSE_KEY_TYPE, ClientSideEncryptionMethod.LOCAL); runner.setProperty(ClientSideEncryptionSupport.CSE_KEY_ID, KEY_ID_VALUE); runner.setProperty(ClientSideEncryptionSupport.CSE_LOCAL_KEY, KEY_128B_VALUE); uploadBlobWithCSE(BLOB_NAME, BLOB_DATA, KEY_128B_VALUE, KEY_ID_VALUE, KeyWrapAlgorithm.A128KW.toString()); @@ -205,7 +205,7 @@ private void assertSuccess(String blobName, byte[] blobData, int originalLength) private void assertFlowFile(String blobName, byte[] blobData, Integer originalLength) throws Exception { runner.assertAllFlowFilesTransferred(FetchAzureBlobStorage_v12.REL_SUCCESS, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(FetchAzureBlobStorage_v12.REL_SUCCESS).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(FetchAzureBlobStorage_v12.REL_SUCCESS).getFirst(); assertFlowFileCommonBlobAttributes(flowFile, getContainerName(), blobName); if(originalLength != null) { @@ -226,7 +226,7 @@ private void assertProvenanceEvents() { private void assertFailure() throws Exception { runner.assertAllFlowFilesTransferred(FetchAzureBlobStorage_v12.REL_FAILURE, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(FetchAzureBlobStorage_v12.REL_FAILURE).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(FetchAzureBlobStorage_v12.REL_FAILURE).getFirst(); flowFile.assertContentEquals(EMPTY_CONTENT); } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureDataLakeStorage.java index 6d50691c6f781..54403b6183b8e 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITFetchAzureDataLakeStorage.java @@ -236,7 +236,6 @@ public void testFetchLargeFile() { Random random = new Random(); byte[] fileContentBytes = new byte[120_000_000]; random.nextBytes(fileContentBytes); - String fileContent = new String(fileContentBytes); String inputFlowFileContent = "InputFlowFileContent"; createDirectoryAndUploadFile(directory, filename, TEST_FILE_CONTENT); @@ -446,7 +445,7 @@ public void testFetchWithRangeStartOutOfRange() { startRunner(inputFlowFileContent, Collections.emptyMap()); // THEN - DataLakeStorageException e = (DataLakeStorageException)runner.getLogger().getErrorMessages().get(0).getThrowable(); + DataLakeStorageException e = (DataLakeStorageException)runner.getLogger().getErrorMessages().getFirst().getThrowable(); assertEquals(416, e.getStatusCode()); } @@ -489,7 +488,7 @@ private void testFailedFetch(String fileSystem, String directory, String filenam startRunner(inputFlowFileContent, attributes); // THEN - DataLakeStorageException e = (DataLakeStorageException)runner.getLogger().getErrorMessages().get(0).getThrowable(); + DataLakeStorageException e = (DataLakeStorageException)runner.getLogger().getErrorMessages().getFirst().getThrowable(); assertEquals(expectedErrorCode, e.getStatusCode()); assertFailure(expectedFlowFileContent); @@ -508,7 +507,7 @@ private void testFailedFetchWithProcessException(String fileSystem, String direc startRunner(inputFlowFileContent, attributes); // THEN - Throwable exception = runner.getLogger().getErrorMessages().get(0).getThrowable(); + Throwable exception = runner.getLogger().getErrorMessages().getFirst().getThrowable(); assertEquals(ProcessException.class, exception.getClass()); assertFailure(expectedFlowFileContent); @@ -541,7 +540,7 @@ private void startRunner(String inputFlowFileContent, Map attrib private void assertSuccess(String expectedFlowFileContent, Set expectedEventTypes) { runner.assertAllFlowFilesTransferred(FetchAzureDataLakeStorage.REL_SUCCESS, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(FetchAzureDataLakeStorage.REL_SUCCESS).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(FetchAzureDataLakeStorage.REL_SUCCESS).getFirst(); flowFile.assertContentEquals(expectedFlowFileContent); Set actualEventTypes = runner.getProvenanceEvents().stream() @@ -552,7 +551,7 @@ private void assertSuccess(String expectedFlowFileContent, Set attributes) { runner.run(); } - private MockFlowFile assertSuccess(String containerName, String blobName, byte[] blobData) throws Exception { - MockFlowFile flowFile = assertFlowFile(containerName, blobName, blobData); + private void assertSuccess(String containerName, String blobName, byte[] blobData) throws Exception { + assertFlowFile(containerName, blobName, blobData); assertAzureBlob(containerName, blobName, blobData); assertProvenanceEvents(); - return flowFile; } - private MockFlowFile assertSuccessForCSE(String containerName, String blobName, byte[] blobData) throws Exception { - MockFlowFile flowFile = assertFlowFile(containerName, blobName, blobData); + private void assertSuccessForCSE(String containerName, String blobName, byte[] blobData) throws Exception { + assertFlowFile(containerName, blobName, blobData); assertAzureBlobExists(containerName, blobName); assertProvenanceEvents(); - return flowFile; } private MockFlowFile assertIgnored(String containerName, String blobName) throws Exception { @@ -343,7 +342,7 @@ private MockFlowFile assertIgnored(String containerName, String blobName) throws private MockFlowFile assertFlowFile(String containerName, String blobName, byte[] blobData) throws Exception { runner.assertAllFlowFilesTransferred(PutAzureBlobStorage_v12.REL_SUCCESS, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutAzureBlobStorage_v12.REL_SUCCESS).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutAzureBlobStorage_v12.REL_SUCCESS).getFirst(); assertFlowFileCommonBlobAttributes(flowFile, containerName, blobName); if (blobData != null) { @@ -378,7 +377,7 @@ private void assertProvenanceEvents() { private MockFlowFile assertFailure(byte[] blobData, BlobErrorCode errorCode) throws Exception { runner.assertAllFlowFilesTransferred(PutAzureBlobStorage_v12.REL_FAILURE, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(DeleteAzureBlobStorage_v12.REL_FAILURE).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(DeleteAzureBlobStorage_v12.REL_FAILURE).getFirst(); flowFile.assertContentEquals(blobData); flowFile.assertAttributeEquals(ATTR_NAME_ERROR_CODE, errorCode.toString()); return flowFile; diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITPutAzureDataLakeStorage.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITPutAzureDataLakeStorage.java index 171e3a5e75fd3..9d22d2f88c1ac 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITPutAzureDataLakeStorage.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/ITPutAzureDataLakeStorage.java @@ -262,7 +262,7 @@ public void testPutFileFromLocalFile() throws Exception { runner.setProperty(service, StandardFileResourceService.FILE_PATH, String.format("${%s}", attributeName)); runner.enableControllerService(service); - runner.setProperty(ResourceTransferProperties.RESOURCE_TRANSFER_SOURCE, ResourceTransferSource.FILE_RESOURCE_SERVICE.getValue()); + runner.setProperty(ResourceTransferProperties.RESOURCE_TRANSFER_SOURCE, ResourceTransferSource.FILE_RESOURCE_SERVICE); runner.setProperty(ResourceTransferProperties.FILE_RESOURCE_SERVICE, serviceId); Path tempFilePath = Files.createTempFile("ITPutAzureDataLakeStorage_testPutFileFromLocalFile_", ""); @@ -325,7 +325,7 @@ private void assertFlowFile(byte[] fileData, String fileName, String directory) private MockFlowFile assertFlowFile(byte[] fileData) throws Exception { runner.assertAllFlowFilesTransferred(PutAzureDataLakeStorage.REL_SUCCESS, 1); - MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutAzureDataLakeStorage.REL_SUCCESS).get(0); + MockFlowFile flowFile = runner.getFlowFilesForRelationship(PutAzureDataLakeStorage.REL_SUCCESS).getFirst(); flowFile.assertContentEquals(fileData); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/TestClientSideEncryptionSupport.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/TestClientSideEncryptionSupport.java index 2664cc81e9951..748c662aa93fb 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/TestClientSideEncryptionSupport.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/TestClientSideEncryptionSupport.java @@ -161,6 +161,6 @@ private void assertNotValid(Collection result) { private void assertContains(Collection result, String explaination) { assertFalse(result.isEmpty(), "There should be validation error"); - assertTrue(result.stream().filter(v -> v.getExplanation().contains(explaination)).findFirst().isPresent()); + assertTrue(result.stream().anyMatch(v -> v.getExplanation().contains(explaination))); } } \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/queue/AbstractTestAzureQueueStorage_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/queue/AbstractTestAzureQueueStorage_v12.java index 6d5d663d9c3ae..74639bb9faa63 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/queue/AbstractTestAzureQueueStorage_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/processors/azure/storage/queue/AbstractTestAzureQueueStorage_v12.java @@ -16,6 +16,7 @@ */ package org.apache.nifi.processors.azure.storage.queue; +import org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils; import org.apache.nifi.reporting.InitializationException; import org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12; import org.apache.nifi.services.azure.storage.AzureStorageCredentialsService_v12; @@ -29,8 +30,8 @@ public abstract class AbstractTestAzureQueueStorage_v12 { protected void setupStorageCredentialsService() throws InitializationException { runner.addControllerService(CREDENTIALS_SERVICE_IDENTIFIER, credentialsService); - runner.setProperty(credentialsService, AzureStorageCredentialsControllerService_v12.ACCOUNT_NAME, "account-name"); - runner.setProperty(credentialsService, AzureStorageCredentialsControllerService_v12.CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY.getAllowableValue()); - runner.setProperty(credentialsService, AzureStorageCredentialsControllerService_v12.ACCOUNT_KEY, "account-key"); + runner.setProperty(credentialsService, AzureStorageUtils.ACCOUNT_NAME, "account-name"); + runner.setProperty(credentialsService, AzureStorageUtils.CREDENTIALS_TYPE, AzureStorageCredentialsType.ACCOUNT_KEY); + runner.setProperty(credentialsService, AzureStorageUtils.ACCOUNT_KEY, "account-key"); } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryServiceTest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryServiceTest.java index fc7bc92bdd4b1..54d195d326144 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryServiceTest.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/data/explorer/StandardKustoQueryServiceTest.java @@ -59,7 +59,7 @@ void testEnableManagedIdentity() throws InitializationException { runner.addControllerService(SERVICE_ID, service); runner.setProperty(service, StandardKustoQueryService.CLUSTER_URI, CLUSTER_URI); - runner.setProperty(service, StandardKustoQueryService.AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.MANAGED_IDENTITY.getValue()); + runner.setProperty(service, StandardKustoQueryService.AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.MANAGED_IDENTITY); runner.setProperty(service, StandardKustoQueryService.APPLICATION_CLIENT_ID, APPLICATION_CLIENT_ID); runner.assertValid(service); @@ -72,7 +72,7 @@ void testEnableApplicationCredentials() throws InitializationException { runner.addControllerService(SERVICE_ID, service); runner.setProperty(service, StandardKustoQueryService.CLUSTER_URI, CLUSTER_URI); - runner.setProperty(service, StandardKustoQueryService.AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS.getValue()); + runner.setProperty(service, StandardKustoQueryService.AUTHENTICATION_STRATEGY, KustoAuthenticationStrategy.APPLICATION_CREDENTIALS); runner.setProperty(service, StandardKustoQueryService.APPLICATION_CLIENT_ID, APPLICATION_CLIENT_ID); runner.setProperty(service, StandardKustoQueryService.APPLICATION_KEY, UUID.randomUUID().toString()); runner.setProperty(service, StandardKustoQueryService.APPLICATION_TENANT_ID, UUID.randomUUID().toString()); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/eventhub/TestAzureEventHubRecordSink.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/eventhub/TestAzureEventHubRecordSink.java index de53ca2b6d2a5..3d841475d9f6d 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/eventhub/TestAzureEventHubRecordSink.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/eventhub/TestAzureEventHubRecordSink.java @@ -24,13 +24,13 @@ import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.serialization.SimpleRecordSchema; import org.apache.nifi.serialization.WriteResult; -import org.apache.nifi.serialization.record.RecordSet; import org.apache.nifi.serialization.record.MapRecord; import org.apache.nifi.serialization.record.MockRecordWriter; import org.apache.nifi.serialization.record.Record; import org.apache.nifi.serialization.record.RecordField; import org.apache.nifi.serialization.record.RecordFieldType; import org.apache.nifi.serialization.record.RecordSchema; +import org.apache.nifi.serialization.record.RecordSet; import org.apache.nifi.shared.azure.eventhubs.AzureEventHubTransportType; import org.apache.nifi.util.NoOpProcessor; import org.apache.nifi.util.TestRunner; @@ -42,19 +42,19 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.io.IOException; -import java.util.Map; import java.util.Arrays; import java.util.Collections; +import java.util.Map; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.isA; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.any; +import static org.mockito.Mockito.isA; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class TestAzureEventHubRecordSink { @@ -92,7 +92,7 @@ void setRunner() throws Exception { runner.setProperty(azureEventHubRecordSink, AzureEventHubRecordSink.EVENT_HUB_NAMESPACE, EVENT_HUB_NAMESPACE); runner.setProperty(azureEventHubRecordSink, AzureEventHubRecordSink.SHARED_ACCESS_POLICY_KEY, POLICY_KEY); runner.setProperty(azureEventHubRecordSink, AzureEventHubRecordSink.RECORD_WRITER_FACTORY, WRITER_IDENTIFIER); - runner.setProperty(azureEventHubRecordSink, AzureEventHubRecordSink.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS.getValue()); + runner.setProperty(azureEventHubRecordSink, AzureEventHubRecordSink.TRANSPORT_TYPE, AzureEventHubTransportType.AMQP_WEB_SOCKETS); runner.enableControllerService(azureEventHubRecordSink); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java index b2655594341bb..ad0c1ba83dfe8 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestADLSCredentialsControllerService.java @@ -58,154 +58,15 @@ public void setUp() throws InitializationException { @Test public void testNotValidBecauseAccountNameMissing() { + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountKey(); runner.assertNotValid(credentialsService); } - @Test - public void testNotValidBecauseNoCredentialsIsSet() { - configureAccountName(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothAccountKeyAndSasTokenSpecified() { - configureAccountName(); - - configureAccountKey(); - configureSasToken(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothAccountKeyAndUseManagedIdentitySpecified() { - configureAccountName(); - - configureAccountKey(); - configureUseManagedIdentity(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothAccountKeyAndServicePrincipalTenantIdSpecified() { - configureAccountName(); - - configureAccountKey(); - configureServicePrincipalTenantId(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothAccountKeyAndServicePrincipalClientIdSpecified() { - configureAccountName(); - - configureAccountKey(); - configureServicePrincipalClientId(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothAccountKeyAndServicePrincipalClientSecretSpecified() { - configureAccountName(); - - configureAccountKey(); - configureServicePrincipalClientSecret(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothSasTokenAndUseManagedIdentitySpecified() { - configureAccountName(); - - configureSasToken(); - configureUseManagedIdentity(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothSasTokenAndServicePrincipalTenantIdSpecified() { - configureAccountName(); - - configureSasToken(); - configureServicePrincipalTenantId(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothSasTokenAndServicePrincipalClientIdSpecified() { - configureAccountName(); - - configureSasToken(); - configureServicePrincipalClientId(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothSasTokenAndServicePrincipalClientSecretSpecified() { - configureAccountName(); - - configureSasToken(); - configureServicePrincipalClientSecret(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothUseManagedIdentityAndServicePrincipalTenantIdSpecified() { - configureAccountName(); - - configureUseManagedIdentity(); - configureServicePrincipalTenantId(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothUseManagedIdentityAndServicePrincipalClientIdSpecified() { - configureAccountName(); - - configureUseManagedIdentity(); - configureServicePrincipalClientId(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseBothUseManagedIdentityAndServicePrincipalClientSecretSpecified() { - configureAccountName(); - - configureUseManagedIdentity(); - configureServicePrincipalClientSecret(); - - runner.assertNotValid(credentialsService); - } - - @Test - public void testNotValidBecauseAllCredentialsSpecified() throws Exception { - configureAccountName(); - - configureAccountKey(); - configureSasToken(); - configureUseManagedIdentity(); - configureServicePrincipalTenantId(); - configureServicePrincipalClientId(); - configureServicePrincipalClientSecret(); - - runner.assertNotValid(credentialsService); - } - @Test public void testNotValidWithEmptyEndpointSuffix() { + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountName(); configureAccountKey(); @@ -214,6 +75,7 @@ public void testNotValidWithEmptyEndpointSuffix() { } @Test public void testNotValidWithWhitespaceEndpointSuffix() { + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountName(); configureAccountKey(); @@ -223,6 +85,7 @@ public void testNotValidWithWhitespaceEndpointSuffix() { @Test public void testValidWithAccountNameAndAccountKey() { + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountName(); configureAccountKey(); @@ -231,6 +94,7 @@ public void testValidWithAccountNameAndAccountKey() { @Test public void testValidWithAccountNameAndSasToken() { + configureCredentialsType(AzureStorageCredentialsType.SAS_TOKEN); configureAccountName(); configureSasToken(); @@ -239,14 +103,15 @@ public void testValidWithAccountNameAndSasToken() { @Test public void testValidWithAccountNameAndUseManagedIdentity() { + configureCredentialsType(AzureStorageCredentialsType.MANAGED_IDENTITY); configureAccountName(); - configureUseManagedIdentity(); runner.assertValid(credentialsService); } @Test public void testValidWithAccountNameAndServicePrincipalWithClientSecret() { + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureAccountName(); configureServicePrincipalTenantId(); configureServicePrincipalClientId(); @@ -255,18 +120,9 @@ public void testValidWithAccountNameAndServicePrincipalWithClientSecret() { runner.assertValid(credentialsService); } - @Test - public void testNotValidBecauseManagedIdentityClientIdSpecifiedButUseManagedIdentityIsFalse() { - configureAccountName(); - configureAccountKey(); - - configureManagedIdentityClientId(); - - runner.assertNotValid(credentialsService); - } - @Test public void testNotValidBecauseNoTenantIdSpecifiedForServicePrincipal() { + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureAccountName(); configureServicePrincipalClientId(); @@ -277,6 +133,7 @@ public void testNotValidBecauseNoTenantIdSpecifiedForServicePrincipal() { @Test public void testNotValidBecauseNoClientIdSpecifiedForServicePrincipal() { + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureAccountName(); configureServicePrincipalTenantId(); @@ -287,6 +144,7 @@ public void testNotValidBecauseNoClientIdSpecifiedForServicePrincipal() { @Test public void testNotValidBecauseNoClientSecretSpecifiedForServicePrincipal() { + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureAccountName(); configureServicePrincipalTenantId(); @@ -298,6 +156,7 @@ public void testNotValidBecauseNoClientSecretSpecifiedForServicePrincipal() { @Test public void testGetCredentialsDetailsWithAccountKey() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountName(); configureAccountKey(); @@ -321,6 +180,7 @@ public void testGetCredentialsDetailsWithAccountKey() throws Exception { @Test public void testGetCredentialsDetailsWithAccountKeyUsingEL() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountNameUsingEL(); configureAccountKeyUsingEL(); @@ -344,6 +204,7 @@ public void testGetCredentialsDetailsWithAccountKeyUsingEL() throws Exception { @Test public void testGetCredentialsDetailsWithSasToken() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.SAS_TOKEN); configureAccountName(); configureSasToken(); @@ -366,6 +227,7 @@ public void testGetCredentialsDetailsWithSasToken() throws Exception { @Test public void testGetCredentialsDetailsWithSasTokenUsingEL() throws Exception { + configureCredentialsType(AzureStorageCredentialsType.SAS_TOKEN); configureAccountName(); configureSasTokenUsingEL(); @@ -386,8 +248,8 @@ public void testGetCredentialsDetailsWithSasTokenUsingEL() throws Exception { @Test public void testGetCredentialsDetailsWithSystemAssignedManagedIdentity() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.MANAGED_IDENTITY); configureAccountName(); - configureUseManagedIdentity(); runner.enableControllerService(credentialsService); @@ -409,8 +271,8 @@ public void testGetCredentialsDetailsWithSystemAssignedManagedIdentity() throws @Test public void testGetCredentialsDetailsWithUserAssignedManagedIdentity() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.MANAGED_IDENTITY); configureAccountName(); - configureUseManagedIdentity(); configureManagedIdentityClientId(); runner.enableControllerService(credentialsService); @@ -433,6 +295,7 @@ public void testGetCredentialsDetailsWithUserAssignedManagedIdentity() throws Ex @Test public void testGetCredentialsDetailsWithServicePrincipalWithClientSecret() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureAccountName(); configureServicePrincipalTenantId(); configureServicePrincipalClientId(); @@ -458,6 +321,7 @@ public void testGetCredentialsDetailsWithServicePrincipalWithClientSecret() thro @Test public void testGetCredentialsDetailsWithSetEndpointSuffix() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountName(); configureAccountKey(); configureEndpointSuffix(); @@ -474,6 +338,7 @@ public void testGetCredentialsDetailsWithSetEndpointSuffix() throws Exception { @Test public void testGetCredentialsDetailsWithSetEndpointSuffixUsingEL() throws Exception { // GIVEN + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountName(); configureAccountKey(); configureEndpointSuffixUsingEL(); @@ -486,13 +351,16 @@ public void testGetCredentialsDetailsWithSetEndpointSuffixUsingEL() throws Excep // THEN assertEquals(END_POINT_SUFFIX_VALUE, actual.getEndpointSuffix()); } + private void configureCredentialsType(AzureStorageCredentialsType credentialsType) { + runner.setProperty(credentialsService, AzureStorageUtils.CREDENTIALS_TYPE, credentialsType); + } private void configureAccountName() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.ACCOUNT_NAME, ACCOUNT_NAME_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.ACCOUNT_NAME, ACCOUNT_NAME_VALUE); } private void configureAccountNameUsingEL() { - configurePropertyUsingEL(ADLSCredentialsControllerService.ACCOUNT_NAME, "account.name", ACCOUNT_NAME_VALUE); + configurePropertyUsingEL(AzureStorageUtils.ACCOUNT_NAME, "account.name", ACCOUNT_NAME_VALUE); } private void configureAccountKey() { @@ -504,41 +372,37 @@ private void configureAccountKeyUsingEL() { } private void configureSasToken() { - runner.setProperty(credentialsService, AzureStorageUtils.PROP_SAS_TOKEN, SAS_TOKEN_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.SAS_TOKEN, SAS_TOKEN_VALUE); } private void configureSasTokenUsingEL() { String variableName = "sas.token"; - configurePropertyUsingEL(AzureStorageUtils.PROP_SAS_TOKEN, variableName, SAS_TOKEN_VALUE); - } - - private void configureUseManagedIdentity() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.USE_MANAGED_IDENTITY, "true"); + configurePropertyUsingEL(AzureStorageUtils.SAS_TOKEN, variableName, SAS_TOKEN_VALUE); } private void configureManagedIdentityClientId() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.MANAGED_IDENTITY_CLIENT_ID, MANAGED_IDENTITY_CLIENT_ID_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.MANAGED_IDENTITY_CLIENT_ID, MANAGED_IDENTITY_CLIENT_ID_VALUE); } private void configureEndpointSuffix() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.ENDPOINT_SUFFIX, END_POINT_SUFFIX_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.ENDPOINT_SUFFIX, END_POINT_SUFFIX_VALUE); } private void configureEndpointSuffixUsingEL() { String variableName = "endpoint.suffix"; - configurePropertyUsingEL(ADLSCredentialsControllerService.ENDPOINT_SUFFIX, variableName, END_POINT_SUFFIX_VALUE); + configurePropertyUsingEL(AzureStorageUtils.ENDPOINT_SUFFIX, variableName, END_POINT_SUFFIX_VALUE); } private void configureServicePrincipalTenantId() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.SERVICE_PRINCIPAL_TENANT_ID, SERVICE_PRINCIPAL_TENANT_ID_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID, SERVICE_PRINCIPAL_TENANT_ID_VALUE); } private void configureServicePrincipalClientId() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.SERVICE_PRINCIPAL_CLIENT_ID, SERVICE_PRINCIPAL_CLIENT_ID_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID, SERVICE_PRINCIPAL_CLIENT_ID_VALUE); } private void configureServicePrincipalClientSecret() { - runner.setProperty(credentialsService, ADLSCredentialsControllerService.SERVICE_PRINCIPAL_CLIENT_SECRET, SERVICE_PRINCIPAL_CLIENT_SECRET_VALUE); + runner.setProperty(credentialsService, AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_SECRET, SERVICE_PRINCIPAL_CLIENT_SECRET_VALUE); } private void configurePropertyUsingEL(PropertyDescriptor propertyDescriptor, String variableName, String variableValue) { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java index d3de995a98fac..94b61bb2e22e6 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-processors/src/test/java/org/apache/nifi/services/azure/storage/TestAzureStorageCredentialsControllerService_v12.java @@ -26,16 +26,14 @@ import java.util.Collections; import static org.apache.nifi.processors.azure.AzureServiceEndpoints.DEFAULT_BLOB_ENDPOINT_SUFFIX; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12.ACCOUNT_NAME; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12.CREDENTIALS_TYPE; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12.ENDPOINT_SUFFIX; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12.SERVICE_PRINCIPAL_CLIENT_ID; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12.SERVICE_PRINCIPAL_CLIENT_SECRET; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsControllerService_v12.SERVICE_PRINCIPAL_TENANT_ID; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsType.ACCOUNT_KEY; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsType.MANAGED_IDENTITY; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsType.SAS_TOKEN; -import static org.apache.nifi.services.azure.storage.AzureStorageCredentialsType.SERVICE_PRINCIPAL; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.ACCOUNT_KEY; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.ACCOUNT_NAME; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.CREDENTIALS_TYPE; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.ENDPOINT_SUFFIX; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SAS_TOKEN; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_ID; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_CLIENT_SECRET; +import static org.apache.nifi.processors.azure.storage.utils.AzureStorageUtils.SERVICE_PRINCIPAL_TENANT_ID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -63,7 +61,7 @@ public void setUp() throws InitializationException { @Test public void testNotValidBecauseAccountNameMissing() { - configureCredentialsType(ACCOUNT_KEY); + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountKey(); runner.assertNotValid(credentialsService); @@ -72,7 +70,7 @@ public void testNotValidBecauseAccountNameMissing() { @Test public void testAccountKeyCredentialsTypeValid() { configureAccountName(); - configureCredentialsType(ACCOUNT_KEY); + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountKey(); runner.assertValid(credentialsService); @@ -81,7 +79,7 @@ public void testAccountKeyCredentialsTypeValid() { @Test public void testAccountKeyCredentialsTypeNotValidBecauseAccountKeyMissing() { configureAccountName(); - configureCredentialsType(ACCOUNT_KEY); + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); runner.assertNotValid(credentialsService); } @@ -89,7 +87,7 @@ public void testAccountKeyCredentialsTypeNotValidBecauseAccountKeyMissing() { @Test public void testSasTokenCredentialsTypeValid() { configureAccountName(); - configureCredentialsType(SAS_TOKEN); + configureCredentialsType(AzureStorageCredentialsType.SAS_TOKEN); configureSasToken(); runner.assertValid(credentialsService); @@ -98,7 +96,7 @@ public void testSasTokenCredentialsTypeValid() { @Test public void testSasTokenCredentialsTypeNotValidBecauseSasTokenMissing() { configureAccountName(); - configureCredentialsType(SAS_TOKEN); + configureCredentialsType(AzureStorageCredentialsType.SAS_TOKEN); runner.assertNotValid(credentialsService); } @@ -106,7 +104,7 @@ public void testSasTokenCredentialsTypeNotValidBecauseSasTokenMissing() { @Test public void testManagedIdentityCredentialsTypeValid() { configureAccountName(); - configureCredentialsType(MANAGED_IDENTITY); + configureCredentialsType(AzureStorageCredentialsType.MANAGED_IDENTITY); runner.assertValid(credentialsService); } @@ -114,7 +112,7 @@ public void testManagedIdentityCredentialsTypeValid() { @Test public void testServicePrincipalCredentialsTypeValid() { configureAccountName(); - configureCredentialsType(SERVICE_PRINCIPAL); + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureServicePrincipalTenantId(); configureServicePrincipalClientId(); configureServicePrincipalClientSecret(); @@ -125,7 +123,7 @@ public void testServicePrincipalCredentialsTypeValid() { @Test public void testServicePrincipalCredentialsTypeNotValidBecauseTenantIdMissing() { configureAccountName(); - configureCredentialsType(SERVICE_PRINCIPAL); + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureServicePrincipalClientId(); configureServicePrincipalClientSecret(); @@ -135,7 +133,7 @@ public void testServicePrincipalCredentialsTypeNotValidBecauseTenantIdMissing() @Test public void testServicePrincipalCredentialsTypeNotValidBecauseClientIdMissing() { configureAccountName(); - configureCredentialsType(SERVICE_PRINCIPAL); + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureServicePrincipalTenantId(); configureServicePrincipalClientSecret(); @@ -145,7 +143,7 @@ public void testServicePrincipalCredentialsTypeNotValidBecauseClientIdMissing() @Test public void testServicePrincipalCredentialsTypeNotValidBecauseClientSecretMissing() { configureAccountName(); - configureCredentialsType(SERVICE_PRINCIPAL); + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureServicePrincipalTenantId(); configureServicePrincipalClientId(); @@ -155,7 +153,7 @@ public void testServicePrincipalCredentialsTypeNotValidBecauseClientSecretMissin @Test public void testGetCredentialsDetailsWithAccountKey() { configureAccountName(); - configureCredentialsType(ACCOUNT_KEY); + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountKey(); runner.enableControllerService(credentialsService); @@ -164,7 +162,7 @@ public void testGetCredentialsDetailsWithAccountKey() { assertEquals(ACCOUNT_NAME_VALUE, actual.getAccountName()); assertEquals(DEFAULT_BLOB_ENDPOINT_SUFFIX, actual.getEndpointSuffix()); - assertEquals(ACCOUNT_KEY, actual.getCredentialsType()); + assertEquals(AzureStorageCredentialsType.ACCOUNT_KEY, actual.getCredentialsType()); assertEquals(ACCOUNT_KEY_VALUE, actual.getAccountKey()); assertNull(actual.getSasToken()); assertNull(actual.getServicePrincipalTenantId()); @@ -175,7 +173,7 @@ public void testGetCredentialsDetailsWithAccountKey() { @Test public void testGetCredentialsDetailsWithSasToken() { configureAccountName(); - configureCredentialsType(SAS_TOKEN); + configureCredentialsType(AzureStorageCredentialsType.SAS_TOKEN); configureSasToken(); runner.enableControllerService(credentialsService); @@ -184,7 +182,7 @@ public void testGetCredentialsDetailsWithSasToken() { assertEquals(ACCOUNT_NAME_VALUE, actual.getAccountName()); assertEquals(DEFAULT_BLOB_ENDPOINT_SUFFIX, actual.getEndpointSuffix()); - assertEquals(SAS_TOKEN, actual.getCredentialsType()); + assertEquals(AzureStorageCredentialsType.SAS_TOKEN, actual.getCredentialsType()); assertNull(actual.getAccountKey()); assertEquals(SAS_TOKEN_VALUE, actual.getSasToken()); assertNull(actual.getServicePrincipalTenantId()); @@ -195,7 +193,7 @@ public void testGetCredentialsDetailsWithSasToken() { @Test public void testGetCredentialsDetailsWithManagedIdentity() { configureAccountName(); - configureCredentialsType(MANAGED_IDENTITY); + configureCredentialsType(AzureStorageCredentialsType.MANAGED_IDENTITY); runner.enableControllerService(credentialsService); @@ -203,7 +201,7 @@ public void testGetCredentialsDetailsWithManagedIdentity() { assertEquals(ACCOUNT_NAME_VALUE, actual.getAccountName()); assertEquals(DEFAULT_BLOB_ENDPOINT_SUFFIX, actual.getEndpointSuffix()); - assertEquals(MANAGED_IDENTITY, actual.getCredentialsType()); + assertEquals(AzureStorageCredentialsType.MANAGED_IDENTITY, actual.getCredentialsType()); assertNull(actual.getAccountKey()); assertNull(actual.getSasToken()); assertNull(actual.getServicePrincipalTenantId()); @@ -214,7 +212,7 @@ public void testGetCredentialsDetailsWithManagedIdentity() { @Test public void testGetCredentialsDetailsWithServicePrincipal() { configureAccountName(); - configureCredentialsType(SERVICE_PRINCIPAL); + configureCredentialsType(AzureStorageCredentialsType.SERVICE_PRINCIPAL); configureServicePrincipalTenantId(); configureServicePrincipalClientId(); configureServicePrincipalClientSecret(); @@ -225,7 +223,7 @@ public void testGetCredentialsDetailsWithServicePrincipal() { assertEquals(ACCOUNT_NAME_VALUE, actual.getAccountName()); assertEquals(DEFAULT_BLOB_ENDPOINT_SUFFIX, actual.getEndpointSuffix()); - assertEquals(SERVICE_PRINCIPAL, actual.getCredentialsType()); + assertEquals(AzureStorageCredentialsType.SERVICE_PRINCIPAL, actual.getCredentialsType()); assertNull(actual.getAccountKey()); assertNull(actual.getSasToken()); assertEquals(SERVICE_PRINCIPAL_TENANT_ID_VALUE, actual.getServicePrincipalTenantId()); @@ -237,7 +235,7 @@ public void testGetCredentialsDetailsWithServicePrincipal() { public void testGetCredentialsDetailsWithCustomEndpointSuffix() { configureAccountName(); configureEndpointSuffix(); - configureCredentialsType(ACCOUNT_KEY); + configureCredentialsType(AzureStorageCredentialsType.ACCOUNT_KEY); configureAccountKey(); runner.enableControllerService(credentialsService); @@ -256,15 +254,15 @@ private void configureEndpointSuffix() { } private void configureCredentialsType(AzureStorageCredentialsType credentialsType) { - runner.setProperty(credentialsService, CREDENTIALS_TYPE, credentialsType.getAllowableValue()); + runner.setProperty(credentialsService, CREDENTIALS_TYPE, credentialsType); } private void configureAccountKey() { - runner.setProperty(credentialsService, AzureStorageCredentialsControllerService_v12.ACCOUNT_KEY, ACCOUNT_KEY_VALUE); + runner.setProperty(credentialsService, ACCOUNT_KEY, ACCOUNT_KEY_VALUE); } private void configureSasToken() { - runner.setProperty(credentialsService, AzureStorageCredentialsControllerService_v12.SAS_TOKEN, SAS_TOKEN_VALUE); + runner.setProperty(credentialsService, SAS_TOKEN, SAS_TOKEN_VALUE); } private void configureServicePrincipalTenantId() { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AbstractAzureLogAnalyticsReportingTask.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AbstractAzureLogAnalyticsReportingTask.java index 1115f61092225..6ed960aa339f1 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AbstractAzureLogAnalyticsReportingTask.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AbstractAzureLogAnalyticsReportingTask.java @@ -16,39 +16,38 @@ */ package org.apache.nifi.reporting.azure.loganalytics; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.expression.ExpressionLanguageScope; +import org.apache.nifi.processor.util.StandardValidators; +import org.apache.nifi.reporting.AbstractReportingTask; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.regex.Pattern; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.nifi.components.PropertyDescriptor; -import org.apache.nifi.expression.ExpressionLanguageScope; -import org.apache.nifi.processor.util.StandardValidators; -import org.apache.nifi.reporting.AbstractReportingTask; - /** * Abstract ReportingTask to send metrics from Apache NiFi and JVM to Azure * Monitor. */ public abstract class AbstractAzureLogAnalyticsReportingTask extends AbstractReportingTask { - private static final Charset UTF8 = Charset.forName("UTF-8"); + private static final Charset UTF8 = StandardCharsets.UTF_8; private static final String HMAC_SHA256_ALG = "HmacSHA256"; // DateTimeFormatter.RFC_1123_DATE_TIME does not work in every case, such as when a @@ -90,6 +89,16 @@ public abstract class AbstractAzureLogAnalyticsReportingTask extends AbstractRep .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT).build(); + private static final List PROPERTIES = List.of( + LOG_ANALYTICS_WORKSPACE_ID, + LOG_ANALYTICS_WORKSPACE_KEY, + APPLICATION_ID, + INSTANCE_ID, + PROCESS_GROUP_IDS, + JOB_NAME, + LOG_ANALYTICS_URL_ENDPOINT_FORMAT + ); + protected String createAuthorization(String workspaceId, String key, int contentLength, String rfc1123Date) { try { String signature = String.format("POST\n%d\napplication/json\nx-ms-date:%s\n/api/logs", contentLength, @@ -105,15 +114,7 @@ protected String createAuthorization(String workspaceId, String key, int content @Override protected List getSupportedPropertyDescriptors() { - final List properties = new ArrayList<>(); - properties.add(LOG_ANALYTICS_WORKSPACE_ID); - properties.add(LOG_ANALYTICS_WORKSPACE_KEY); - properties.add(APPLICATION_ID); - properties.add(INSTANCE_ID); - properties.add(PROCESS_GROUP_IDS); - properties.add(JOB_NAME); - properties.add(LOG_ANALYTICS_URL_ENDPOINT_FORMAT); - return properties; + return PROPERTIES; } /** @@ -135,7 +136,7 @@ protected HttpPost getHttpPost(final String urlFormat, final String workspaceId, } protected void sendToLogAnalytics(final HttpPost request, final String workspaceId, final String linuxPrimaryKey, - final String rawJson) throws IllegalArgumentException, RuntimeException, IOException { + final String rawJson) throws RuntimeException, IOException { final int bodyLength = rawJson.getBytes(UTF8).length; final ZonedDateTime zNow = ZonedDateTime.now(ZoneOffset.UTC); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsProvenanceReportingTask.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsProvenanceReportingTask.java index c0f00a18a6b41..25da596c18046 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsProvenanceReportingTask.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsProvenanceReportingTask.java @@ -16,29 +16,6 @@ */ package org.apache.nifi.reporting.azure.loganalytics; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.text.DateFormat; -import java.text.MessageFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.UUID; - -import javax.json.Json; -import javax.json.JsonArrayBuilder; -import javax.json.JsonBuilderFactory; -import javax.json.JsonObject; -import javax.json.JsonObjectBuilder; -import javax.json.JsonValue; - import org.apache.commons.lang3.StringUtils; import org.apache.http.client.methods.HttpPost; import org.apache.nifi.annotation.documentation.CapabilityDescription; @@ -54,6 +31,26 @@ import org.apache.nifi.reporting.ReportingContext; import org.apache.nifi.reporting.util.provenance.ProvenanceEventConsumer; +import javax.json.Json; +import javax.json.JsonArrayBuilder; +import javax.json.JsonBuilderFactory; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.json.JsonValue; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.text.MessageFormat; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + @Tags({ "azure", "provenace", "reporting", "log analytics" }) @CapabilityDescription("Publishes Provenance events to to a Azure Log Analytics workspace.") public class AzureLogAnalyticsProvenanceReportingTask extends AbstractAzureLogAnalyticsReportingTask { @@ -61,6 +58,7 @@ public class AzureLogAnalyticsProvenanceReportingTask extends AbstractAzureLogAn protected static final String LAST_EVENT_ID_KEY = "last_event_id"; protected static final String DESTINATION_URL_PATH = "/nifi"; protected static final String TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(TIMESTAMP_FORMAT); static final PropertyDescriptor LOG_ANALYTICS_CUSTOM_LOG_NAME = new PropertyDescriptor.Builder() .name("Log Analytics Custom Log Name").description("Log Analytics Custom Log Name").required(false) @@ -145,7 +143,7 @@ public class AzureLogAnalyticsProvenanceReportingTask extends AbstractAzureLogAn .description("If the Reporting Task has never been run, or if its state has been reset by a user, " + "specifies where in the stream of Provenance Events the Reporting Task should start") .allowableValues(BEGINNING_OF_STREAM, END_OF_STREAM) - .defaultValue(BEGINNING_OF_STREAM.getValue()).required(true).build(); + .defaultValue(BEGINNING_OF_STREAM).required(true).build(); static final PropertyDescriptor ALLOW_NULL_VALUES = new PropertyDescriptor.Builder().name("include-null-values") .displayName("Include Null Values") @@ -169,32 +167,34 @@ public class AzureLogAnalyticsProvenanceReportingTask extends AbstractAzureLogAn .description("Specifies how many records to send in a single batch, at most.").required(true) .defaultValue("1000").addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR).build(); + private static final List PROPERTIES = List.of( + LOG_ANALYTICS_WORKSPACE_ID, + LOG_ANALYTICS_CUSTOM_LOG_NAME, + LOG_ANALYTICS_WORKSPACE_KEY, + APPLICATION_ID, + INSTANCE_ID, + JOB_NAME, + LOG_ANALYTICS_URL_ENDPOINT_FORMAT, + FILTER_EVENT_TYPE, + FILTER_EVENT_TYPE_EXCLUDE, + FILTER_COMPONENT_TYPE, + FILTER_COMPONENT_TYPE_EXCLUDE, + FILTER_COMPONENT_ID, + FILTER_COMPONENT_ID_EXCLUDE, + FILTER_COMPONENT_NAME, + FILTER_COMPONENT_NAME_EXCLUDE, + START_POSITION, + ALLOW_NULL_VALUES, + PLATFORM, + INSTANCE_URL, + BATCH_SIZE + ); + private volatile ProvenanceEventConsumer consumer; @Override protected List getSupportedPropertyDescriptors() { - final List properties = new ArrayList<>(); - properties.add(LOG_ANALYTICS_WORKSPACE_ID); - properties.add(LOG_ANALYTICS_CUSTOM_LOG_NAME); - properties.add(LOG_ANALYTICS_WORKSPACE_KEY); - properties.add(APPLICATION_ID); - properties.add(INSTANCE_ID); - properties.add(JOB_NAME); - properties.add(LOG_ANALYTICS_URL_ENDPOINT_FORMAT); - properties.add(FILTER_EVENT_TYPE); - properties.add(FILTER_EVENT_TYPE_EXCLUDE); - properties.add(FILTER_COMPONENT_TYPE); - properties.add(FILTER_COMPONENT_TYPE_EXCLUDE); - properties.add(FILTER_COMPONENT_ID); - properties.add(FILTER_COMPONENT_ID_EXCLUDE); - properties.add(FILTER_COMPONENT_NAME); - properties.add(FILTER_COMPONENT_NAME_EXCLUDE); - properties.add(START_POSITION); - properties.add(ALLOW_NULL_VALUES); - properties.add(PLATFORM); - properties.add(INSTANCE_URL); - properties.add(BATCH_SIZE); - return properties; + return PROPERTIES; } public void CreateConsumer(final ReportingContext context) { @@ -278,7 +278,7 @@ public void onTrigger(ReportingContext context) { } } - public void processProvenanceData(final ReportingContext context) throws IOException { + public void processProvenanceData(final ReportingContext context) { getLogger().debug("Starting to process provenance data"); final String workspaceId = context.getProperty(LOG_ANALYTICS_WORKSPACE_ID) .evaluateAttributeExpressions().getValue(); @@ -307,8 +307,6 @@ public void processProvenanceData(final ReportingContext context) throws IOExcep final Map config = Collections.emptyMap(); final JsonBuilderFactory factory = Json.createBuilderFactory(config); final JsonObjectBuilder builder = factory.createObjectBuilder(); - final DateFormat df = new SimpleDateFormat(TIMESTAMP_FORMAT); - df.setTimeZone(TimeZone.getTimeZone("Z")); CreateConsumer(context); consumer.consumeEvents(context, (mapHolder, events) -> { StringBuilder stringBuilder = new StringBuilder(); @@ -318,7 +316,7 @@ public void processProvenanceData(final ReportingContext context) throws IOExcep final String processGroupId = mapHolder.getProcessGroupId(event.getComponentId(), event.getComponentType()); final String processGroupName = mapHolder.getComponentName(processGroupId); - final JsonObject jo = serialize(factory, builder, event, df, componentName, + final JsonObject jo = serialize(factory, builder, event, componentName, processGroupId, processGroupName, hostname, url, rootGroupName, platform, nodeId, allowNullValues); stringBuilder.append(jo.toString()); @@ -345,7 +343,7 @@ public void processProvenanceData(final ReportingContext context) throws IOExcep } private JsonObject serialize(final JsonBuilderFactory factory, final JsonObjectBuilder builder, - final ProvenanceEventRecord event, final DateFormat df, final String componentName, + final ProvenanceEventRecord event, final String componentName, final String processGroupId, final String processGroupName, final String hostname, final URL nifiUrl, final String applicationName, final String platform, final String nodeIdentifier, Boolean allowNullValues) { @@ -353,7 +351,7 @@ private JsonObject serialize(final JsonBuilderFactory factory, final JsonObjectB addField(builder, "eventOrdinal", event.getEventId(), allowNullValues); addField(builder, "eventType", event.getEventType().name(), allowNullValues); addField(builder, "timestampMillis", event.getEventTime(), allowNullValues); - addField(builder, "timestamp", df.format(event.getEventTime()), allowNullValues); + addField(builder, "timestamp", DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(event.getEventTime()).atOffset(ZoneOffset.UTC)), allowNullValues); addField(builder, "durationMillis", event.getEventDuration(), allowNullValues); addField(builder, "lineageStart", event.getLineageStartDate(), allowNullValues); addField(builder, "details", event.getDetails(), allowNullValues); @@ -406,20 +404,15 @@ public void onUnscheduled() { public static void addField(final JsonObjectBuilder builder, final String key, final Object value, boolean allowNullValues) { - if (value != null) { - if (value instanceof String) { - builder.add(key, (String) value); - } else if (value instanceof Integer) { - builder.add(key, (Integer) value); - } else if (value instanceof Boolean) { - builder.add(key, (Boolean) value); - } else if (value instanceof Long) { - builder.add(key, (Long) value); - } else { - builder.add(key, value.toString()); + switch (value) { + case String s -> builder.add(key, s); + case Integer i -> builder.add(key, i); + case Boolean b -> builder.add(key, b); + case Long l -> builder.add(key, l); + case null -> { + if (allowNullValues) builder.add(key, JsonValue.NULL); } - } else if (allowNullValues) { - builder.add(key, JsonValue.NULL); + default -> builder.add(key, value.toString()); } } @@ -428,10 +421,8 @@ public static void addField(final JsonObjectBuilder builder, final JsonBuilderFa if (values != null) { final JsonObjectBuilder mapBuilder = factory.createObjectBuilder(); for (final Map.Entry entry : values.entrySet()) { - - if (entry.getKey() == null) { - continue; - } else if (entry.getValue() == null) { + if (entry.getKey() == null) continue; + if (entry.getValue() == null) { if (allowNullValues) { mapBuilder.add(entry.getKey(), JsonValue.NULL); } @@ -441,7 +432,6 @@ public static void addField(final JsonObjectBuilder builder, final JsonBuilderFa } builder.add(key, mapBuilder); - } else if (allowNullValues) { builder.add(key, JsonValue.NULL); } diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsReportingTask.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsReportingTask.java index 50ba99a323351..94ce957f20563 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsReportingTask.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/AzureLogAnalyticsReportingTask.java @@ -16,13 +16,8 @@ */ package org.apache.nifi.reporting.azure.loganalytics; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; - import org.apache.http.client.methods.HttpPost; import org.apache.nifi.annotation.configuration.DefaultSchedule; import org.apache.nifi.annotation.documentation.CapabilityDescription; @@ -39,6 +34,10 @@ import org.apache.nifi.reporting.azure.loganalytics.api.AzureLogAnalyticsMetricsFactory; import org.apache.nifi.scheduling.SchedulingStrategy; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + /** * ReportingTask to send metrics from Apache NiFi and JVM to Azure Monitor. */ @@ -59,37 +58,36 @@ public class AzureLogAnalyticsReportingTask extends AbstractAzureLogAnalyticsRep .defaultValue("nifimetrics").addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT).build(); + private static final List PROPERTIES = List.of( + SEND_JVM_METRICS, + LOG_ANALYTICS_WORKSPACE_ID, + LOG_ANALYTICS_CUSTOM_LOG_NAME, + LOG_ANALYTICS_WORKSPACE_KEY, + APPLICATION_ID, + INSTANCE_ID, + PROCESS_GROUP_IDS, + JOB_NAME, + LOG_ANALYTICS_URL_ENDPOINT_FORMAT + ); + @Override protected List getSupportedPropertyDescriptors() { - final List properties = new ArrayList<>(); - properties.add(SEND_JVM_METRICS); - properties.add(LOG_ANALYTICS_WORKSPACE_ID); - properties.add(LOG_ANALYTICS_CUSTOM_LOG_NAME); - properties.add(LOG_ANALYTICS_WORKSPACE_KEY); - properties.add(APPLICATION_ID); - properties.add(INSTANCE_ID); - properties.add(PROCESS_GROUP_IDS); - properties.add(JOB_NAME); - properties.add(LOG_ANALYTICS_URL_ENDPOINT_FORMAT); - return properties; + return PROPERTIES; } @Override public void onTrigger(final ReportingContext context) { - final String workspaceId = context.getProperty(LOG_ANALYTICS_WORKSPACE_ID).evaluateAttributeExpressions() - .getValue(); - final String linuxPrimaryKey = context.getProperty(LOG_ANALYTICS_WORKSPACE_KEY).evaluateAttributeExpressions() - .getValue(); + final String workspaceId = context.getProperty(LOG_ANALYTICS_WORKSPACE_ID).evaluateAttributeExpressions().getValue(); + final String linuxPrimaryKey = context.getProperty(LOG_ANALYTICS_WORKSPACE_KEY).evaluateAttributeExpressions().getValue(); final boolean jvmMetricsCollected = context.getProperty(SEND_JVM_METRICS).asBoolean(); - final String logName = context.getProperty(LOG_ANALYTICS_CUSTOM_LOG_NAME).evaluateAttributeExpressions() - .getValue(); + final String logName = context.getProperty(LOG_ANALYTICS_CUSTOM_LOG_NAME).evaluateAttributeExpressions().getValue(); final String instanceId = context.getProperty(INSTANCE_ID).evaluateAttributeExpressions().getValue(); final String groupIds = context.getProperty(PROCESS_GROUP_IDS).evaluateAttributeExpressions().getValue(); final String urlEndpointFormat = context.getProperty(LOG_ANALYTICS_URL_ENDPOINT_FORMAT) .evaluateAttributeExpressions().getValue(); try { - List allMetrics = null; + final List allMetrics; if (groupIds == null || groupIds.isEmpty()) { ProcessGroupStatus status = context.getEventAccess().getControllerStatus(); String processGroupName = status.getName(); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/Metric.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/Metric.java index afd35d8fa01f0..9550b050968ca 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/Metric.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/Metric.java @@ -41,13 +41,13 @@ public Metric(String instanceId, String processGroupId, String processGroupName } public void setCount(long value){ - this.count = Long.valueOf((long)value); + this.count = (long) value; } public void setCount(double value){ - this.count = Long.valueOf((long)value); + this.count = (long) value; } public void setCount(int value){ - this.count = Long.valueOf((long)value); + this.count = (long) value; } public Long getCount() { diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/MetricsBuilder.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/MetricsBuilder.java index 5578290dccd01..4cc02096579f5 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/MetricsBuilder.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/main/java/org/apache/nifi/reporting/azure/loganalytics/MetricsBuilder.java @@ -22,7 +22,7 @@ /** * MetricsBuilder builds the list of metrics */ -public class MetricsBuilder{ +public class MetricsBuilder { private List metrics = new ArrayList<>(); private String computer; @@ -34,29 +34,28 @@ public class MetricsBuilder{ private boolean isProcessorMetric = false; private String tags = null; - public MetricsBuilder(String category, String instanceId, String processGroupId, String processGroupName) { this.computer = instanceId; this.processGroupName = processGroupName; this.processGroupId = processGroupId; this.categoryName = category; - if (category.equals(Metric.CATEGORY_PROCESSOR)){ + if (category.equals(Metric.CATEGORY_PROCESSOR)) { isProcessorMetric = true; } } public MetricsBuilder(String category, String instanceId, String processGroupId, String processGroupName, String processorId, String processorName) { - this(category, instanceId,processGroupId,processGroupName); + this(category, instanceId, processGroupId, processGroupName); this.processorId = processorId; - this.processorName =processorName; + this.processorName = processorName; } - public MetricsBuilder setProcessorId(String processorId){ + public MetricsBuilder setProcessorId(String processorId) { this.processorId = processorId; return this; } - public MetricsBuilder setProcessorName(String processorName){ + public MetricsBuilder setProcessorName(String processorName) { this.processorName = processorName; return this; } @@ -66,69 +65,33 @@ public MetricsBuilder setTags(String tags) { return this; } - public MetricsBuilder metric(String metricName, long count){ - Metric metric = null; - if(isProcessorMetric) { - metric = new Metric(this.computer, this.processGroupId, this.processGroupName); - metric.setProcessorId(this.processorId); - metric.setProcessorName(this.processorName); - } else { - metric = new Metric(this.computer, this.processGroupId, this.processGroupName); - } - metric.setCategoryName(this.categoryName); - metric.setName(metricName); + public MetricsBuilder metric(String metricName, long count) { + final Metric metric = buildMetric(metricName); metric.setCount(count); - if(this.tags != null) { - metric.setTags(this.tags); - } metrics.add(metric); return this; } - public MetricsBuilder metric(String metricName, double count){ - Metric metric = null; - if(isProcessorMetric) { - metric = new Metric(this.computer, this.processGroupId, this.processGroupName); - metric.setProcessorId(this.processorId); - metric.setProcessorName(this.processorName); - } else { - metric = new Metric(this.computer, this.processGroupId, this.processGroupName); - } - metric.setCategoryName(this.categoryName); - metric.setName(metricName); + public MetricsBuilder metric(String metricName, double count) { + final Metric metric = buildMetric(metricName); metric.setCount(count); - if(this.tags != null) { - metric.setTags(this.tags); - } metrics.add(metric); return this; } public MetricsBuilder metric(String metricName, int count) { - Metric metric = null; - if(isProcessorMetric) { - metric = new Metric(this.computer, this.processGroupId, this.processGroupName); - metric.setProcessorId(this.processorId); - metric.setProcessorName(this.processorName); - } else { - metric = new Metric(this.computer, this.processGroupId, this.processGroupName); - } - metric.setCategoryName(this.categoryName); - metric.setName(metricName); + final Metric metric = buildMetric(metricName); metric.setCount(count); - if(this.tags != null) { - metric.setTags(this.tags); - } metrics.add(metric); return this; } + public List build() { return metrics; } public List getMetrics() { return this.metrics; } - public void setMetrics(List metrics) { this.metrics = metrics; } @@ -191,5 +154,17 @@ public String getTags() { return this.tags; } - + private Metric buildMetric(String metricName) { + final Metric metric = new Metric(this.computer, this.processGroupId, this.processGroupName); + if (this.isProcessorMetric) { + metric.setProcessorId(this.processorId); + metric.setProcessorName(this.processorName); + } + metric.setCategoryName(this.categoryName); + metric.setName(metricName); + if (this.tags != null) { + metric.setTags(this.tags); + } + return metric; + } } \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/test/java/org/apache/nifi/reporting/azure/loganalytics/TestAzureLogAnalyticsReportingTask.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/test/java/org/apache/nifi/reporting/azure/loganalytics/TestAzureLogAnalyticsReportingTask.java index 5d5e04713bec4..1eeef639b44e0 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/test/java/org/apache/nifi/reporting/azure/loganalytics/TestAzureLogAnalyticsReportingTask.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-reporting-task/src/test/java/org/apache/nifi/reporting/azure/loganalytics/TestAzureLogAnalyticsReportingTask.java @@ -153,7 +153,7 @@ private void initTestGroup2Statuses() { testGroupStatus2.setInputCount(1000); } @Test - public void testOnTrigger() throws IOException, InterruptedException, InitializationException { + public void testOnTrigger() throws InitializationException { testedReportingTask.initialize(reportingInitContextStub); reportingContextStub.getEventAccess().setProcessGroupStatus(rootGroupStatus); testedReportingTask.onTrigger(reportingContextStub); @@ -162,7 +162,7 @@ public void testOnTrigger() throws IOException, InterruptedException, Initializa TestVerification.assertDatatFlowMetrics(collectedMetrics); } @Test - public void testOnTriggerWithOnePG() throws IOException, InterruptedException, InitializationException { + public void testOnTriggerWithOnePG() throws InitializationException { initTestGroupStatuses(); reportingContextStub.setProperty(AzureLogAnalyticsReportingTask.PROCESS_GROUP_IDS.getName(), TEST_GROUP1_ID); testedReportingTask.initialize(reportingInitContextStub); @@ -174,7 +174,7 @@ public void testOnTriggerWithOnePG() throws IOException, InterruptedException, I TestVerification.assertDatatFlowMetrics(collectedMetrics); } @Test - public void testOnTriggerWithPGList() throws IOException, InterruptedException, InitializationException { + public void testOnTriggerWithPGList() throws InitializationException { initTestGroupStatuses(); initTestGroup2Statuses(); reportingContextStub.setProperty(AzureLogAnalyticsReportingTask.PROCESS_GROUP_IDS.getName(), @@ -190,7 +190,7 @@ public void testOnTriggerWithPGList() throws IOException, InterruptedException, } @Test - public void testEmitJVMMetrics() throws IOException, InterruptedException, InitializationException { + public void testEmitJVMMetrics() throws InitializationException { reportingContextStub.setProperty(AzureLogAnalyticsReportingTask.SEND_JVM_METRICS.getName(), "true"); testedReportingTask.initialize(reportingInitContextStub); @@ -202,7 +202,7 @@ public void testEmitJVMMetrics() throws IOException, InterruptedException, Initi } @Test - public void testAuthorization() throws IOException, InterruptedException, InitializationException { + public void testAuthorization() throws InitializationException { reportingContextStub.setProperty(AzureLogAnalyticsReportingTask.SEND_JVM_METRICS.getName(), "true"); testedReportingTask.initialize(reportingInitContextStub); diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestService.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestService.java new file mode 100644 index 0000000000000..f9fe6becdced6 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestService.java @@ -0,0 +1,49 @@ +/* + * 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. + */ +package org.apache.nifi.services.azure.data.explorer; + +import org.apache.nifi.controller.ControllerService; + +/** + * Kusto Ingest Service interface for Azure Data Explorer + */ +public interface KustoIngestService extends ControllerService { + /** + * Ingest data stream and return result status + * + * @param kustoIngestionRequest Kusto Ingestion Request with input stream + * @return Ingestion Result with status + */ + KustoIngestionResult ingestData(KustoIngestionRequest kustoIngestionRequest); + + /** + * Is Streaming Policy Enabled for specified database + * + * @param databaseName Database Name to be checked + * @return Streaming Policy Enabled status + */ + boolean isStreamingPolicyEnabled(String databaseName); + + /** + * Is Database Table Readable for specified database and table name + * + * @param databaseName Database Name to be checked + * @param table Table Name to be checked + * @return Table Readable status + */ + boolean isTableReadable(String databaseName, String table); +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestionRequest.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestionRequest.java new file mode 100644 index 0000000000000..3c790943615f1 --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestionRequest.java @@ -0,0 +1,96 @@ +/* + * 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. + */ +package org.apache.nifi.services.azure.data.explorer; + +import java.io.InputStream; +import java.time.Duration; + +public class KustoIngestionRequest { + + private final boolean streamingEnabled; + private final boolean pollOnIngestionStatus; + private final InputStream inputStream; + private final String dataFormat; + private final String mappingName; + private final String databaseName; + private final String tableName; + private final boolean ignoreFirstRecord; + private final Duration ingestionStatusPollingTimeout; + private final Duration ingestionStatusPollingInterval; + + public KustoIngestionRequest(final boolean isStreamingEnabled, + final boolean pollOnIngestionStatus, + final InputStream inputStream, + final String databaseName, + final String tableName, + final String dataFormat, + final String mappingName, + final boolean ignoreFirstRecord, + final Duration ingestionStatusPollingTimeout, + final Duration ingestionStatusPollingInterval) { + this.streamingEnabled = isStreamingEnabled; + this.inputStream = inputStream; + this.pollOnIngestionStatus = pollOnIngestionStatus; + this.databaseName = databaseName; + this.tableName = tableName; + this.dataFormat = dataFormat; + this.mappingName = mappingName; + this.ignoreFirstRecord = ignoreFirstRecord; + this.ingestionStatusPollingInterval = ingestionStatusPollingInterval; + this.ingestionStatusPollingTimeout = ingestionStatusPollingTimeout; + } + + public boolean isStreamingEnabled() { + return streamingEnabled; + } + + public InputStream getInputStream() { + return inputStream; + } + + public boolean pollOnIngestionStatus() { + return pollOnIngestionStatus; + } + + public String getDatabaseName() { + return databaseName; + } + + public String getTableName() { + return tableName; + } + + public boolean isIgnoreFirstRecord() { + return ignoreFirstRecord; + } + + public String getDataFormat() { + return dataFormat; + } + + public String getMappingName() { + return mappingName; + } + + public Duration getIngestionStatusPollingTimeout() { + return ingestionStatusPollingTimeout; + } + + public Duration getIngestionStatusPollingInterval() { + return ingestionStatusPollingInterval; + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestionResult.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestionResult.java new file mode 100644 index 0000000000000..e8133395a440e --- /dev/null +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/data/explorer/KustoIngestionResult.java @@ -0,0 +1,46 @@ +/* + * 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. + */ +package org.apache.nifi.services.azure.data.explorer; + +public enum KustoIngestionResult { + SUCCEEDED("Succeeded"), + + PARTIALLY_SUCCEEDED("PartiallySucceeded"), + + FAILED("Failed"), + + DEFAULT("Default"); + + private final String status; + + KustoIngestionResult(final String status) { + this.status = status; + } + + public static KustoIngestionResult fromString(String status) { + for (KustoIngestionResult result : KustoIngestionResult.values()) { + if (result.status.equalsIgnoreCase(status)) { + return result; + } + } + return DEFAULT; + } + + public String getStatus() { + return status; + } +} diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageConflictResolutionStrategy.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageConflictResolutionStrategy.java index 30ecd49bc9667..59dbda9346603 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageConflictResolutionStrategy.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageConflictResolutionStrategy.java @@ -20,11 +20,7 @@ public enum AzureStorageConflictResolutionStrategy implements DescribedValue { FAIL_RESOLUTION("fail", "Fail if the blob already exists"), - IGNORE_RESOLUTION("ignore", - String.format( - "Ignore if the blob already exists; the 'azure.error' attribute will be set to the value 'BLOB_ALREADY_EXISTS'" - ) - ), + IGNORE_RESOLUTION("ignore", "Ignore if the blob already exists; the 'azure.error' attribute will be set to the value 'BLOB_ALREADY_EXISTS'"), REPLACE_RESOLUTION("replace", "Replace blob contents if the blob already exist"); private final String label; diff --git a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsType.java b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsType.java index 4b83dcd3a26b6..04921c9ec080e 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsType.java +++ b/nifi-nar-bundles/nifi-azure-bundle/nifi-azure-services-api/src/main/java/org/apache/nifi/services/azure/storage/AzureStorageCredentialsType.java @@ -16,9 +16,9 @@ */ package org.apache.nifi.services.azure.storage; -import org.apache.nifi.components.AllowableValue; +import org.apache.nifi.components.DescribedValue; -public enum AzureStorageCredentialsType { +public enum AzureStorageCredentialsType implements DescribedValue { ACCOUNT_KEY("Account Key", "The primary or secondary Account Key of the storage account that provides full access to the resources in the account"), SAS_TOKEN("SAS Token", "SAS (Shared Access Signature) Token generated for accessing resources in the storage account"), @@ -26,17 +26,27 @@ public enum AzureStorageCredentialsType { SERVICE_PRINCIPAL("Service Principal", "Azure Active Directory Service Principal with Client Id / Client Secret of a registered application"), ACCESS_TOKEN("Access Token", "Access Token provided by custom controller service implementations"); - private final String label; + private final String displayName; private final String description; - AzureStorageCredentialsType(String label, String description) { - this.label = label; + AzureStorageCredentialsType(String displayName, String description) { + this.displayName = displayName; this.description = description; } - public AllowableValue getAllowableValue() { - return new AllowableValue(name(), label, description); + @Override + public String getValue() { + return name(); } + @Override + public String getDisplayName() { + return displayName; + } + + @Override + public String getDescription() { + return description; + } } diff --git a/nifi-nar-bundles/nifi-azure-bundle/pom.xml b/nifi-nar-bundles/nifi-azure-bundle/pom.xml index b9eb8d00380fa..61b0502a46686 100644 --- a/nifi-nar-bundles/nifi-azure-bundle/pom.xml +++ b/nifi-nar-bundles/nifi-azure-bundle/pom.xml @@ -27,8 +27,8 @@ pom - 1.2.18 - 1.14.0 + 1.2.19 + 1.14.2 0.34.1 diff --git a/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/main/java/org/apache/nifi/processors/cassandra/QueryCassandra.java b/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/main/java/org/apache/nifi/processors/cassandra/QueryCassandra.java index c7aa63d9e1080..67bd8e1d0b223 100644 --- a/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/main/java/org/apache/nifi/processors/cassandra/QueryCassandra.java +++ b/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/main/java/org/apache/nifi/processors/cassandra/QueryCassandra.java @@ -59,7 +59,9 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; -import java.text.SimpleDateFormat; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -71,7 +73,6 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; -import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -181,7 +182,7 @@ public class QueryCassandra extends AbstractCassandraProcessor { .addValidator((subject, input, context) -> { final ValidationResult.Builder vrb = new ValidationResult.Builder().subject(subject).input(input); try { - new SimpleDateFormat(input).format(new Date()); + DateTimeFormatter.ofPattern(input); vrb.valid(true).explanation("Valid date format pattern"); } catch (Exception ex) { vrb.valid(false).explanation("the pattern is invalid: " + ex.getMessage()); @@ -526,9 +527,9 @@ private static String getFormattedDate(final Optional context, D final String dateFormatPattern = context .map(_context -> _context.getProperty(TIMESTAMP_FORMAT_PATTERN).getValue()) .orElse(TIMESTAMP_FORMAT_PATTERN.getDefaultValue()); - SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatPattern); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - return dateFormat.format(value); + final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateFormatPattern); + final OffsetDateTime offsetDateTime = value.toInstant().atOffset(ZoneOffset.UTC); + return dateTimeFormatter.format(offsetDateTime); } public static long convertToJsonStream(final ResultSet rs, long maxRowsPerFlowFile, @@ -682,9 +683,8 @@ protected static String getJsonElement(final Optional context, O * * @param rs The result set from which an Avro schema will be created * @return An Avro schema corresponding to the given result set's metadata - * @throws IOException If an error occurs during schema discovery/building */ - public static Schema createSchema(final ResultSet rs) throws IOException { + public static Schema createSchema(final ResultSet rs) { final ColumnDefinitions columnDefinitions = rs.getColumnDefinitions(); final int nrOfColumns = (columnDefinitions == null ? 0 : columnDefinitions.size()); String tableName = "NiFi_Cassandra_Query_Record"; diff --git a/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/CassandraQueryTestUtil.java b/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/CassandraQueryTestUtil.java index e31627aa0bf64..6bdb400159b21 100644 --- a/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/CassandraQueryTestUtil.java +++ b/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/CassandraQueryTestUtil.java @@ -26,7 +26,8 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import java.text.SimpleDateFormat; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.Set; import java.util.Map; import java.util.List; @@ -67,7 +68,7 @@ public static ResultSet createMockResultSet(boolean falseThenTrue) throws Except "user_id", "first_name", "last_name", "emails", "top_places", "todo", "registered", "scale", "metric"); @Override - public String answer(InvocationOnMock invocationOnMock) throws Throwable { + public String answer(InvocationOnMock invocationOnMock) { return colNames.get((Integer) invocationOnMock.getArguments()[0]); } @@ -90,10 +91,10 @@ public DataType answer(InvocationOnMock invocationOnMock) throws Throwable { } }); - SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssZ"); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - final Date aMonthPrior = dateFormat.parse("2016-01-03 05:00:00+0000"); - final Date testDate = dateFormat.parse("2016-02-03 05:00:00+0000"); + final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssZ"); + final Date aMonthPrior = Date.from(OffsetDateTime.parse("2016-01-03 05:00:00+0000", dateTimeFormatter).toInstant()); + final Date testDate = Date.from(OffsetDateTime.parse("2016-02-03 05:00:00+0000", dateTimeFormatter).toInstant()); + List rows = Arrays.asList( createRow("user1", "Joe", "Smith", Sets.newHashSet("jsmith@notareal.com"), Arrays.asList("New York, NY", "Santa Clara, CA"), diff --git a/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/QueryCassandraTest.java b/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/QueryCassandraTest.java index c327f1ce3659d..fa3505b831433 100644 --- a/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/QueryCassandraTest.java +++ b/nifi-nar-bundles/nifi-cassandra-bundle/nifi-cassandra-processors/src/test/java/org/apache/nifi/processors/cassandra/QueryCassandraTest.java @@ -19,7 +19,6 @@ import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Configuration; import com.datastax.driver.core.ConsistencyLevel; -import com.datastax.driver.core.EndPoint; import com.datastax.driver.core.Metadata; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.ResultSetFuture; @@ -42,13 +41,12 @@ import java.io.ByteArrayOutputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TimeZone; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -62,14 +60,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; - public class QueryCassandraTest { private TestRunner testRunner; private MockQueryCassandra processor; @BeforeEach - public void setUp() throws Exception { + public void setUp() { processor = new MockQueryCassandra(); testRunner = TestRunners.newTestRunner(processor); } @@ -113,7 +110,7 @@ public void testProcessorNoInputFlowFileAndExceptions() { testRunner.clearTransferState(); // Test exceptions - processor.setExceptionToThrow(new NoHostAvailableException(new HashMap())); + processor.setExceptionToThrow(new NoHostAvailableException(new HashMap<>())); testRunner.run(1, true, true); testRunner.assertAllFlowFilesTransferred(QueryCassandra.REL_RETRY, 1); testRunner.clearTransferState(); @@ -282,7 +279,7 @@ public void testProcessorEmptyFlowFileAndNoHostAvailableException() { setUpStandardProcessorConfig(); // Test exceptions - processor.setExceptionToThrow(new NoHostAvailableException(new HashMap())); + processor.setExceptionToThrow(new NoHostAvailableException(new HashMap<>())); testRunner.enqueue("".getBytes()); testRunner.run(1, true, true); testRunner.assertTransferCount(QueryCassandra.REL_RETRY, 1); @@ -323,8 +320,6 @@ public void testProcessorEmptyFlowFileAndExceptionsProcessException() { testRunner.assertTransferCount(QueryCassandra.REL_FAILURE, 1); } - // -- - @Test public void testCreateSchemaOneColumn() throws Exception { ResultSet rs = CassandraQueryTestUtil.createMockResultSetOneColumn(); @@ -464,8 +459,7 @@ public void testDefaultDateFormatInConvertToJSONStream() throws Exception { ResultSet rs = CassandraQueryTestUtil.createMockDateResultSet(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DateFormat df = new SimpleDateFormat(QueryCassandra.TIMESTAMP_FORMAT_PATTERN.getDefaultValue()); - df.setTimeZone(TimeZone.getTimeZone("UTC")); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(QueryCassandra.TIMESTAMP_FORMAT_PATTERN.getDefaultValue()); long numberOfRows = QueryCassandra.convertToJsonStream(Optional.of(testRunner.getProcessContext()), rs, 0, baos, StandardCharsets.UTF_8, 0, null); @@ -473,7 +467,7 @@ public void testDefaultDateFormatInConvertToJSONStream() throws Exception { Map>> map = new ObjectMapper().readValue(baos.toByteArray(), HashMap.class); String date = map.get("results").get(0).get("date"); - assertEquals(df.format(CassandraQueryTestUtil.TEST_DATE), date); + assertEquals(formatter.format(CassandraQueryTestUtil.TEST_DATE.toInstant().atOffset(ZoneOffset.UTC)), date); } @Test @@ -484,15 +478,14 @@ public void testCustomDateFormatInConvertToJSONStream() throws Exception { final String customDateFormat = "yyyy-MM-dd HH:mm:ss.SSSZ"; context.setProperty(QueryCassandra.TIMESTAMP_FORMAT_PATTERN, customDateFormat); - DateFormat df = new SimpleDateFormat(customDateFormat); - df.setTimeZone(TimeZone.getTimeZone("UTC")); + final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(customDateFormat); long numberOfRows = QueryCassandra.convertToJsonStream(Optional.of(context), rs, 0, baos, StandardCharsets.UTF_8, 0, null); assertEquals(1, numberOfRows); Map>> map = new ObjectMapper().readValue(baos.toByteArray(), HashMap.class); String date = map.get("results").get(0).get("date"); - assertEquals(df.format(CassandraQueryTestUtil.TEST_DATE), date); + assertEquals(formatter.format(CassandraQueryTestUtil.TEST_DATE.toInstant().atOffset(ZoneOffset.UTC)), date); } private void setUpStandardProcessorConfig() { diff --git a/nifi-nar-bundles/nifi-cdc/nifi-cdc-mysql-bundle/nifi-cdc-mysql-processors/src/main/java/org/apache/nifi/cdc/mysql/processors/CaptureChangeMySQL.java b/nifi-nar-bundles/nifi-cdc/nifi-cdc-mysql-bundle/nifi-cdc-mysql-processors/src/main/java/org/apache/nifi/cdc/mysql/processors/CaptureChangeMySQL.java index 234d6acd27af4..9d158eb8b2d2e 100644 --- a/nifi-nar-bundles/nifi-cdc/nifi-cdc-mysql-bundle/nifi-cdc-mysql-processors/src/main/java/org/apache/nifi/cdc/mysql/processors/CaptureChangeMySQL.java +++ b/nifi-nar-bundles/nifi-cdc/nifi-cdc-mysql-bundle/nifi-cdc-mysql-processors/src/main/java/org/apache/nifi/cdc/mysql/processors/CaptureChangeMySQL.java @@ -580,7 +580,7 @@ public void setup(ProcessContext context) { binlogResourceInfo.setInTransaction("true".equals(stateMap.get("inTransaction"))); // Build a event writer config object for the event writers to use - final FlowFileEventWriteStrategy flowFileEventWriteStrategy = context.getProperty(EVENTS_PER_FLOWFILE_STRATEGY).asDescribedValue(FlowFileEventWriteStrategy.class); + final FlowFileEventWriteStrategy flowFileEventWriteStrategy = context.getProperty(EVENTS_PER_FLOWFILE_STRATEGY).asAllowableValue(FlowFileEventWriteStrategy.class); eventWriterConfiguration = new EventWriterConfiguration( flowFileEventWriteStrategy, context.getProperty(NUMBER_OF_EVENTS_PER_FLOWFILE).evaluateAttributeExpressions().asInteger() diff --git a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContent.java b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContent.java index b32bb2699301c..1409c909f2951 100644 --- a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContent.java +++ b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContent.java @@ -161,11 +161,11 @@ public void onTrigger(final ProcessContext context, final ProcessSession session return; } - final KeySpecificationFormat keySpecificationFormat = context.getProperty(KEY_SPECIFICATION_FORMAT).asDescribedValue(KeySpecificationFormat.class); + final KeySpecificationFormat keySpecificationFormat = context.getProperty(KEY_SPECIFICATION_FORMAT).asAllowableValue(KeySpecificationFormat.class); final String cipherTransformation = getCipherTransformation(context); final Cipher cipher = getCipher(cipherTransformation); - final CipherAlgorithmMode cipherAlgorithmMode = context.getProperty(CIPHER_ALGORITHM_MODE).asDescribedValue(CipherAlgorithmMode.class); + final CipherAlgorithmMode cipherAlgorithmMode = context.getProperty(CIPHER_ALGORITHM_MODE).asAllowableValue(CipherAlgorithmMode.class); final KeySpec keySpec = getKeySpec(context, keySpecificationFormat); final StreamCallback callback = new DecryptCallback(cipher, cipherAlgorithmMode, keySpec); diff --git a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentAge.java b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentAge.java index 6f44d2ebd741e..5534456042ec8 100644 --- a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentAge.java +++ b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentAge.java @@ -224,7 +224,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session } private List getRecipientStanzaReaders(final PropertyContext context) throws IOException { - final KeySource keySource = context.getProperty(PRIVATE_KEY_SOURCE).asDescribedValue(KeySource.class); + final KeySource keySource = context.getProperty(PRIVATE_KEY_SOURCE).asAllowableValue(KeySource.class); final List resources = switch (keySource) { case PROPERTIES -> List.of(context.getProperty(PRIVATE_KEY_IDENTITIES).asResource()); case RESOURCES -> context.getProperty(PRIVATE_KEY_IDENTITY_RESOURCES).asResources().asList(); diff --git a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentCompatibility.java b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentCompatibility.java index ebf53219a2a99..b22514fe97802 100644 --- a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentCompatibility.java +++ b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/DecryptContentCompatibility.java @@ -143,7 +143,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session } final CompatibilityModeEncryptionScheme encryptionScheme = - context.getProperty(ENCRYPTION_SCHEME).asDescribedValue(CompatibilityModeEncryptionScheme.class); + context.getProperty(ENCRYPTION_SCHEME).asAllowableValue(CompatibilityModeEncryptionScheme.class); final String scheme = encryptionScheme.getValue(); final Cipher cipher = getCipher(scheme); @@ -151,7 +151,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session final PBEKeySpec keySpec = new PBEKeySpec(password); final CompatibilityModeKeyDerivationStrategy keyDerivationStrategy = - context.getProperty(KEY_DERIVATION_STRATEGY).asDescribedValue(CompatibilityModeKeyDerivationStrategy.class); + context.getProperty(KEY_DERIVATION_STRATEGY).asAllowableValue(CompatibilityModeKeyDerivationStrategy.class); final StreamCallback callback = new DecryptCallback(cipher, keySpec, keyDerivationStrategy); final Map attributes = new LinkedHashMap<>(); diff --git a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/EncryptContentAge.java b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/EncryptContentAge.java index 4ee85d599aad8..6d4a828b0887c 100644 --- a/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/EncryptContentAge.java +++ b/nifi-nar-bundles/nifi-cipher-bundle/nifi-cipher-processors/src/main/java/org/apache/nifi/processors/cipher/EncryptContentAge.java @@ -214,7 +214,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session } try { - final FileEncoding fileEncoding = context.getProperty(FILE_ENCODING).asDescribedValue(FileEncoding.class); + final FileEncoding fileEncoding = context.getProperty(FILE_ENCODING).asAllowableValue(FileEncoding.class); final EncryptingChannelFactory encryptingChannelFactory = getEncryptingChannelFactory(fileEncoding); final StreamCallback streamCallback = new EncryptingStreamCallback(configuredRecipientStanzaWriters, encryptingChannelFactory); flowFile = session.write(flowFile, streamCallback); @@ -234,7 +234,7 @@ private EncryptingChannelFactory getEncryptingChannelFactory(final FileEncoding } private List getRecipientStanzaWriters(final PropertyContext context) throws IOException { - final KeySource keySource = context.getProperty(PUBLIC_KEY_SOURCE).asDescribedValue(KeySource.class); + final KeySource keySource = context.getProperty(PUBLIC_KEY_SOURCE).asAllowableValue(KeySource.class); final List resources = switch (keySource) { case PROPERTIES -> List.of(context.getProperty(PUBLIC_KEY_RECIPIENTS).asResource()); case RESOURCES -> context.getProperty(PUBLIC_KEY_RECIPIENT_RESOURCES).asResources().asList(); diff --git a/nifi-nar-bundles/nifi-compress-bundle/nifi-compress-processors/src/main/java/org/apache/nifi/processors/compress/ModifyCompression.java b/nifi-nar-bundles/nifi-compress-bundle/nifi-compress-processors/src/main/java/org/apache/nifi/processors/compress/ModifyCompression.java index 884357fcfdc7f..1f0fffb0354b5 100644 --- a/nifi-nar-bundles/nifi-compress-bundle/nifi-compress-processors/src/main/java/org/apache/nifi/processors/compress/ModifyCompression.java +++ b/nifi-nar-bundles/nifi-compress-bundle/nifi-compress-processors/src/main/java/org/apache/nifi/processors/compress/ModifyCompression.java @@ -195,7 +195,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session } final CompressionStrategy inputCompressionStrategy; - final CompressionStrategy configuredInputCompressionStrategy = context.getProperty(INPUT_COMPRESSION_STRATEGY).asDescribedValue(CompressionStrategy.class); + final CompressionStrategy configuredInputCompressionStrategy = context.getProperty(INPUT_COMPRESSION_STRATEGY).asAllowableValue(CompressionStrategy.class); if (CompressionStrategy.MIME_TYPE_ATTRIBUTE == configuredInputCompressionStrategy) { final String mimeType = flowFile.getAttribute(CoreAttributes.MIME_TYPE.key()); if (mimeType == null) { @@ -214,7 +214,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session inputCompressionStrategy = configuredInputCompressionStrategy; } - final CompressionStrategy outputCompressionStrategy = context.getProperty(OUTPUT_COMPRESSION_STRATEGY).asDescribedValue(CompressionStrategy.class); + final CompressionStrategy outputCompressionStrategy = context.getProperty(OUTPUT_COMPRESSION_STRATEGY).asAllowableValue(CompressionStrategy.class); final AtomicReference mimeTypeRef = new AtomicReference<>(null); final StopWatch stopWatch = new StopWatch(true); final long inputFileSize = flowFile.getSize(); diff --git a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-client-service/pom.xml b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-client-service/pom.xml index b9014738b4eb2..c0bd5207aaa2e 100644 --- a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-client-service/pom.xml +++ b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-client-service/pom.xml @@ -114,7 +114,6 @@ com.jayway.jsonpath json-path - 2.8.0 org.apache.httpcomponents diff --git a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/pom.xml b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/pom.xml index 4d10f33364be0..47d1d0e83b9d2 100644 --- a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/pom.xml +++ b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/pom.xml @@ -86,8 +86,6 @@ language governing permissions and limitations under the License. --> com.jayway.jsonpath json-path - 2.8.0 - compile diff --git a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/PutElasticsearchRecord.java b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/PutElasticsearchRecord.java index 99ce71f412e6c..e17db52035fef 100644 --- a/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/PutElasticsearchRecord.java +++ b/nifi-nar-bundles/nifi-elasticsearch-bundle/nifi-elasticsearch-restapi-processors/src/main/java/org/apache/nifi/processors/elasticsearch/PutElasticsearchRecord.java @@ -55,13 +55,14 @@ import org.apache.nifi.serialization.RecordReaderFactory; import org.apache.nifi.serialization.RecordSetWriter; import org.apache.nifi.serialization.RecordSetWriterFactory; -import org.apache.nifi.serialization.SimpleDateFormatValidator; +import org.apache.nifi.serialization.DateTimeFormatValidator; import org.apache.nifi.serialization.record.DataType; import org.apache.nifi.serialization.record.PushBackRecordSet; import org.apache.nifi.serialization.record.Record; import org.apache.nifi.serialization.record.RecordField; import org.apache.nifi.serialization.record.RecordFieldType; import org.apache.nifi.serialization.record.RecordSchema; +import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; import org.apache.nifi.serialization.record.type.ChoiceDataType; import org.apache.nifi.serialization.record.util.DataTypeUtils; import org.apache.nifi.util.StopWatch; @@ -307,7 +308,7 @@ public class PutElasticsearchRecord extends AbstractPutElasticsearch { + "If specified, the value must match the Java Simple Date Format (for example, MM/dd/yyyy for a two-digit month, followed by " + "a two-digit day, followed by a four-digit year, all separated by '/' characters, as in 01/25/2017).") .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .addValidator(new SimpleDateFormatValidator()) + .addValidator(new DateTimeFormatValidator()) .required(false) .build(); @@ -319,7 +320,7 @@ public class PutElasticsearchRecord extends AbstractPutElasticsearch { + "If specified, the value must match the Java Simple Date Format (for example, HH:mm:ss for a two-digit hour in 24-hour format, followed by " + "a two-digit minute, followed by a two-digit second, all separated by ':' characters, as in 18:04:15).") .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .addValidator(new SimpleDateFormatValidator()) + .addValidator(new DateTimeFormatValidator()) .required(false) .build(); @@ -332,7 +333,7 @@ public class PutElasticsearchRecord extends AbstractPutElasticsearch { + "a two-digit day, followed by a four-digit year, all separated by '/' characters; and then followed by a two-digit hour in 24-hour format, followed by " + "a two-digit minute, followed by a two-digit second, all separated by ':' characters, as in 01/25/2017 18:04:15).") .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) - .addValidator(new SimpleDateFormatValidator()) + .addValidator(new DateTimeFormatValidator()) .required(false) .build(); @@ -622,7 +623,7 @@ private void formatDateTimeFields(final Map contentMap, final Re if (format != null) { final Object formattedValue = coerceStringToLong( recordField.getFieldName(), - DataTypeUtils.toString(value, () -> DataTypeUtils.getDateFormat(format)) + StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class).convertField(value, Optional.of(format), recordField.getFieldName()) ); contentMap.put(recordField.getFieldName(), formattedValue); } @@ -717,7 +718,7 @@ private Object getTimestampFromRecordPath(final Record record, final RecordPath final String format = determineDateFormat(chosenDataType.getFieldType()); returnValue = coerceStringToLong( fieldName, - DataTypeUtils.toString(coercedValue, () -> DataTypeUtils.getDateFormat(format)) + StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class).convertField(coercedValue, Optional.ofNullable(format), path.getPath()) ); break; case LONG: diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNode.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNode.java index aa783627e7ee4..8b2e99072e375 100644 --- a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNode.java +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNode.java @@ -22,24 +22,20 @@ import org.apache.nifi.processors.evtx.parser.bxml.BxmlNode; import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.TimeZone; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; /** * Node containing a windows file time */ public class FiletimeTypeNode extends VariantTypeNode { + protected static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + private final String value; public FiletimeTypeNode(BinaryReader binaryReader, ChunkHeader chunkHeader, BxmlNode parent, int length) throws IOException { super(binaryReader, chunkHeader, parent, length); - value = getFormat().format(binaryReader.readFileTime()); - } - - public static final SimpleDateFormat getFormat() { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - return simpleDateFormat; + value = DATE_TIME_FORMATTER.format(binaryReader.readFileTime().toInstant().atOffset(ZoneOffset.UTC)); } @Override diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNode.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNode.java index af5c9c0238189..68aa05ea8f8c2 100644 --- a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNode.java +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/main/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNode.java @@ -22,36 +22,31 @@ import org.apache.nifi.processors.evtx.parser.bxml.BxmlNode; import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.TimeZone; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; /** * Node containing a system timestamp */ public class SystemtimeTypeNode extends VariantTypeNode { + public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + private final String value; public SystemtimeTypeNode(BinaryReader binaryReader, ChunkHeader chunkHeader, BxmlNode parent, int length) throws IOException { super(binaryReader, chunkHeader, parent, length); int year = binaryReader.readWord(); int month = binaryReader.readWord(); + final int monthOfYear = month + 1; int dayOfWeek = binaryReader.readWord(); int day = binaryReader.readWord(); int hour = binaryReader.readWord(); int minute = binaryReader.readWord(); int second = binaryReader.readWord(); int millisecond = binaryReader.readWord(); - Calendar calendar = Calendar.getInstance(); - calendar.set(year, month, day, hour, minute, second); - calendar.set(Calendar.MILLISECOND, millisecond); - value = getFormat().format(calendar.getTime()); - } - - public static final SimpleDateFormat getFormat() { - SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - return simpleDateFormat; + final int nanosecond = millisecond * 1000000; + final LocalDateTime localDateTime = LocalDateTime.of(year, monthOfYear, day, hour, minute, second, nanosecond); + value = FORMATTER.format(localDateTime); } @Override diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNodeTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNodeTest.java index 22f2ba10d7a04..a79715b4a1a93 100644 --- a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNodeTest.java +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/FiletimeTypeNodeTest.java @@ -21,6 +21,8 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Date; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -28,8 +30,8 @@ public class FiletimeTypeNodeTest extends BxmlNodeTestBase { @Test public void testFiletimeTypeNode() throws IOException { - Date date = new Date(); - assertEquals(FiletimeTypeNode.getFormat().format(date), - new FiletimeTypeNode(testBinaryReaderBuilder.putFileTime(date).build(), chunkHeader, parent, -1).getValue()); + final Instant instant = Instant.now(); + assertEquals(FiletimeTypeNode.DATE_TIME_FORMATTER.format(instant.atOffset(ZoneOffset.UTC)), + new FiletimeTypeNode(testBinaryReaderBuilder.putFileTime(Date.from(instant)).build(), chunkHeader, parent, -1).getValue()); } } diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNodeTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNodeTest.java index 0a0d706206d52..1b9b41ea54639 100644 --- a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNodeTest.java +++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/parser/bxml/value/SystemtimeTypeNodeTest.java @@ -21,6 +21,9 @@ import org.junit.jupiter.api.Test; import java.io.IOException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.Calendar; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -28,8 +31,11 @@ public class SystemtimeTypeNodeTest extends BxmlNodeTestBase { @Test public void testSystemtimeTypeNode() throws IOException { - Calendar calendar = Calendar.getInstance(); - assertEquals(SystemtimeTypeNode.getFormat().format(calendar.getTime()), + final LocalDateTime localDateTime = LocalDateTime.now(); + final Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant(); + final Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(instant.toEpochMilli()); + assertEquals(SystemtimeTypeNode.FORMATTER.format(localDateTime), new SystemtimeTypeNode(testBinaryReaderBuilder.putSystemtime(calendar).build(), chunkHeader, parent, -1).getValue()); } } diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/main/java/org/apache/nifi/util/db/JdbcCommon.java b/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/main/java/org/apache/nifi/util/db/JdbcCommon.java index bdc66302fd79e..84af3a926b280 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/main/java/org/apache/nifi/util/db/JdbcCommon.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/main/java/org/apache/nifi/util/db/JdbcCommon.java @@ -60,7 +60,6 @@ import java.sql.Timestamp; import java.sql.Types; import java.text.ParseException; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; @@ -126,6 +125,9 @@ public class JdbcCommon { public static final String MIME_TYPE_AVRO_BINARY = "application/avro-binary"; public static final String MASKED_LOG_VALUE = "MASKED VALUE"; + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss.SSS"); + private static final DateTimeFormatter TIMESTAMP_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + public static long convertToAvroStream(final ResultSet rs, final OutputStream outStream, boolean convertNames) throws SQLException, IOException { return convertToAvroStream(rs, outStream, null, null, convertNames); } @@ -751,7 +753,7 @@ private static void setParameterAtIndex(final PreparedStatement stmt, final Map< */ public static void setParameter(final PreparedStatement stmt, final int parameterIndex, final String parameterValue, final int jdbcType, final String valueFormat) - throws SQLException, ParseException, UnsupportedEncodingException { + throws SQLException, UnsupportedEncodingException, ParseException { if (parameterValue == null) { stmt.setNull(parameterIndex, jdbcType); } else { @@ -789,13 +791,11 @@ public static void setParameter(final PreparedStatement stmt, final int paramete java.sql.Date date; if (valueFormat.equals("")) { - if(LONG_PATTERN.matcher(parameterValue).matches()){ + if (LONG_PATTERN.matcher(parameterValue).matches()){ date = new java.sql.Date(Long.parseLong(parameterValue)); - }else { - String dateFormatString = "yyyy-MM-dd"; - SimpleDateFormat dateFormat = new SimpleDateFormat(dateFormatString); - java.util.Date parsedDate = dateFormat.parse(parameterValue); - date = new java.sql.Date(parsedDate.getTime()); + } else { + final LocalDate localDate = LocalDate.parse(parameterValue); + date = java.sql.Date.valueOf(localDate); } } else { final DateTimeFormatter dtFormatter = getDateTimeFormatter(valueFormat); @@ -812,10 +812,8 @@ public static void setParameter(final PreparedStatement stmt, final int paramete if (LONG_PATTERN.matcher(parameterValue).matches()) { time = new Time(Long.parseLong(parameterValue)); } else { - String timeFormatString = "HH:mm:ss.SSS"; - SimpleDateFormat dateFormat = new SimpleDateFormat(timeFormatString); - java.util.Date parsedDate = dateFormat.parse(parameterValue); - time = new Time(parsedDate.getTime()); + final LocalTime localTime = LocalTime.parse(parameterValue, TIME_FORMATTER); + time = Time.valueOf(localTime); } } else { final DateTimeFormatter dtFormatter = getDateTimeFormatter(valueFormat); @@ -833,12 +831,11 @@ public static void setParameter(final PreparedStatement stmt, final int paramete // Backwards compatibility note: Format was unsupported for a timestamp field. if (valueFormat.equals("")) { long lTimestamp = 0L; - if(LONG_PATTERN.matcher(parameterValue).matches()){ + if (LONG_PATTERN.matcher(parameterValue).matches()){ lTimestamp = Long.parseLong(parameterValue); } else { - final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - java.util.Date parsedDate = dateFormat.parse(parameterValue); - lTimestamp = parsedDate.getTime(); + final LocalDateTime localDateTime = LocalDateTime.parse(parameterValue, TIMESTAMP_FORMATTER); + lTimestamp = Timestamp.valueOf(localDateTime).getTime(); } ts = new Timestamp(lTimestamp); } else { diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/test/java/org/apache/nifi/util/db/TestJdbcCommon.java b/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/test/java/org/apache/nifi/util/db/TestJdbcCommon.java index 81e2dc0126933..163a3a1981fbe 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/test/java/org/apache/nifi/util/db/TestJdbcCommon.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-database-utils/src/test/java/org/apache/nifi/util/db/TestJdbcCommon.java @@ -43,7 +43,7 @@ import java.sql.Types; import java.time.Instant; import java.time.LocalTime; -import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -137,7 +137,7 @@ public void cleanup() throws IOException { private static final String DERBY_LOG_PROPERTY = "derby.stream.error.file"; @Test - public void testCreateSchema() throws ClassNotFoundException, SQLException { + public void testCreateSchema() throws SQLException { final Statement st = con.createStatement(); st.executeUpdate("insert into restaurants values (1, 'Irifunes', 'San Mateo')"); st.executeUpdate("insert into restaurants values (2, 'Estradas', 'Daly City')"); @@ -161,7 +161,7 @@ public void testCreateSchema() throws ClassNotFoundException, SQLException { } @Test - public void testCreateSchemaNoColumns() throws ClassNotFoundException, SQLException { + public void testCreateSchemaNoColumns() throws SQLException { final ResultSet resultSet = mock(ResultSet.class); final ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class); @@ -180,7 +180,7 @@ public void testCreateSchemaNoColumns() throws ClassNotFoundException, SQLExcept } @Test - public void testCreateSchemaNoTableName() throws ClassNotFoundException, SQLException { + public void testCreateSchemaNoTableName() throws SQLException { final ResultSet resultSet = mock(ResultSet.class); final ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class); @@ -224,7 +224,7 @@ public void testCreateSchemaOnlyColumnLabel() throws SQLException { } @Test - public void testConvertToBytes() throws ClassNotFoundException, SQLException, IOException { + public void testConvertToBytes() throws SQLException, IOException { final Statement st = con.createStatement(); st.executeUpdate("insert into restaurants values (1, 'Irifunes', 'San Mateo')"); st.executeUpdate("insert into restaurants values (2, 'Estradas', 'Daly City')"); @@ -285,14 +285,13 @@ public void testCreateSchemaTypes() throws SQLException, IllegalArgumentExceptio try { JdbcCommon.createSchema(rs); } catch (final IllegalArgumentException | SQLException sqle) { - sqle.printStackTrace(); fail("Failed when using type " + field.getName()); } } } @Test - public void testSignedIntShouldBeInt() throws SQLException, IllegalArgumentException, IllegalAccessException { + public void testSignedIntShouldBeInt() throws SQLException, IllegalArgumentException { final ResultSetMetaData metadata = mock(ResultSetMetaData.class); when(metadata.getColumnCount()).thenReturn(1); when(metadata.getColumnType(1)).thenReturn(Types.INTEGER); @@ -326,7 +325,7 @@ public void testSignedIntShouldBeInt() throws SQLException, IllegalArgumentExcep } @Test - public void testUnsignedIntShouldBeLong() throws SQLException, IllegalArgumentException, IllegalAccessException { + public void testUnsignedIntShouldBeLong() throws SQLException, IllegalArgumentException { final ResultSetMetaData metadata = mock(ResultSetMetaData.class); when(metadata.getColumnCount()).thenReturn(1); when(metadata.getColumnType(1)).thenReturn(Types.INTEGER); @@ -361,7 +360,7 @@ public void testUnsignedIntShouldBeLong() throws SQLException, IllegalArgumentEx } @Test - public void testMediumUnsignedIntShouldBeInt() throws SQLException, IllegalArgumentException, IllegalAccessException { + public void testMediumUnsignedIntShouldBeInt() throws SQLException, IllegalArgumentException { final ResultSetMetaData metadata = mock(ResultSetMetaData.class); when(metadata.getColumnCount()).thenReturn(1); when(metadata.getColumnType(1)).thenReturn(Types.INTEGER); @@ -396,7 +395,7 @@ public void testMediumUnsignedIntShouldBeInt() throws SQLException, IllegalArgum } @Test - public void testInt9ShouldBeLong() throws SQLException, IllegalArgumentException, IllegalAccessException { + public void testInt9ShouldBeLong() throws SQLException, IllegalArgumentException { final ResultSetMetaData metadata = mock(ResultSetMetaData.class); when(metadata.getColumnCount()).thenReturn(1); when(metadata.getColumnType(1)).thenReturn(Types.INTEGER); @@ -430,7 +429,6 @@ public void testInt9ShouldBeLong() throws SQLException, IllegalArgumentException assertTrue(foundNullSchema); } - @Test public void testConvertToAvroStreamForBigDecimal() throws SQLException, IOException { final BigDecimal bigDecimal = new BigDecimal(12345D); @@ -777,7 +775,7 @@ public void testConvertToAvroStreamForDateTimeAsLogicalType() throws SQLExceptio }, (record, time) -> { int millisSinceMidnight = (int) record.get("time"); - LocalTime localTime = Instant.ofEpochMilli(millisSinceMidnight).atZone(ZoneId.systemDefault()).toLocalTime(); + LocalTime localTime = Instant.ofEpochMilli(millisSinceMidnight).atOffset(ZoneOffset.UTC).toLocalTime(); Time actual = Time.valueOf(localTime); LOGGER.debug("comparing times, expecting '{}', actual '{}'", time, actual); assertEquals(time, actual); diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/pom.xml b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/pom.xml new file mode 100644 index 0000000000000..4b3085fd20616 --- /dev/null +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/pom.xml @@ -0,0 +1,59 @@ + + + + 4.0.0 + + org.apache.nifi + nifi-extension-utils + 2.0.0-SNAPSHOT + + nifi-file-transfer + jar + + + org.apache.nifi + nifi-api + + + org.apache.nifi + nifi-listed-entity + 2.0.0-SNAPSHOT + + + org.apache.nifi + nifi-property-utils + 2.0.0-SNAPSHOT + + + org.apache.nifi + nifi-record + 2.0.0-SNAPSHOT + + + org.apache.nifi + nifi-utils + 2.0.0-SNAPSHOT + + + commons-io + commons-io + + + org.apache.commons + commons-lang3 + + + diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/FetchFileTransfer.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FetchFileTransfer.java similarity index 92% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/FetchFileTransfer.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FetchFileTransfer.java index 1e8efba2c06a2..a4f720924558c 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/FetchFileTransfer.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FetchFileTransfer.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.nifi.processors.standard; +package org.apache.nifi.processor.util.file.transfer; import org.apache.commons.lang3.StringUtils; import org.apache.nifi.annotation.lifecycle.OnScheduled; @@ -32,8 +32,6 @@ import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.util.StandardValidators; -import org.apache.nifi.processors.standard.util.FileTransfer; -import org.apache.nifi.processors.standard.util.PermissionDeniedException; import org.apache.nifi.util.StopWatch; import org.apache.nifi.util.Tuple; @@ -58,19 +56,19 @@ */ public abstract class FetchFileTransfer extends AbstractProcessor { - static final AllowableValue COMPLETION_NONE = new AllowableValue("None", "None", "Leave the file as-is"); - static final AllowableValue COMPLETION_MOVE = new AllowableValue("Move File", "Move File", "Move the file to the directory specified by the property"); - static final AllowableValue COMPLETION_DELETE = new AllowableValue("Delete File", "Delete File", "Deletes the original file from the remote system"); - static final String FAILURE_REASON_ATTRIBUTE = "fetch.failure.reason"; + public static final AllowableValue COMPLETION_NONE = new AllowableValue("None", "None", "Leave the file as-is"); + public static final AllowableValue COMPLETION_MOVE = new AllowableValue("Move File", "Move File", "Move the file to the directory specified by the property"); + public static final AllowableValue COMPLETION_DELETE = new AllowableValue("Delete File", "Delete File", "Deletes the original file from the remote system"); + public static final String FAILURE_REASON_ATTRIBUTE = "fetch.failure.reason"; - static final PropertyDescriptor HOSTNAME = new PropertyDescriptor.Builder() + public static final PropertyDescriptor HOSTNAME = new PropertyDescriptor.Builder() .name("Hostname") .description("The fully-qualified hostname or IP address of the host to fetch the data from") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) .required(true) .build(); - static final PropertyDescriptor UNDEFAULTED_PORT = new PropertyDescriptor.Builder() + public static final PropertyDescriptor UNDEFAULTED_PORT = new PropertyDescriptor.Builder() .name("Port") .description("The port to connect to on the remote host to fetch the data from") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) @@ -91,7 +89,7 @@ public abstract class FetchFileTransfer extends AbstractProcessor { .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) .expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES) .build(); - static final PropertyDescriptor COMPLETION_STRATEGY = new PropertyDescriptor.Builder() + public static final PropertyDescriptor COMPLETION_STRATEGY = new PropertyDescriptor.Builder() .name("Completion Strategy") .description("Specifies what to do with the original file on the server once it has been pulled into NiFi. If the Completion Strategy fails, a warning will be " + "logged but the data will still be transferred.") @@ -100,14 +98,14 @@ public abstract class FetchFileTransfer extends AbstractProcessor { .defaultValue(COMPLETION_NONE.getValue()) .required(true) .build(); - static final PropertyDescriptor MOVE_CREATE_DIRECTORY = new PropertyDescriptor.Builder() + public static final PropertyDescriptor MOVE_CREATE_DIRECTORY = new PropertyDescriptor.Builder() .fromPropertyDescriptor(FileTransfer.CREATE_DIRECTORY).description(String.format("Used when '%s' is '%s'. %s", COMPLETION_STRATEGY.getDisplayName(), COMPLETION_MOVE.getDisplayName(), FileTransfer.CREATE_DIRECTORY.getDescription())) .required(false) .build(); - static final PropertyDescriptor MOVE_DESTINATION_DIR = new PropertyDescriptor.Builder() + public static final PropertyDescriptor MOVE_DESTINATION_DIR = new PropertyDescriptor.Builder() .name("Move Destination Directory") .description(String.format("The directory on the remote server to move the original file to once it has been ingested into NiFi. " + "This property is ignored unless the %s is set to '%s'. The specified directory must already exist on " @@ -118,7 +116,7 @@ public abstract class FetchFileTransfer extends AbstractProcessor { .required(false) .build(); - static final PropertyDescriptor FILE_NOT_FOUND_LOG_LEVEL = new PropertyDescriptor.Builder() + public static final PropertyDescriptor FILE_NOT_FOUND_LOG_LEVEL = new PropertyDescriptor.Builder() .displayName("Log level when file not found") .name("fetchfiletransfer-notfound-loglevel") .description("Log level to use in case the file does not exist when the processor is triggered") @@ -131,15 +129,15 @@ public abstract class FetchFileTransfer extends AbstractProcessor { .name("success") .description("All FlowFiles that are received are routed to success") .build(); - static final Relationship REL_COMMS_FAILURE = new Relationship.Builder() + public static final Relationship REL_COMMS_FAILURE = new Relationship.Builder() .name("comms.failure") .description("Any FlowFile that could not be fetched from the remote server due to a communications failure will be transferred to this Relationship.") .build(); - static final Relationship REL_NOT_FOUND = new Relationship.Builder() + public static final Relationship REL_NOT_FOUND = new Relationship.Builder() .name("not.found") .description("Any FlowFile for which we receive a 'Not Found' message from the remote server will be transferred to this Relationship.") .build(); - static final Relationship REL_PERMISSION_DENIED = new Relationship.Builder() + public static final Relationship REL_PERMISSION_DENIED = new Relationship.Builder() .name("permission.denied") .description("Any FlowFile that could not be fetched from the remote server due to insufficient permissions will be transferred to this Relationship.") .build(); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FileInfo.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FileInfo.java similarity index 99% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FileInfo.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FileInfo.java index 20efdf5fc37d6..a6ed2c265ef5a 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FileInfo.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FileInfo.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.processors.standard.util; +package org.apache.nifi.processor.util.file.transfer; import java.io.File; import java.io.Serializable; diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FileTransfer.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FileTransfer.java similarity index 99% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FileTransfer.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FileTransfer.java index c3fc9fb7b713c..56f6f1bfa72a3 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/FileTransfer.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/FileTransfer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.processors.standard.util; +package org.apache.nifi.processor.util.file.transfer; import java.io.Closeable; import java.io.File; diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFileTransfer.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/GetFileTransfer.java similarity index 96% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFileTransfer.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/GetFileTransfer.java index 6afbc41aa230d..b902d6e483b73 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/GetFileTransfer.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/GetFileTransfer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.processors.standard; +package org.apache.nifi.processor.util.file.transfer; import org.apache.nifi.annotation.lifecycle.OnScheduled; import org.apache.nifi.flowfile.FlowFile; @@ -25,21 +25,18 @@ import org.apache.nifi.processor.ProcessSession; import org.apache.nifi.processor.Relationship; import org.apache.nifi.processor.exception.FlowFileAccessException; -import org.apache.nifi.processors.standard.util.FileInfo; -import org.apache.nifi.processors.standard.util.FileTransfer; import org.apache.nifi.util.StopWatch; import java.io.File; import java.io.IOException; import java.nio.file.Path; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; @@ -68,7 +65,9 @@ public abstract class GetFileTransfer extends AbstractProcessor { public static final String FILE_OWNER_ATTRIBUTE = "file.owner"; public static final String FILE_GROUP_ATTRIBUTE = "file.group"; public static final String FILE_PERMISSIONS_ATTRIBUTE = "file.permissions"; + public static final String FILE_SIZE_ATTRIBUTE = "file.size"; public static final String FILE_MODIFY_DATE_ATTR_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; + protected static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(FILE_MODIFY_DATE_ATTR_FORMAT); private final AtomicLong lastPollTime = new AtomicLong(-1L); private final Lock listingLock = new ReentrantLock(); @@ -277,8 +276,7 @@ private void closeTransfer(final FileTransfer transfer, final String hostname) { protected Map getAttributesFromFile(FileInfo info) { Map attributes = new HashMap<>(); if (info != null) { - final DateFormat formatter = new SimpleDateFormat(FILE_MODIFY_DATE_ATTR_FORMAT, Locale.US); - attributes.put(FILE_LAST_MODIFY_TIME_ATTRIBUTE, formatter.format(new Date(info.getLastModifiedTime()))); + attributes.put(FILE_LAST_MODIFY_TIME_ATTRIBUTE, DATE_TIME_FORMATTER.format(Instant.ofEpochMilli(info.getLastModifiedTime()).atZone(ZoneId.systemDefault()))); attributes.put(FILE_PERMISSIONS_ATTRIBUTE, info.getPermissions()); attributes.put(FILE_OWNER_ATTRIBUTE, info.getOwner()); attributes.put(FILE_GROUP_ATTRIBUTE, info.getGroup()); diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFileTransfer.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/ListFileTransfer.java similarity index 87% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFileTransfer.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/ListFileTransfer.java index b6fe2fd360d51..1106b27fa37c5 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ListFileTransfer.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/ListFileTransfer.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.nifi.processors.standard; +package org.apache.nifi.processor.util.file.transfer; import org.apache.commons.io.IOUtils; import org.apache.nifi.components.PropertyDescriptor; @@ -24,14 +24,12 @@ import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.util.StandardValidators; import org.apache.nifi.processor.util.list.AbstractListProcessor; -import org.apache.nifi.processors.standard.util.FileInfo; -import org.apache.nifi.processors.standard.util.FileTransfer; import org.apache.nifi.serialization.record.RecordSchema; import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -46,7 +44,7 @@ public abstract class ListFileTransfer extends AbstractListProcessor { .required(true) .expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT) .build(); - static final PropertyDescriptor UNDEFAULTED_PORT = new PropertyDescriptor.Builder() + public static final PropertyDescriptor UNDEFAULTED_PORT = new PropertyDescriptor.Builder() .name("Port") .description("The port to connect to on the remote host to fetch the data from") .addValidator(StandardValidators.NON_EMPTY_VALIDATOR) @@ -76,15 +74,15 @@ public abstract class ListFileTransfer extends AbstractListProcessor { @Override protected Map createAttributes(final FileInfo fileInfo, final ProcessContext context) { final Map attributes = new HashMap<>(); - final DateFormat formatter = new SimpleDateFormat(ListFile.FILE_MODIFY_DATE_ATTR_FORMAT, Locale.US); + final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(GetFileTransfer.FILE_MODIFY_DATE_ATTR_FORMAT, Locale.US); attributes.put(getProtocolName() + ".remote.host", context.getProperty(HOSTNAME).evaluateAttributeExpressions().getValue()); attributes.put(getProtocolName() + ".remote.port", context.getProperty(UNDEFAULTED_PORT).evaluateAttributeExpressions().getValue()); attributes.put(getProtocolName() + ".listing.user", context.getProperty(USERNAME).evaluateAttributeExpressions().getValue()); - attributes.put(ListFile.FILE_LAST_MODIFY_TIME_ATTRIBUTE, formatter.format(new Date(fileInfo.getLastModifiedTime()))); - attributes.put(ListFile.FILE_PERMISSIONS_ATTRIBUTE, fileInfo.getPermissions()); - attributes.put(ListFile.FILE_OWNER_ATTRIBUTE, fileInfo.getOwner()); - attributes.put(ListFile.FILE_GROUP_ATTRIBUTE, fileInfo.getGroup()); - attributes.put(ListFile.FILE_SIZE_ATTRIBUTE, Long.toString(fileInfo.getSize())); + attributes.put(GetFileTransfer.FILE_LAST_MODIFY_TIME_ATTRIBUTE, dateTimeFormatter.format(Instant.ofEpochMilli(fileInfo.getLastModifiedTime()).atZone(ZoneId.systemDefault()))); + attributes.put(GetFileTransfer.FILE_PERMISSIONS_ATTRIBUTE, fileInfo.getPermissions()); + attributes.put(GetFileTransfer.FILE_OWNER_ATTRIBUTE, fileInfo.getOwner()); + attributes.put(GetFileTransfer.FILE_GROUP_ATTRIBUTE, fileInfo.getGroup()); + attributes.put(GetFileTransfer.FILE_SIZE_ATTRIBUTE, Long.toString(fileInfo.getSize())); attributes.put(CoreAttributes.FILENAME.key(), fileInfo.getFileName()); final String fullPath = fileInfo.getFullPathFileName(); if (fullPath != null) { diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/PermissionDeniedException.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/PermissionDeniedException.java similarity index 95% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/PermissionDeniedException.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/PermissionDeniedException.java index 465995e99fc8e..616815ff6adcb 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/PermissionDeniedException.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/PermissionDeniedException.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.nifi.processors.standard.util; +package org.apache.nifi.processor.util.file.transfer; import java.io.IOException; diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFileTransfer.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/PutFileTransfer.java similarity index 98% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFileTransfer.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/PutFileTransfer.java index afb6bb6058d40..353680c595e1c 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/PutFileTransfer.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/main/java/org/apache/nifi/processor/util/file/transfer/PutFileTransfer.java @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.processors.standard; +package org.apache.nifi.processor.util.file.transfer; import org.apache.nifi.flowfile.FlowFile; import org.apache.nifi.flowfile.attributes.CoreAttributes; @@ -26,9 +26,6 @@ import org.apache.nifi.processor.exception.FlowFileAccessException; import org.apache.nifi.processor.exception.ProcessException; import org.apache.nifi.processor.io.InputStreamCallback; -import org.apache.nifi.processors.standard.util.FileInfo; -import org.apache.nifi.processors.standard.util.FileTransfer; -import org.apache.nifi.processors.standard.util.SFTPTransfer; import org.apache.nifi.util.StopWatch; import org.apache.nifi.util.StringUtils; @@ -127,7 +124,7 @@ public void onTrigger(final ProcessContext context, final ProcessSession session @Override public void process(final InputStream in) throws IOException { try (final InputStream bufferedIn = new BufferedInputStream(in)) { - if (workingDirPath != null && context.getProperty(SFTPTransfer.CREATE_DIRECTORY).asBoolean()) { + if (workingDirPath != null && context.getProperty(FileTransfer.CREATE_DIRECTORY).asBoolean()) { transfer.ensureDirectoryExists(flowFileToTransfer, new File(workingDirPath)); } diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestFileInfo.java b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/test/java/org/apache/nifi/processor/util/file/transfer/TestFileInfo.java similarity index 96% rename from nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestFileInfo.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/test/java/org/apache/nifi/processor/util/file/transfer/TestFileInfo.java index ea5ab57cff1a7..922cd89a8be2b 100644 --- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/util/TestFileInfo.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-file-transfer/src/test/java/org/apache/nifi/processor/util/file/transfer/TestFileInfo.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.nifi.processors.standard.util; +package org.apache.nifi.processor.util.file.transfer; import org.junit.jupiter.api.Test; diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-listed-entity/src/main/java/org/apache/nifi/processor/util/list/ListProcessorTestWatcher.java b/nifi-nar-bundles/nifi-extension-utils/nifi-listed-entity/src/main/java/org/apache/nifi/processor/util/list/ListProcessorTestWatcher.java index f76846f3e1597..c79c775effd9f 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-listed-entity/src/main/java/org/apache/nifi/processor/util/list/ListProcessorTestWatcher.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-listed-entity/src/main/java/org/apache/nifi/processor/util/list/ListProcessorTestWatcher.java @@ -24,7 +24,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -45,7 +49,7 @@ public interface Provider { T provide(); } - private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); + private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME; private final Provider> stateMapProvider; private final Provider> entitiesProvider; private final Provider> successFlowFilesProvider; @@ -68,36 +72,39 @@ public void dumpState(final long start) { private void dumpState(Consumer d, final Map state, final List entities, final List flowFiles, final long start) { - final long nTime = System.currentTimeMillis(); + final OffsetDateTime nTime = OffsetDateTime.now(); log(d, "--------------------------------------------------------------------"); log(d, "%-19s %-13s %-23s %s", "", "timestamp", "date from timestamp", "t0 delta"); log(d, "%-19s %-13s %-23s %s", "-------------------", "-------------", "-----------------------", "--------"); - log(d, "%-19s = %13d %s %8d", "started at", start, dateFormat.format(start), 0); - log(d, "%-19s = %13d %s %8d", "current time", nTime, dateFormat.format(nTime), 0); + log(d, "%-19s = %13d %s %8d", "started at", start, dateTimeFormatter.format(Instant.ofEpochMilli(start).atZone(ZoneId.systemDefault())), 0); + log(d, "%-19s = %13d %s %8d", "current time", nTime.toInstant().toEpochMilli(), dateTimeFormatter.format(nTime), 0); log(d, "---- processor state -----------------------------------------------"); if (state.containsKey("processed.timestamp")) { final long pTime = Long.parseLong(state.get("processed.timestamp")); - log(d, "%19s = %13d %s %8d", "processed.timestamp", pTime, dateFormat.format(pTime), pTime - nTime); + final OffsetDateTime processedTime = OffsetDateTime.ofInstant(Instant.ofEpochMilli(pTime), ZoneOffset.UTC); + log(d, "%19s = %13d %s %8d", "processed.timestamp", pTime, dateTimeFormatter.format(processedTime), pTime - nTime.toInstant().toEpochMilli()); } else { log(d, "%19s = na", "processed.timestamp"); } if (state.containsKey("listing.timestamp")) { final long lTime = Long.parseLong(state.get("listing.timestamp")); - log(d, "%19s = %13d %s %8d", "listing.timestamp", lTime, dateFormat.format(lTime), lTime - nTime); + log(d, "%19s = %13d %s %8d", "listing.timestamp", lTime, dateTimeFormatter.format(Instant.ofEpochMilli(lTime).atZone(ZoneId.systemDefault())), lTime - nTime.toInstant().toEpochMilli()); } else { log(d, "%19s = na", "listing.timestamp"); } log(d, "---- input folder contents -----------------------------------------"); entities.sort(Comparator.comparing(ListableEntity::getIdentifier)); for (ListableEntity entity : entities) { - log(d, "%19s = %12d %s %8d", entity.getIdentifier(), entity.getTimestamp(), dateFormat.format(entity.getTimestamp()), entity.getTimestamp() - nTime); + final OffsetDateTime timestamp = OffsetDateTime.ofInstant(Instant.ofEpochMilli(entity.getTimestamp()), ZoneId.systemDefault()); + log(d, "%19s = %12d %s %8d", entity.getIdentifier(), entity.getTimestamp(), dateTimeFormatter.format(timestamp), entity.getTimestamp() - nTime.toInstant().toEpochMilli()); } log(d, "---- output flowfiles ----------------------------------------------"); final Map fileTimes = entities.stream().collect(Collectors.toMap(ListableEntity::getIdentifier, ListableEntity::getTimestamp)); for (FlowFile ff : flowFiles) { String fName = ff.getAttribute(CoreAttributes.FILENAME.key()); Long fTime = fileTimes.get(fName); - log(d, "%19s = %13d %s %8d", fName, fTime, dateFormat.format(fTime), fTime - nTime); + final OffsetDateTime timestamp = OffsetDateTime.ofInstant(Instant.ofEpochMilli(fTime), ZoneId.systemDefault()); + log(d, "%19s = %13d %s %8d", fName, fTime, dateTimeFormatter.format(timestamp), fTime - nTime.toInstant().toEpochMilli()); } log(d, "REL_SUCCESS count = " + flowFiles.size()); log(d, "--------------------------------------------------------------------"); diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-avro-record-utils/src/main/java/org/apache/nifi/avro/AvroTypeUtil.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-avro-record-utils/src/main/java/org/apache/nifi/avro/AvroTypeUtil.java index 9048a59bfc6b3..beb09d48ae7c4 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-avro-record-utils/src/main/java/org/apache/nifi/avro/AvroTypeUtil.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-avro-record-utils/src/main/java/org/apache/nifi/avro/AvroTypeUtil.java @@ -17,23 +17,23 @@ package org.apache.nifi.avro; -import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.sql.Blob; -import java.sql.Time; import java.sql.Timestamp; import java.time.Duration; +import java.time.Instant; import java.time.LocalDate; +import java.time.LocalTime; import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -68,6 +68,8 @@ import org.apache.nifi.serialization.record.RecordSchema; import org.apache.nifi.serialization.record.SchemaIdentifier; import org.apache.nifi.serialization.record.StandardSchemaIdentifier; +import org.apache.nifi.serialization.record.field.FieldConverter; +import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; import org.apache.nifi.serialization.record.type.ArrayDataType; import org.apache.nifi.serialization.record.type.ChoiceDataType; import org.apache.nifi.serialization.record.type.DecimalDataType; @@ -91,6 +93,7 @@ public class AvroTypeUtil { private static final String LOGICAL_TYPE_DECIMAL = "decimal"; private static final String LOGICAL_TYPE_UUID = "uuid"; + private static final long ONE_THOUSAND_MILLISECONDS = 1000; public static Schema extractAvroSchema(final RecordSchema recordSchema) { if (recordSchema == null) { @@ -592,11 +595,11 @@ protected static Pair lookupField(final Schema avroSchema, final return new ImmutablePair<>(fieldName, field); } - public static GenericRecord createAvroRecord(final Record record, final Schema avroSchema) throws IOException { + public static GenericRecord createAvroRecord(final Record record, final Schema avroSchema) { return createAvroRecord(record, avroSchema, StandardCharsets.UTF_8); } - public static GenericRecord createAvroRecord(final Record record, final Schema avroSchema, final Charset charset) throws IOException { + public static GenericRecord createAvroRecord(final Record record, final Schema avroSchema, final Charset charset) { final GenericRecord rec = new GenericData.Record(avroSchema); final RecordSchema recordSchema = record.getSchema(); @@ -692,8 +695,9 @@ private static void addFieldToList(final List recordFields, final F private static Long getLongFromTimestamp(final Object rawValue, final Schema fieldSchema, final String fieldName) { final String format = AvroTypeUtil.determineDataType(fieldSchema).getFormat(); - Timestamp t = DataTypeUtils.toTimestamp(rawValue, () -> DataTypeUtils.getDateFormat(format), fieldName); - return t.getTime(); + final FieldConverter converter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(Timestamp.class); + final Timestamp timestamp = converter.convertField(rawValue, Optional.ofNullable(format), fieldName); + return timestamp.getTime(); } @SuppressWarnings("unchecked") @@ -709,17 +713,15 @@ private static Object convertToAvroObject(final Object rawValue, final Schema fi return DataTypeUtils.toInteger(rawValue, fieldName); } + if (LOGICAL_TYPE_DATE.equals(logicalType.getName())) { final String format = AvroTypeUtil.determineDataType(fieldSchema).getFormat(); - final LocalDate localDate = DataTypeUtils.toLocalDate(rawValue, () -> DataTypeUtils.getDateTimeFormatter(format, ZoneId.systemDefault()), fieldName); + final FieldConverter fieldConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalDate.class); + final LocalDate localDate = fieldConverter.convertField(rawValue, Optional.ofNullable(format), fieldName); return (int) localDate.toEpochDay(); } else if (LOGICAL_TYPE_TIME_MILLIS.equals(logicalType.getName())) { final String format = AvroTypeUtil.determineDataType(fieldSchema).getFormat(); - final Time time = DataTypeUtils.toTime(rawValue, () -> DataTypeUtils.getDateFormat(format), fieldName); - final Date date = new Date(time.getTime()); - final Duration duration = Duration.between(date.toInstant().truncatedTo(ChronoUnit.DAYS), date.toInstant()); - final long millisSinceMidnight = duration.toMillis(); - return (int) millisSinceMidnight; + return getLogicalTimeMillis(rawValue, format, fieldName); } return DataTypeUtils.toInteger(rawValue, fieldName); @@ -731,14 +733,15 @@ private static Object convertToAvroObject(final Object rawValue, final Schema fi } if (LOGICAL_TYPE_TIME_MICROS.equals(logicalType.getName())) { - final long longValue = getLongFromTimestamp(rawValue, fieldSchema, fieldName); - final Date date = new Date(longValue); - final Duration duration = Duration.between(date.toInstant().truncatedTo(ChronoUnit.DAYS), date.toInstant()); - return duration.toMillis() * 1000L; + final long epochMilli = getLongFromTimestamp(rawValue, fieldSchema, fieldName); + final ZonedDateTime zonedDateTime = Instant.ofEpochMilli(epochMilli).atZone(ZoneId.systemDefault()); + final ZonedDateTime midnight = zonedDateTime.truncatedTo(ChronoUnit.DAYS); + final Duration duration = Duration.between(midnight, zonedDateTime); + return duration.toMillis() * ONE_THOUSAND_MILLISECONDS; } else if (LOGICAL_TYPE_TIMESTAMP_MILLIS.equals(logicalType.getName())) { return getLongFromTimestamp(rawValue, fieldSchema, fieldName); } else if (LOGICAL_TYPE_TIMESTAMP_MICROS.equals(logicalType.getName())) { - return getLongFromTimestamp(rawValue, fieldSchema, fieldName) * 1000L; + return getLongFromTimestamp(rawValue, fieldSchema, fieldName) * ONE_THOUSAND_MILLISECONDS; } return DataTypeUtils.toLong(rawValue, fieldName); @@ -1174,4 +1177,13 @@ private static Object normalizeValue(final Object value, final Schema avroSchema return value; } + private static int getLogicalTimeMillis(final Object value, final String format, final String fieldName) { + final FieldConverter fieldConverter = StandardFieldConverterRegistry.getRegistry().getFieldConverter(LocalTime.class); + final LocalTime localTime = fieldConverter.convertField(value, Optional.ofNullable(format), fieldName); + + final LocalTime midnightLocalTime = localTime.truncatedTo(ChronoUnit.DAYS); + final Duration duration = Duration.between(midnightLocalTime, localTime); + final long millisSinceMidnight = duration.toMillis(); + return (int) millisSinceMidnight; + } } diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/pom.xml b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/pom.xml index 6ce68e83cd84f..4cd6a0d6a0a37 100755 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/pom.xml +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/pom.xml @@ -37,7 +37,6 @@ com.jayway.jsonpath json-path - 2.8.0 com.fasterxml.jackson.core diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/AbstractJsonRowRecordReader.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/AbstractJsonRowRecordReader.java index fd3bb71465d77..6daf71a49108b 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/AbstractJsonRowRecordReader.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/AbstractJsonRowRecordReader.java @@ -44,14 +44,13 @@ import java.io.IOException; import java.io.InputStream; -import java.text.DateFormat; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.BiPredicate; -import java.util.function.Supplier; public abstract class AbstractJsonRowRecordReader implements RecordReader { public static final String DEFAULT_MAX_STRING_LENGTH = "20 MB"; @@ -80,9 +79,9 @@ public abstract class AbstractJsonRowRecordReader implements RecordReader { .build(); private final ComponentLog logger; - private final Supplier lazyDateFormat; - private final Supplier lazyTimeFormat; - private final Supplier lazyTimestampFormat; + private final String dateFormat; + private final String timeFormat; + private final String timestampFormat; private boolean firstObjectConsumed = false; private JsonParser jsonParser; @@ -94,13 +93,9 @@ public abstract class AbstractJsonRowRecordReader implements RecordReader { private AbstractJsonRowRecordReader(final ComponentLog logger, final String dateFormat, final String timeFormat, final String timestampFormat) { this.logger = logger; - final DateFormat df = dateFormat == null ? null : DataTypeUtils.getDateFormat(dateFormat); - final DateFormat tf = timeFormat == null ? null : DataTypeUtils.getDateFormat(timeFormat); - final DateFormat tsf = timestampFormat == null ? null : DataTypeUtils.getDateFormat(timestampFormat); - - lazyDateFormat = () -> df; - lazyTimeFormat = () -> tf; - lazyTimestampFormat = () -> tsf; + this.dateFormat = dateFormat; + this.timeFormat = timeFormat; + this.timestampFormat = timestampFormat; } /** @@ -170,16 +165,16 @@ protected AbstractJsonRowRecordReader(final InputStream in, } } - protected Supplier getLazyDateFormat() { - return lazyDateFormat; + protected Optional getDateFormat() { + return Optional.ofNullable(dateFormat); } - protected Supplier getLazyTimeFormat() { - return lazyTimeFormat; + protected Optional getTimeFormat() { + return Optional.ofNullable(timeFormat); } - protected Supplier getLazyTimestampFormat() { - return lazyTimestampFormat; + protected Optional getTimestampFormat() { + return Optional.ofNullable(timestampFormat); } @@ -238,7 +233,7 @@ protected Object getRawNodeValue(final JsonNode fieldNode, final DataType dataTy case TIME: case TIMESTAMP: try { - return DataTypeUtils.convertType(textValue, dataType, lazyDateFormat, lazyTimeFormat, lazyTimestampFormat, fieldName); + return DataTypeUtils.convertType(textValue, dataType, Optional.ofNullable(dateFormat), Optional.ofNullable(timeFormat), Optional.ofNullable(timestampFormat), fieldName); } catch (final Exception e) { return textValue; } diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonPathRowRecordReader.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonPathRowRecordReader.java index bc9ba69800a6d..42f956daab5a6 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonPathRowRecordReader.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonPathRowRecordReader.java @@ -196,7 +196,7 @@ record = true; case UUID: case TIMESTAMP: try { - return DataTypeUtils.convertType(value, dataType, getLazyDateFormat(), getLazyTimeFormat(), getLazyTimestampFormat(), fieldName); + return DataTypeUtils.convertType(value, dataType, getDateFormat(), getTimeFormat(), getTimestampFormat(), fieldName); } catch (final Exception e) { return value; } @@ -249,7 +249,7 @@ protected Object convert(final Object value, final DataType dataType, final Stri return new MapRecord(childSchema, coercedValues); } else { - return DataTypeUtils.convertType(value, dataType, getLazyDateFormat(), getLazyTimeFormat(), getLazyTimestampFormat(), fieldName); + return DataTypeUtils.convertType(value, dataType, getDateFormat(), getTimeFormat(), getTimestampFormat(), fieldName); } } diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonTreeRowRecordReader.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonTreeRowRecordReader.java index 489474e804dcc..a8dc6c4e3ae87 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonTreeRowRecordReader.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/JsonTreeRowRecordReader.java @@ -217,7 +217,7 @@ protected Object convertField(final JsonNode fieldNode, final String fieldName, case UUID: case TIMESTAMP: { final Object rawValue = getRawNodeValue(fieldNode, fieldName); - return DataTypeUtils.convertType(rawValue, desiredType, getLazyDateFormat(), getLazyTimeFormat(), getLazyTimestampFormat(), fieldName); + return DataTypeUtils.convertType(rawValue, desiredType, getDateFormat(), getTimeFormat(), getTimestampFormat(), fieldName); } case MAP: { final DataType valueType = ((MapDataType) desiredType).getValueType(); diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/WriteJsonResult.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/WriteJsonResult.java index 61eb1b2d45b41..065c43823ef10 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/WriteJsonResult.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-json-record-utils/src/main/java/org/apache/nifi/json/WriteJsonResult.java @@ -34,6 +34,8 @@ import org.apache.nifi.serialization.record.RecordFieldType; import org.apache.nifi.serialization.record.RecordSchema; import org.apache.nifi.serialization.record.SerializedForm; +import org.apache.nifi.serialization.record.field.FieldConverter; +import org.apache.nifi.serialization.record.field.StandardFieldConverterRegistry; import org.apache.nifi.serialization.record.type.ArrayDataType; import org.apache.nifi.serialization.record.type.ChoiceDataType; import org.apache.nifi.serialization.record.type.MapDataType; @@ -43,24 +45,23 @@ import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.function.Supplier; public class WriteJsonResult extends AbstractRecordSetWriter implements RecordSetWriter, RawRecordWriter { + private static final FieldConverter STRING_FIELD_CONVERTER = StandardFieldConverterRegistry.getRegistry().getFieldConverter(String.class); + private final ComponentLog logger; private final SchemaAccessWriter schemaAccess; private final RecordSchema recordSchema; private final JsonGenerator generator; private final NullSuppression nullSuppression; private final OutputGrouping outputGrouping; - private final Supplier LAZY_DATE_FORMAT; - private final Supplier LAZY_TIME_FORMAT; - private final Supplier LAZY_TIMESTAMP_FORMAT; - private String mimeType = "application/json"; + private final String dateFormat; + private final String timeFormat; + private final String timestampFormat; + private final String mimeType; private final boolean prettyPrint; private static final ObjectMapper objectMapper = new ObjectMapper(); @@ -82,14 +83,9 @@ public WriteJsonResult(final ComponentLog logger, final RecordSchema recordSchem this.outputGrouping = outputGrouping; this.mimeType = mimeType; - // Use DateFormat with default TimeZone to avoid unexpected conversion of year-month-day - final DateFormat df = dateFormat == null ? null : new SimpleDateFormat(dateFormat); - final DateFormat tf = timeFormat == null ? null : DataTypeUtils.getDateFormat(timeFormat); - final DateFormat tsf = timestampFormat == null ? null : DataTypeUtils.getDateFormat(timestampFormat); - - LAZY_DATE_FORMAT = () -> df; - LAZY_TIME_FORMAT = () -> tf; - LAZY_TIMESTAMP_FORMAT = () -> tsf; + this.dateFormat = dateFormat; + this.timeFormat = timeFormat; + this.timestampFormat = timestampFormat; final JsonFactory factory = new JsonFactory(); factory.setCodec(objectMapper); @@ -251,8 +247,7 @@ private void writeRawValue(final JsonGenerator generator, final Object value, fi return; } - if (value instanceof Record) { - final Record record = (Record) value; + if (value instanceof Record record) { writeRecord(record, record.getSchema(), generator, JsonGenerator::writeStartObject, JsonGenerator::writeEndObject, false); return; } @@ -272,8 +267,7 @@ private void writeRawValue(final JsonGenerator generator, final Object value, fi return; } - if (value instanceof Object[]) { - final Object[] values = (Object[]) value; + if (value instanceof Object[] values) { generator.writeStartArray(); for (final Object element : values) { writeRawValue(generator, element, fieldName); @@ -283,17 +277,17 @@ private void writeRawValue(final JsonGenerator generator, final Object value, fi } if (value instanceof java.sql.Time) { - final Object formatted = format((java.sql.Time) value, LAZY_TIME_FORMAT); + final Object formatted = STRING_FIELD_CONVERTER.convertField(value, Optional.ofNullable(timeFormat), fieldName); generator.writeObject(formatted); return; } if (value instanceof java.sql.Date) { - final Object formatted = format((java.sql.Date) value, LAZY_DATE_FORMAT); + final Object formatted = STRING_FIELD_CONVERTER.convertField(value, Optional.ofNullable(dateFormat), fieldName); generator.writeObject(formatted); return; } if (value instanceof java.util.Date) { - final Object formatted = format((java.util.Date) value, LAZY_TIMESTAMP_FORMAT); + final Object formatted = STRING_FIELD_CONVERTER.convertField(value, Optional.ofNullable(timestampFormat), fieldName); generator.writeObject(formatted); return; } @@ -301,22 +295,6 @@ private void writeRawValue(final JsonGenerator generator, final Object value, fi generator.writeObject(value); } - private Object format(final java.util.Date value, final Supplier formatSupplier) { - if (value == null) { - return null; - } - - if (formatSupplier == null) { - return value.getTime(); - } - final DateFormat format = formatSupplier.get(); - if (format == null) { - return value.getTime(); - } - - return format.format(value); - } - @SuppressWarnings("unchecked") private void writeValue(final JsonGenerator generator, final Object value, final String fieldName, final DataType dataType) throws IOException { if (value == null) { @@ -326,12 +304,14 @@ private void writeValue(final JsonGenerator generator, final Object value, final final DataType chosenDataType = dataType.getFieldType() == RecordFieldType.CHOICE ? DataTypeUtils.chooseDataType(value, (ChoiceDataType) dataType) : dataType; if (chosenDataType == null) { - logger.debug("Could not find a suitable field type in the CHOICE for field {} and value {}; will use null value", new Object[] {fieldName, value}); + logger.debug("Could not find a suitable field type in the CHOICE for field {} and value {}; will use null value", fieldName, value); generator.writeNull(); return; } - final Object coercedValue = DataTypeUtils.convertType(value, chosenDataType, LAZY_DATE_FORMAT, LAZY_TIME_FORMAT, LAZY_TIMESTAMP_FORMAT, fieldName); + final Object coercedValue = DataTypeUtils.convertType( + value, chosenDataType, Optional.ofNullable(dateFormat), Optional.ofNullable(timeFormat), Optional.ofNullable(timestampFormat), fieldName + ); if (coercedValue == null) { generator.writeNull(); return; @@ -339,7 +319,7 @@ private void writeValue(final JsonGenerator generator, final Object value, final switch (chosenDataType.getFieldType()) { case DATE: { - final String stringValue = DataTypeUtils.toString(coercedValue, LAZY_DATE_FORMAT); + final String stringValue = STRING_FIELD_CONVERTER.convertField(coercedValue, Optional.ofNullable(dateFormat), fieldName); if (DataTypeUtils.isLongTypeCompatible(stringValue)) { generator.writeNumber(DataTypeUtils.toLong(coercedValue, fieldName)); } else { @@ -348,7 +328,7 @@ private void writeValue(final JsonGenerator generator, final Object value, final break; } case TIME: { - final String stringValue = DataTypeUtils.toString(coercedValue, LAZY_TIME_FORMAT); + final String stringValue = STRING_FIELD_CONVERTER.convertField(coercedValue, Optional.ofNullable(timeFormat), fieldName); if (DataTypeUtils.isLongTypeCompatible(stringValue)) { generator.writeNumber(DataTypeUtils.toLong(coercedValue, fieldName)); } else { @@ -357,7 +337,7 @@ private void writeValue(final JsonGenerator generator, final Object value, final break; } case TIMESTAMP: { - final String stringValue = DataTypeUtils.toString(coercedValue, LAZY_TIMESTAMP_FORMAT); + final String stringValue = STRING_FIELD_CONVERTER.convertField(coercedValue, Optional.ofNullable(timestampFormat), fieldName); if (DataTypeUtils.isLongTypeCompatible(stringValue)) { generator.writeNumber(DataTypeUtils.toLong(coercedValue, fieldName)); } else { @@ -389,7 +369,7 @@ private void writeValue(final JsonGenerator generator, final Object value, final break; case BIGINT: if (coercedValue instanceof Long) { - generator.writeNumber(((Long) coercedValue).longValue()); + generator.writeNumber((Long) coercedValue); } else { generator.writeNumber((BigInteger) coercedValue); } @@ -428,8 +408,7 @@ private void writeValue(final JsonGenerator generator, final Object value, final } case ARRAY: default: - if (coercedValue instanceof Object[]) { - final Object[] values = (Object[]) coercedValue; + if (coercedValue instanceof Object[] values) { final ArrayDataType arrayDataType = (ArrayDataType) chosenDataType; final DataType elementType = arrayDataType.getElementType(); writeArray(values, fieldName, generator, elementType); diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/SimpleDateFormatValidator.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeFormatValidator.java similarity index 91% rename from nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/SimpleDateFormatValidator.java rename to nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeFormatValidator.java index f25749bfe4bd8..cd1db13c8eebe 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/SimpleDateFormatValidator.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeFormatValidator.java @@ -17,18 +17,18 @@ package org.apache.nifi.serialization; -import java.text.SimpleDateFormat; - import org.apache.nifi.components.ValidationContext; import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.Validator; -public class SimpleDateFormatValidator implements Validator { +import java.time.format.DateTimeFormatter; + +public class DateTimeFormatValidator implements Validator { @Override public ValidationResult validate(final String subject, final String input, final ValidationContext context) { try { - new SimpleDateFormat(input); + DateTimeFormatter.ofPattern(input); } catch (final Exception e) { return new ValidationResult.Builder() .input(input) @@ -44,5 +44,4 @@ public ValidationResult validate(final String subject, final String input, final .valid(true) .build(); } - } diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeUtils.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeUtils.java index 45b3f9368b4a0..03b768a79722a 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeUtils.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/main/java/org/apache/nifi/serialization/DateTimeUtils.java @@ -28,7 +28,7 @@ public class DateTimeUtils { + "If specified, the value must match the Java Simple Date Format (for example, MM/dd/yyyy for a two-digit month, followed by " + "a two-digit day, followed by a four-digit year, all separated by '/' characters, as in 01/01/2017).") .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .addValidator(new SimpleDateFormatValidator()) + .addValidator(new DateTimeFormatValidator()) .required(false) .build(); @@ -39,7 +39,7 @@ public class DateTimeUtils { + "If specified, the value must match the Java Simple Date Format (for example, HH:mm:ss for a two-digit hour in 24-hour format, followed by " + "a two-digit minute, followed by a two-digit second, all separated by ':' characters, as in 18:04:15).") .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .addValidator(new SimpleDateFormatValidator()) + .addValidator(new DateTimeFormatValidator()) .required(false) .build(); @@ -51,7 +51,7 @@ public class DateTimeUtils { + "a two-digit day, followed by a four-digit year, all separated by '/' characters; and then followed by a two-digit hour in 24-hour format, followed by " + "a two-digit minute, followed by a two-digit second, all separated by ':' characters, as in 01/01/2017 18:04:15).") .expressionLanguageSupported(ExpressionLanguageScope.NONE) - .addValidator(new SimpleDateFormatValidator()) + .addValidator(new DateTimeFormatValidator()) .required(false) .build(); } diff --git a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/test/java/org/apache/nifi/schema/validation/TestStandardSchemaValidator.java b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/test/java/org/apache/nifi/schema/validation/TestStandardSchemaValidator.java index f8467f9a74b51..a35d436f5000a 100644 --- a/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/test/java/org/apache/nifi/schema/validation/TestStandardSchemaValidator.java +++ b/nifi-nar-bundles/nifi-extension-utils/nifi-record-utils/nifi-standard-record-utils/src/test/java/org/apache/nifi/schema/validation/TestStandardSchemaValidator.java @@ -35,9 +35,6 @@ import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -48,7 +45,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TimeZone; import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -75,7 +71,7 @@ public class TestStandardSchemaValidator { )); @Test - public void testValidateCorrectSimpleTypesStrictValidation() throws ParseException { + public void testValidateCorrectSimpleTypesStrictValidation() { final List fields = new ArrayList<>(); for (final RecordFieldType fieldType : RecordFieldType.values()) { if (fieldType == RecordFieldType.CHOICE) { @@ -97,9 +93,7 @@ public void testValidateCorrectSimpleTypesStrictValidation() throws ParseExcepti } } - final DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS"); - df.setTimeZone(TimeZone.getTimeZone("gmt")); - final long time = df.parse("2017/01/01 17:00:00.000").getTime(); + final long time = 1483290000000L; final Map intMap = new LinkedHashMap<>(); intMap.put("height", 48); @@ -229,7 +223,7 @@ public void testDoubleBelowFloatRangeIsConsideredAsInvalid() { } @Test - public void testValidateWrongButCoerceableType() throws ParseException { + public void testValidateWrongButCoerceableType() { final List fields = new ArrayList<>(); fields.add(new RecordField("id", RecordFieldType.INT.getDataType())); final RecordSchema schema = new SimpleRecordSchema(fields); diff --git a/nifi-nar-bundles/nifi-extension-utils/pom.xml b/nifi-nar-bundles/nifi-extension-utils/pom.xml index f77ab77313f29..186c64c47e1f4 100644 --- a/nifi-nar-bundles/nifi-extension-utils/pom.xml +++ b/nifi-nar-bundles/nifi-extension-utils/pom.xml @@ -34,6 +34,7 @@ nifi-event-listen nifi-event-put nifi-event-transport + nifi-file-transfer nifi-hadoop-utils nifi-kerberos-test-utils nifi-listed-entity diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/pom.xml index 3cf9833369f7b..83d8854bb1fc2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/pom.xml @@ -23,7 +23,7 @@ nifi-client-dto - io.swagger + io.swagger.core.v3 swagger-annotations diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AboutDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AboutDTO.java index b75ba46dd8e4b..e45d1cd38c13f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AboutDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AboutDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import org.apache.nifi.web.api.dto.util.TimezoneAdapter; @@ -48,8 +48,7 @@ public class AboutDTO { * * @return The title */ - @ApiModelProperty( - value = "The title to be used on the page and in the about dialog." + @Schema(description = "The title to be used on the page and in the about dialog." ) public String getTitle() { return title; @@ -64,8 +63,7 @@ public void setTitle(String title) { * * @return The version. */ - @ApiModelProperty( - value = "The version of this NiFi." + @Schema(description = "The version of this NiFi." ) public String getVersion() { return version; @@ -78,8 +76,7 @@ public void setVersion(String version) { /** * @return URI for this NiFi controller */ - @ApiModelProperty( - value = "The URI for the NiFi." + @Schema(description = "The URI for the NiFi." ) public String getUri() { return uri; @@ -92,8 +89,7 @@ public void setUri(String uri) { /** * @return the URL for the content viewer if configured */ - @ApiModelProperty( - value = "The URL for the content viewer if configured." + @Schema(description = "The URL for the content viewer if configured." ) public String getContentViewerUrl() { return contentViewerUrl; @@ -107,10 +103,9 @@ public void setContentViewerUrl(String contentViewerUrl) { * @return the timezone of the NiFi instance */ @XmlJavaTypeAdapter(TimezoneAdapter.class) - @ApiModelProperty( - value = "The timezone of the NiFi instance.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, - dataType = "string" + @Schema(description = "The timezone of the NiFi instance.", + accessMode = Schema.AccessMode.READ_ONLY, + type = "string" ) public Date getTimezone() { return timezone; @@ -120,8 +115,7 @@ public void setTimezone(Date timezone) { this.timezone = timezone; } - @ApiModelProperty( - value = "Build tag" + @Schema(description = "Build tag" ) public String getBuildTag() { return buildTag; @@ -131,8 +125,7 @@ public void setBuildTag(String buildTag) { this.buildTag = buildTag; } - @ApiModelProperty( - value = "Build revision or commit hash" + @Schema(description = "Build revision or commit hash" ) public String getBuildRevision() { return buildRevision; @@ -142,8 +135,7 @@ public void setBuildRevision(String buildRevision) { this.buildRevision = buildRevision; } - @ApiModelProperty( - value = "Build branch" + @Schema(description = "Build branch" ) public String getBuildBranch() { return buildBranch; @@ -154,9 +146,8 @@ public void setBuildBranch(String buildBranch) { } @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "Build timestamp", - dataType = "string" + @Schema(description = "Build timestamp", + type = "string" ) public Date getBuildTimestamp() { return buildTimestamp; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessConfigurationDTO.java index bebd34c3b7481..79cd87a64d075 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessConfigurationDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,9 +31,8 @@ public class AccessConfigurationDTO { /** * @return Indicates whether or not this NiFi supports user login. */ - @ApiModelProperty( - value = "Indicates whether or not this NiFi supports user login.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Indicates whether or not this NiFi supports user login.", + accessMode = Schema.AccessMode.READ_ONLY ) public Boolean getSupportsLogin() { return supportsLogin; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java index f2145d8b72799..367d5fe51b50b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.TenantEntity; import jakarta.xml.bind.annotation.XmlType; @@ -34,7 +34,7 @@ public class AccessPolicyDTO extends AccessPolicySummaryDTO { /** * @return The set of user IDs associated with this access policy. */ - @ApiModelProperty(value = "The set of user IDs associated with this access policy.") + @Schema(description = "The set of user IDs associated with this access policy.") public Set getUsers() { return users; } @@ -46,7 +46,7 @@ public void setUsers(Set users) { /** * @return The set of user group IDs associated with this access policy. */ - @ApiModelProperty(value = "The set of user group IDs associated with this access policy.") + @Schema(description = "The set of user group IDs associated with this access policy.") public Set getUserGroups() { return userGroups; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicySummaryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicySummaryDTO.java index 091b8656a689a..07da700c06909 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicySummaryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicySummaryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ComponentReferenceEntity; import jakarta.xml.bind.annotation.XmlType; @@ -35,8 +35,7 @@ public class AccessPolicySummaryDTO extends ComponentDTO { /** * @return The action associated with this access policy. */ - @ApiModelProperty( - value = "The action associated with this access policy.", + @Schema(description = "The action associated with this access policy.", allowableValues = "read, write" ) public String getAction() { @@ -50,7 +49,7 @@ public void setAction(String action) { /** * @return The resource for this access policy. */ - @ApiModelProperty(value="The resource for this access policy.") + @Schema(description = "The resource for this access policy.") public String getResource() { return resource; } @@ -62,7 +61,7 @@ public void setResource(String resource) { /** * @return Component this policy references if applicable. */ - @ApiModelProperty(value="Component this policy references if applicable.") + @Schema(description = "Component this policy references if applicable.") public ComponentReferenceEntity getComponentReference() { return componentReference; } @@ -74,7 +73,7 @@ public void setComponentReference(ComponentReferenceEntity componentReference) { /** * @return whether this policy is configurable */ - @ApiModelProperty(value = "Whether this policy is configurable.") + @Schema(description = "Whether this policy is configurable.") public Boolean getConfigurable() { return configurable; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessStatusDTO.java index 404e5bd735441..92410c504a7c8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; @@ -40,9 +40,8 @@ public static enum Status { /** * @return the user identity */ - @ApiModelProperty( - value = "The user identity.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The user identity.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getIdentity() { return identity; @@ -55,9 +54,8 @@ public void setIdentity(String identity) { /** * @return the user access status */ - @ApiModelProperty( - value = "The user access status.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The user access status.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getStatus() { return status; @@ -70,9 +68,8 @@ public void setStatus(String status) { /** * @return additional details about the user access status */ - @ApiModelProperty( - value = "Additional details about the user access status.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Additional details about the user access status.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getMessage() { return message; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessTokenExpirationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessTokenExpirationDTO.java index db7682f3978b2..c95c484d578fe 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessTokenExpirationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessTokenExpirationDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.InstantAdapter; import jakarta.xml.bind.annotation.XmlRootElement; @@ -29,10 +29,9 @@ public class AccessTokenExpirationDTO { private Instant expiration; @XmlJavaTypeAdapter(InstantAdapter.class) - @ApiModelProperty( - value = "Token Expiration", - dataType = "string", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Token Expiration", + type = "string", + accessMode = Schema.AccessMode.READ_ONLY ) public Instant getExpiration() { return expiration; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AffectedComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AffectedComponentDTO.java index 82892021762f0..44f3024f88a5a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AffectedComponentDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AffectedComponentDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -41,7 +41,7 @@ public class AffectedComponentDTO { private Collection validationErrors; - @ApiModelProperty("The UUID of the Process Group that this component is in") + @Schema(description = "The UUID of the Process Group that this component is in") public String getProcessGroupId() { return processGroupId; } @@ -50,7 +50,7 @@ public void setProcessGroupId(final String processGroupId) { this.processGroupId = processGroupId; } - @ApiModelProperty("The UUID of this component") + @Schema(description = "The UUID of this component") public String getId() { return id; } @@ -59,7 +59,7 @@ public void setId(final String id) { this.id = id; } - @ApiModelProperty(value = "The type of this component", + @Schema(description = "The type of this component", allowableValues = COMPONENT_TYPE_PROCESSOR + "," + COMPONENT_TYPE_CONTROLLER_SERVICE + ", " + COMPONENT_TYPE_INPUT_PORT + ", " + COMPONENT_TYPE_OUTPUT_PORT + ", " + COMPONENT_TYPE_REMOTE_INPUT_PORT + ", " + COMPONENT_TYPE_REMOTE_OUTPUT_PORT + ", " + COMPONENT_TYPE_STATELESS_GROUP) @@ -71,7 +71,7 @@ public void setReferenceType(final String referenceType) { this.referenceType = referenceType; } - @ApiModelProperty("The name of this component.") + @Schema(description = "The name of this component.") public String getName() { return name; } @@ -83,8 +83,7 @@ public void setName(String name) { /** * @return active thread count for the referencing component */ - @ApiModelProperty( - value = "The number of active threads for the referencing component." + @Schema(description = "The number of active threads for the referencing component." ) public Integer getActiveThreadCount() { return activeThreadCount; @@ -97,8 +96,7 @@ public void setActiveThreadCount(Integer activeThreadCount) { /** * @return Any validation error associated with this component */ - @ApiModelProperty( - value = "The validation errors for the component." + @Schema(description = "The validation errors for the component." ) public Collection getValidationErrors() { return validationErrors; @@ -108,7 +106,7 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty("The scheduled state of a processor or reporting task referencing a controller service. If this component is another controller " + @Schema(description = "The scheduled state of a processor or reporting task referencing a controller service. If this component is another controller " + "service, this field represents the controller service state.") public String getState() { return state; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AllowableValueDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AllowableValueDTO.java index 606e9f9be15fa..2d15bffb7edbc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AllowableValueDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AllowableValueDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class AllowableValueDTO { /** * @return the human-readable value that is allowed for this PropertyDescriptor */ - @ApiModelProperty( - value = "A human readable value that is allowed for the property descriptor." + @Schema(description = "A human readable value that is allowed for the property descriptor." ) public String getDisplayName() { return displayName; @@ -47,8 +46,7 @@ public void setDisplayName(String displayName) { /** * @return the value for this allowable value */ - @ApiModelProperty( - value = "A value that is allowed for the property descriptor." + @Schema(description = "A value that is allowed for the property descriptor." ) public String getValue() { return value; @@ -61,8 +59,7 @@ public void setValue(String value) { /** * @return a description of this Allowable Value, or null if no description is given */ - @ApiModelProperty( - value = "A description for this allowable value." + @Schema(description = "A description for this allowable value." ) public String getDescription() { return description; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AnalyzeFlowRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AnalyzeFlowRequestDTO.java index 7157fba199225..188c1a1da2ba0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AnalyzeFlowRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AnalyzeFlowRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -35,7 +35,7 @@ public AnalyzeFlowRequestDTO() { * * @return The id */ - @ApiModelProperty("The id of the process group representing (a part of) the flow to be analyzed.") + @Schema(description = "The id of the process group representing (a part of) the flow to be analyzed.") public String getProcessGroupId() { return this.processGroupId; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AsynchronousRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AsynchronousRequestDTO.java index 5f3f1ad176284..de7608aa23450 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AsynchronousRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AsynchronousRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @@ -35,7 +35,7 @@ public abstract class AsynchronousRequestDTO { private List updateSteps; - @ApiModelProperty(value = "The ID of the request", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The ID of the request", accessMode = Schema.AccessMode.READ_ONLY) public String getRequestId() { return requestId; } @@ -44,7 +44,7 @@ public void setRequestId(final String requestId) { this.requestId = requestId; } - @ApiModelProperty(value = "The URI for the request", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The URI for the request", accessMode = Schema.AccessMode.READ_ONLY) public String getUri() { return uri; } @@ -54,7 +54,7 @@ public void setUri(final String uri) { } @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty(value = "The timestamp of when the request was submitted", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The timestamp of when the request was submitted", accessMode = Schema.AccessMode.READ_ONLY) public Date getSubmissionTime() { return submissionTime; } @@ -64,7 +64,7 @@ public void setSubmissionTime(final Date submissionTime) { } @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty(value = "The timestamp of when the request was last updated", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The timestamp of when the request was last updated", accessMode = Schema.AccessMode.READ_ONLY) public Date getLastUpdated() { return lastUpdated; } @@ -73,7 +73,7 @@ public void setLastUpdated(final Date lastUpdated) { this.lastUpdated = lastUpdated; } - @ApiModelProperty(value = "Whether or not the request is completed", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Whether or not the request is completed", accessMode = Schema.AccessMode.READ_ONLY) public boolean isComplete() { return complete; } @@ -82,7 +82,7 @@ public void setComplete(final boolean complete) { this.complete = complete; } - @ApiModelProperty(value = "The reason for the request failing, or null if the request has not failed", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The reason for the request failing, or null if the request has not failed", accessMode = Schema.AccessMode.READ_ONLY) public String getFailureReason() { return failureReason; } @@ -91,7 +91,7 @@ public void setFailureReason(final String failureReason) { this.failureReason = failureReason; } - @ApiModelProperty(value = "A value between 0 and 100 (inclusive) indicating how close the request is to completion", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "A value between 0 and 100 (inclusive) indicating how close the request is to completion", accessMode = Schema.AccessMode.READ_ONLY) public int getPercentCompleted() { return percentCompleted; } @@ -100,7 +100,7 @@ public void setPercentCompleted(final int percentCompleted) { this.percentCompleted = percentCompleted; } - @ApiModelProperty(value = "A description of the current state of the request", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "A description of the current state of the request", accessMode = Schema.AccessMode.READ_ONLY) public String getState() { return state; } @@ -109,7 +109,7 @@ public void setState(final String state) { this.state = state; } - @ApiModelProperty(value = "The steps that are required in order to complete the request, along with the status of each", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The steps that are required in order to complete the request, along with the status of each", accessMode = Schema.AccessMode.READ_ONLY) public List getUpdateSteps() { return updateSteps; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BannerDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BannerDTO.java index 1b2d797a259ba..ae1008806f414 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BannerDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BannerDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -35,8 +35,7 @@ public class BannerDTO { * * @return The footer text */ - @ApiModelProperty( - value = "The footer text." + @Schema(description = "The footer text." ) public String getFooterText() { return footerText; @@ -51,8 +50,7 @@ public void setFooterText(String footerText) { * * @return The header text */ - @ApiModelProperty( - value = "The header text." + @Schema(description = "The header text." ) public String getHeaderText() { return headerText; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BatchSettingsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BatchSettingsDTO.java index f5cafe443dff0..6b004cac8a72c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BatchSettingsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BatchSettingsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class BatchSettingsDTO { /** * @return preferred number of flow files to include in a transaction */ - @ApiModelProperty( - value = "Preferred number of flow files to include in a transaction." + @Schema(description = "Preferred number of flow files to include in a transaction." ) public Integer getCount() { return count; @@ -47,8 +46,7 @@ public void setCount(Integer count) { /** * @return preferred number of bytes to include in a transaction */ - @ApiModelProperty( - value = "Preferred number of bytes to include in a transaction." + @Schema(description = "Preferred number of bytes to include in a transaction." ) public String getSize() { return size; @@ -61,8 +59,7 @@ public void setSize(String size) { /** * @return preferred amount of time that a transaction should span */ - @ApiModelProperty( - value = "Preferred amount of time that a transaction should span." + @Schema(description = "Preferred amount of time that a transaction should span." ) public String getDuration() { return duration; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinBoardDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinBoardDTO.java index dcd74d8a0a229..79bd3da676442 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinBoardDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinBoardDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import org.apache.nifi.web.api.entity.BulletinEntity; @@ -37,8 +37,7 @@ public class BulletinBoardDTO { /** * @return bulletins to populate in the bulletin board */ - @ApiModelProperty( - value = "The bulletins in the bulletin board, that matches the supplied request." + @Schema(description = "The bulletins in the bulletin board, that matches the supplied request." ) public List getBulletins() { return bulletins; @@ -52,9 +51,8 @@ public void setBulletins(List bulletins) { * @return when this bulletin board was generated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The timestamp when this report was generated.", - dataType = "string" + @Schema(description = "The timestamp when this report was generated.", + type = "string" ) public Date getGenerated() { return generated; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinDTO.java index 64c3e6417b058..6f5cc39547d8f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -43,8 +43,7 @@ public class BulletinDTO { /** * @return id of this message */ - @ApiModelProperty( - value = "The id of the bulletin." + @Schema(description = "The id of the bulletin." ) public Long getId() { return id; @@ -57,8 +56,7 @@ public void setId(Long id) { /** * @return When clustered, the address of the node from which this bulletin originated */ - @ApiModelProperty( - value = "If clustered, the address of the node from which the bulletin originated." + @Schema(description = "If clustered, the address of the node from which the bulletin originated." ) public String getNodeAddress() { return nodeAddress; @@ -71,8 +69,7 @@ public void setNodeAddress(String nodeAddress) { /** * @return group id of the source component */ - @ApiModelProperty( - value = "The group id of the source component." + @Schema(description = "The group id of the source component." ) public String getGroupId() { return groupId; @@ -85,8 +82,7 @@ public void setGroupId(String groupId) { /** * @return category of this message */ - @ApiModelProperty( - value = "The category of this bulletin." + @Schema(description = "The category of this bulletin." ) public String getCategory() { return category; @@ -99,8 +95,7 @@ public void setCategory(String category) { /** * @return actual message */ - @ApiModelProperty( - value = "The bulletin message." + @Schema(description = "The bulletin message." ) public String getMessage() { return message; @@ -113,8 +108,7 @@ public void setMessage(String message) { /** * @return id of the source of this message */ - @ApiModelProperty( - value = "The id of the source component." + @Schema(description = "The id of the source component." ) public String getSourceId() { return sourceId; @@ -127,8 +121,7 @@ public void setSourceId(String sourceId) { /** * @return name of the source of this message */ - @ApiModelProperty( - value = "The name of the source component." + @Schema(description = "The name of the source component." ) public String getSourceName() { return sourceName; @@ -141,8 +134,7 @@ public void setSourceName(String sourceName) { /** * @return level of this bulletin */ - @ApiModelProperty( - value = "The level of the bulletin." + @Schema(description = "The level of the bulletin." ) public String getLevel() { return level; @@ -156,9 +148,8 @@ public void setLevel(String level) { * @return When this bulletin was generated as a formatted string */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "When this bulletin was generated.", - dataType = "string" + @Schema(description = "When this bulletin was generated.", + type = "string" ) public Date getTimestamp() { return timestamp; @@ -168,8 +159,7 @@ public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } - @ApiModelProperty( - value = "The type of the source component" + @Schema(description = "The type of the source component" ) public String getSourceType() { return sourceType; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinQueryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinQueryDTO.java index 97ca4bb165c31..8bdd512225ccb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinQueryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BulletinQueryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -36,8 +36,7 @@ public class BulletinQueryDTO { /** * @return Include bulletins after this id */ - @ApiModelProperty( - value = "Will include bulletins that occurred after this id. The ids are a one-up number that are used to ensure bulletins that " + @Schema(description = "Will include bulletins that occurred after this id. The ids are a one-up number that are used to ensure bulletins that " + "occur at the same time will not be missed." ) public Long getAfter() { @@ -51,8 +50,7 @@ public void setAfter(Long after) { /** * @return Include bulletin within this group. Supports a regular expression */ - @ApiModelProperty( - value = "Will include bulletins that occurred within this group. Supports a regular expression." + @Schema(description = "Will include bulletins that occurred within this group. Supports a regular expression." ) public String getGroupId() { return groupId; @@ -65,8 +63,7 @@ public void setGroupId(String groupId) { /** * @return Include bulletins that match this message. Supports a regular expression */ - @ApiModelProperty( - value = "Will include bulletins that match this message. Supports a regular expression." + @Schema(description = "Will include bulletins that match this message. Supports a regular expression." ) public String getMessage() { return message; @@ -79,8 +76,7 @@ public void setMessage(String message) { /** * @return Include bulletins that match this name. Supports a regular expression */ - @ApiModelProperty( - value = "Will include bulletins that match this name. Supports a regular expression." + @Schema(description = "Will include bulletins that match this name. Supports a regular expression." ) public String getName() { return name; @@ -93,8 +89,7 @@ public void setName(String name) { /** * @return Include bulletins that match this id. Supports a source id */ - @ApiModelProperty( - value = "Will include bulletins from components that match this id. Supports a regular expression." + @Schema(description = "Will include bulletins from components that match this id. Supports a regular expression." ) public String getSourceId() { return sourceId; @@ -107,8 +102,7 @@ public void setSourceId(String sourceId) { /** * @return The maximum number of bulletins to return */ - @ApiModelProperty( - value = "The maximum number of bulletins to return." + @Schema(description = "The maximum number of bulletins to return." ) public Integer getLimit() { return limit; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BundleDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BundleDTO.java index 6d7bd1637c9ce..903ef4e7d04d4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BundleDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/BundleDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Objects; @@ -45,8 +45,7 @@ public BundleDTO(final String group, final String artifact, final String version * * @return bundle group */ - @ApiModelProperty( - value = "The group of the bundle." + @Schema(description = "The group of the bundle." ) public String getGroup() { return group; @@ -61,8 +60,7 @@ public void setGroup(String group) { * * @return bundle artifact */ - @ApiModelProperty( - value = "The artifact of the bundle." + @Schema(description = "The artifact of the bundle." ) public String getArtifact() { return artifact; @@ -77,8 +75,7 @@ public void setArtifact(String artifact) { * * @return bundle version */ - @ApiModelProperty( - value = "The version of the bundle." + @Schema(description = "The version of the bundle." ) public String getVersion() { return version; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterDTO.java index d8b6ec9866837..03bb30c3b568b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -36,8 +36,7 @@ public class ClusterDTO { /** * @return collection of the node DTOs */ - @ApiModelProperty( - value = "The collection of nodes that are part of the cluster." + @Schema(description = "The collection of nodes that are part of the cluster." ) public Collection getNodes() { return nodes; @@ -51,9 +50,8 @@ public void setNodes(Collection nodes) { * @return the date/time that this report was generated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The timestamp the report was generated.", - dataType = "string" + @Schema(description = "The timestamp the report was generated.", + type = "string" ) public Date getGenerated() { return generated; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterSummaryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterSummaryDTO.java index bc96302682379..39ff54717bbb8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterSummaryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ClusterSummaryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -36,8 +36,7 @@ public class ClusterSummaryDTO { /** * @return whether this NiFi instance is clustered */ - @ApiModelProperty( - value = "Whether this NiFi instance is clustered." + @Schema(description = "Whether this NiFi instance is clustered." ) public Boolean getClustered() { return isClustered; @@ -50,8 +49,7 @@ public void setClustered(Boolean clustered) { /** * @return whether this NiFi instance is connected to a cluster */ - @ApiModelProperty( - value = "Whether this NiFi instance is connected to a cluster." + @Schema(description = "Whether this NiFi instance is connected to a cluster." ) public Boolean getConnectedToCluster() { return isConnectedToCluster; @@ -61,7 +59,7 @@ public void setConnectedToCluster(Boolean connectedToCluster) { isConnectedToCluster = connectedToCluster; } - @ApiModelProperty("The number of nodes that are currently connected to the cluster") + @Schema(description = "The number of nodes that are currently connected to the cluster") public Integer getConnectedNodeCount() { return connectedNodeCount; } @@ -70,7 +68,7 @@ public void setConnectedNodeCount(Integer connectedNodeCount) { this.connectedNodeCount = connectedNodeCount; } - @ApiModelProperty("The number of nodes in the cluster, regardless of whether or not they are connected") + @Schema(description = "The number of nodes in the cluster, regardless of whether or not they are connected") public Integer getTotalNodeCount() { return totalNodeCount; } @@ -83,7 +81,7 @@ public void setTotalNodeCount(Integer totalNodeCount) { * @return Used in clustering, will report the number of nodes connected vs * the number of nodes in the cluster */ - @ApiModelProperty("When clustered, reports the number of nodes connected vs the number of nodes in the cluster.") + @Schema(description = "When clustered, reports the number of nodes connected vs the number of nodes in the cluster.") public String getConnectedNodes() { return connectedNodes; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java index 6cbb927b7c30d..4dd1a6ab7bd0b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -37,8 +37,7 @@ public class ComponentDTO { * * @return The id */ - @ApiModelProperty( - value = "The id of the component." + @Schema(description = "The id of the component." ) public String getId() { return this.id; @@ -48,7 +47,7 @@ public void setId(final String id) { this.id = id; } - @ApiModelProperty("The ID of the corresponding component that is under version control") + @Schema(description = "The ID of the corresponding component that is under version control") public String getVersionedComponentId() { return versionedComponentId; } @@ -60,8 +59,7 @@ public void setVersionedComponentId(final String id) { /** * @return id for the parent group of this component if applicable, null otherwise */ - @ApiModelProperty( - value = "The id of parent process group of this component if applicable." + @Schema(description = "The id of parent process group of this component if applicable." ) public String getParentGroupId() { return parentGroupId; @@ -76,8 +74,7 @@ public void setParentGroupId(String parentGroupId) { * * @return The position */ - @ApiModelProperty( - value = "The position of this component in the UI if applicable." + @Schema(description = "The position of this component in the UI if applicable." ) public PositionDTO getPosition() { return position; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDifferenceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDifferenceDTO.java index 566a8de454aac..5ac6c30a46c6c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDifferenceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDifferenceDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -31,7 +31,7 @@ public class ComponentDifferenceDTO { private String processGroupId; private List differences; - @ApiModelProperty("The type of component") + @Schema(description = "The type of component") public String getComponentType() { return componentType; } @@ -40,7 +40,7 @@ public void setComponentType(String componentType) { this.componentType = componentType; } - @ApiModelProperty("The ID of the component") + @Schema(description = "The ID of the component") public String getComponentId() { return componentId; } @@ -49,7 +49,7 @@ public void setComponentId(String componentId) { this.componentId = componentId; } - @ApiModelProperty("The name of the component") + @Schema(description = "The name of the component") public String getComponentName() { return componentName; } @@ -58,7 +58,7 @@ public void setComponentName(String componentName) { this.componentName = componentName; } - @ApiModelProperty("The ID of the Process Group that the component belongs to") + @Schema(description = "The ID of the Process Group that the component belongs to") public String getProcessGroupId() { return processGroupId; } @@ -67,7 +67,7 @@ public void setProcessGroupId(String processGroupId) { this.processGroupId = processGroupId; } - @ApiModelProperty("The differences in the component between the two flows") + @Schema(description = "The differences in the component between the two flows") public List getDifferences() { return differences; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentHistoryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentHistoryDTO.java index 796da3380e8e2..240c70dcb1edc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentHistoryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentHistoryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Map; @@ -33,8 +33,7 @@ public class ComponentHistoryDTO { /** * @return component id */ - @ApiModelProperty( - value = "The component id." + @Schema(description = "The component id." ) public String getComponentId() { return componentId; @@ -47,8 +46,7 @@ public void setComponentId(String componentId) { /** * @return history for this components properties */ - @ApiModelProperty( - value = "The history for the properties of the component." + @Schema(description = "The history for the properties of the component." ) public Map getPropertyHistory() { return propertyHistory; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentReferenceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentReferenceDTO.java index 0580adc988e6c..0dccab0474a09 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentReferenceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentReferenceDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -35,8 +35,7 @@ public class ComponentReferenceDTO extends ComponentDTO { * * @return The id */ - @ApiModelProperty( - value = "The id of the component." + @Schema(description = "The id of the component." ) public String getId() { return this.id; @@ -49,8 +48,7 @@ public void setId(final String id) { /** * @return id for the parent group of this component if applicable, null otherwise */ - @ApiModelProperty( - value = "The id of parent process group of this component if applicable." + @Schema(description = "The id of parent process group of this component if applicable." ) public String getParentGroupId() { return parentGroupId; @@ -63,8 +61,7 @@ public void setParentGroupId(String parentGroupId) { /** * @return id for the parent group of this component if applicable, null otherwise */ - @ApiModelProperty( - value = "The name of the component." + @Schema(description = "The name of the component." ) public String getName() { return name; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentRestrictionPermissionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentRestrictionPermissionDTO.java index ff59e17fb8229..b50737487cc34 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentRestrictionPermissionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentRestrictionPermissionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Objects; @@ -33,8 +33,7 @@ public class ComponentRestrictionPermissionDTO { /** * @return The required permission necessary for this restriction. */ - @ApiModelProperty( - value = "The required permission necessary for this restriction." + @Schema(description = "The required permission necessary for this restriction." ) public RequiredPermissionDTO getRequiredPermission() { return requiredPermission; @@ -47,8 +46,7 @@ public void setRequiredPermission(RequiredPermissionDTO requiredPermission) { /** * @return The permissions for this component restriction. */ - @ApiModelProperty( - value = "The permissions for this component restriction. Note: the read permission are not used and will always be false." + @Schema(description = "The permissions for this component restriction. Note: the read permission are not used and will always be false." ) public PermissionsDTO getPermissions() { return permissions; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentStateDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentStateDTO.java index 5ee5848427867..37ba9d13f2452 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentStateDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentStateDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,8 +34,7 @@ public class ComponentStateDTO { /** * @return The component identifier */ - @ApiModelProperty( - value = "The component identifier." + @Schema(description = "The component identifier." ) public String getComponentId() { return componentId; @@ -48,8 +47,7 @@ public void setComponentId(String componentId) { /** * @return Description of the state this component persists. */ - @ApiModelProperty( - value = "Description of the state this component persists." + @Schema(description = "Description of the state this component persists." ) public String getStateDescription() { return stateDescription; @@ -62,8 +60,7 @@ public void setStateDescription(String stateDescription) { /** * @return The cluster state for this component, or null if this NiFi is a standalone instance */ - @ApiModelProperty( - value = "The cluster state for this component, or null if this NiFi is a standalone instance." + @Schema(description = "The cluster state for this component, or null if this NiFi is a standalone instance." ) public StateMapDTO getClusterState() { return clusterState; @@ -76,8 +73,7 @@ public void setClusterState(StateMapDTO clusterState) { /** * @return The local state for this component */ - @ApiModelProperty( - value = "The local state for this component." + @Schema(description = "The local state for this component." ) public StateMapDTO getLocalState() { return localState; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentValidationResultDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentValidationResultDTO.java index 2a3f6c4dd96c8..040b09f9d4975 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentValidationResultDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentValidationResultDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -27,7 +27,7 @@ public class ComponentValidationResultDTO extends AffectedComponentDTO { private Boolean resultsValid; private Collection resultantValidationErrors; - @ApiModelProperty("Whether or not the component is currently valid") + @Schema(description = "Whether or not the component is currently valid") public Boolean getCurrentlyValid() { return currentlyValid; } @@ -36,7 +36,7 @@ public void setCurrentlyValid(final Boolean currentlyValid) { this.currentlyValid = currentlyValid; } - @ApiModelProperty("Whether or not the component will be valid if the Parameter Context is changed") + @Schema(description = "Whether or not the component will be valid if the Parameter Context is changed") public Boolean getResultsValid() { return resultsValid; } @@ -45,7 +45,7 @@ public void setResultsValid(final Boolean resultsValid) { this.resultsValid = resultsValid; } - @ApiModelProperty("The validation errors that will apply to the component if the Parameter Context is changed") + @Schema(description = "The validation errors that will apply to the component if the Parameter Context is changed") public Collection getResultantValidationErrors() { return resultantValidationErrors; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigVerificationResultDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigVerificationResultDTO.java index b44b40ea022ce..6ae28b2722d76 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigVerificationResultDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigVerificationResultDTO.java @@ -17,14 +17,14 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class ConfigVerificationResultDTO { private String outcome; private String verificationStepName; private String explanation; - @ApiModelProperty(value = "The outcome of the verification", allowableValues = "SUCCESSFUL, FAILED, SKIPPED") + @Schema(description = "The outcome of the verification", allowableValues = "SUCCESSFUL, FAILED, SKIPPED") public String getOutcome() { return outcome; } @@ -33,7 +33,7 @@ public void setOutcome(final String outcome) { this.outcome = outcome; } - @ApiModelProperty("The name of the verification step") + @Schema(description = "The name of the verification step") public String getVerificationStepName() { return verificationStepName; } @@ -42,7 +42,7 @@ public void setVerificationStepName(final String verificationStepName) { this.verificationStepName = verificationStepName; } - @ApiModelProperty("An explanation of why the step was or was not successful") + @Schema(description = "An explanation of why the step was or was not successful") public String getExplanation() { return explanation; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigurationAnalysisDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigurationAnalysisDTO.java index 58464696bfdaf..d1ea4f68cd6f4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigurationAnalysisDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConfigurationAnalysisDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Map; @@ -29,7 +29,7 @@ public class ConfigurationAnalysisDTO { private Map referencedAttributes; private boolean supportsVerification; - @ApiModelProperty("The ID of the component") + @Schema(description = "The ID of the component") public String getComponentId() { return componentId; } @@ -38,7 +38,7 @@ public void setComponentId(final String componentId) { this.componentId = componentId; } - @ApiModelProperty("The configured properties for the component") + @Schema(description = "The configured properties for the component") public Map getProperties() { return properties; } @@ -47,7 +47,7 @@ public void setProperties(final Map properties) { this.properties = properties; } - @ApiModelProperty("The attributes that are referenced by the properties, mapped to recently used values") + @Schema(description = "The attributes that are referenced by the properties, mapped to recently used values") public Map getReferencedAttributes() { return referencedAttributes; } @@ -56,7 +56,7 @@ public void setReferencedAttributes(final Map referencedAttribut this.referencedAttributes = referencedAttributes; } - @ApiModelProperty("Whether or not the component supports verification") + @Schema(description = "Whether or not the component supports verification") public boolean isSupportsVerification() { return supportsVerification; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectableDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectableDTO.java index ddbd9f0c5c81f..fb58c2a344e63 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectableDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectableDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -39,9 +39,8 @@ public class ConnectableDTO { /** * @return id of this connectable component */ - @ApiModelProperty( - value = "The id of the connectable component.", - required = true + @Schema(description = "The id of the connectable component.", + requiredMode = Schema.RequiredMode.REQUIRED ) public String getId() { return id; @@ -51,7 +50,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The ID of the corresponding component that is under version control") + @Schema(description = "The ID of the corresponding component that is under version control") public String getVersionedComponentId() { return versionedComponentId; } @@ -64,9 +63,8 @@ public void setVersionedComponentId(final String id) { /** * @return type of this connectable component */ - @ApiModelProperty( - value = "The type of component the connectable is.", - required = true, + @Schema(description = "The type of component the connectable is.", + requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = "PROCESSOR, REMOTE_INPUT_PORT, REMOTE_OUTPUT_PORT, INPUT_PORT, OUTPUT_PORT, FUNNEL" ) public String getType() { @@ -80,9 +78,8 @@ public void setType(String type) { /** * @return id of the group that this connectable component resides in */ - @ApiModelProperty( - value = "The id of the group that the connectable component resides in", - required = true + @Schema(description = "The id of the group that the connectable component resides in", + requiredMode = Schema.RequiredMode.REQUIRED ) public String getGroupId() { return groupId; @@ -95,8 +92,7 @@ public void setGroupId(String groupId) { /** * @return name of this connectable component */ - @ApiModelProperty( - value = "The name of the connectable component" + @Schema(description = "The name of the connectable component" ) public String getName() { return name; @@ -109,8 +105,7 @@ public void setName(String name) { /** * @return Used to reflect the current state of this Connectable */ - @ApiModelProperty( - value = "Reflects the current state of the connectable component." + @Schema(description = "Reflects the current state of the connectable component." ) public Boolean isRunning() { return running; @@ -123,8 +118,7 @@ public void setRunning(Boolean running) { /** * @return If this represents a remote port it is used to indicate whether the target exists */ - @ApiModelProperty( - value = "If the connectable component represents a remote port, indicates if the target exists." + @Schema(description = "If the connectable component represents a remote port, indicates if the target exists." ) public Boolean getExists() { return exists; @@ -137,8 +131,7 @@ public void setExists(Boolean exists) { /** * @return If this represents a remote port it is used to indicate whether is it configured to transmit */ - @ApiModelProperty( - value = "If the connectable component represents a remote port, indicates if the target is configured to transmit." + @Schema(description = "If the connectable component represents a remote port, indicates if the target is configured to transmit." ) public Boolean getTransmitting() { return transmitting; @@ -151,8 +144,7 @@ public void setTransmitting(Boolean transmitting) { /** * @return The comments from this Connectable */ - @ApiModelProperty( - value = "The comments for the connectable component." + @Schema(description = "The comments for the connectable component." ) public String getComments() { return comments; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java index f98c149c6d7ee..22aea63a1ccbc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -55,8 +55,7 @@ public class ConnectionDTO extends ComponentDTO { * * @return The source of this connection */ - @ApiModelProperty( - value = "The source of the connection." + @Schema(description = "The source of the connection." ) public ConnectableDTO getSource() { return source; @@ -71,8 +70,7 @@ public void setSource(ConnectableDTO source) { * * @return The destination of this connection */ - @ApiModelProperty( - value = "The destination of the connection." + @Schema(description = "The destination of the connection." ) public ConnectableDTO getDestination() { return destination; @@ -85,8 +83,7 @@ public void setDestination(ConnectableDTO destination) { /** * @return name of the connection */ - @ApiModelProperty( - value = "The name of the connection." + @Schema(description = "The name of the connection." ) public String getName() { return name; @@ -99,8 +96,7 @@ public void setName(String name) { /** * @return position of the bend points on this connection */ - @ApiModelProperty( - value = "The bend points on the connection." + @Schema(description = "The bend points on the connection." ) public List getBends() { return bends; @@ -113,8 +109,7 @@ public void setBends(List bends) { /** * @return The index of control point that the connection label should be placed over */ - @ApiModelProperty( - value = "The index of the bend point where to place the connection label." + @Schema(description = "The index of the bend point where to place the connection label." ) public Integer getLabelIndex() { return labelIndex; @@ -127,8 +122,7 @@ public void setLabelIndex(Integer labelIndex) { /** * @return z index for this connection */ - @ApiModelProperty( - value = "The z index of the connection." + @Schema(description = "The z index of the connection." ) public Long getzIndex() { return zIndex; @@ -143,8 +137,7 @@ public void setzIndex(Long zIndex) { * * @return The relationships */ - @ApiModelProperty( - value = "The selected relationship that comprise the connection." + @Schema(description = "The selected relationship that comprise the connection." ) public Set getSelectedRelationships() { return selectedRelationships; @@ -157,9 +150,8 @@ public void setSelectedRelationships(Set relationships) { /** * @return relationships that the source of the connection currently supports. This property is read only */ - @ApiModelProperty( - value = "The relationships that the source of the connection currently supports.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The relationships that the source of the connection currently supports.", + accessMode = Schema.AccessMode.READ_ONLY ) public Set getAvailableRelationships() { return availableRelationships; @@ -175,8 +167,7 @@ public void setAvailableRelationships(Set availableRelationships) { * * @return The back pressure object threshold */ - @ApiModelProperty( - value = "The object count threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing files " + @Schema(description = "The object count threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing files " + "over the limit are affected but it does help feeder processors to stop pushing too much into this work queue." ) public Long getBackPressureObjectThreshold() { @@ -193,8 +184,7 @@ public void setBackPressureObjectThreshold(Long backPressureObjectThreshold) { * * @return The back pressure data size threshold */ - @ApiModelProperty( - value = "The object data size threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing " + @Schema(description = "The object data size threshold for determining when back pressure is applied. Updating this value is a passive change in the sense that it won't impact whether existing " + "files over the limit are affected but it does help feeder processors to stop pushing too much into this work queue." ) public String getBackPressureDataSizeThreshold() { @@ -211,8 +201,7 @@ public void setBackPressureDataSizeThreshold(String backPressureDataSizeThreshol * * @return The flow file expiration in minutes */ - @ApiModelProperty( - value = "The amount of time a flow file may be in the flow before it will be automatically aged out of the flow. Once a flow file reaches this age it will be terminated from " + @Schema(description = "The amount of time a flow file may be in the flow before it will be automatically aged out of the flow. Once a flow file reaches this age it will be terminated from " + "the flow the next time a processor attempts to start work on it." ) public String getFlowFileExpiration() { @@ -228,8 +217,7 @@ public void setFlowFileExpiration(String flowFileExpiration) { * * @return The prioritizer list */ - @ApiModelProperty( - value = "The comparators used to prioritize the queue." + @Schema(description = "The comparators used to prioritize the queue." ) public List getPrioritizers() { return prioritizers; @@ -239,7 +227,7 @@ public void setPrioritizers(List prioritizers) { this.prioritizers = prioritizers; } - @ApiModelProperty(value = "How to load balance the data in this Connection across the nodes in the cluster.", + @Schema(description = "How to load balance the data in this Connection across the nodes in the cluster.", allowableValues = "DO_NOT_LOAD_BALANCE, PARTITION_BY_ATTRIBUTE, ROUND_ROBIN, SINGLE_NODE") public String getLoadBalanceStrategy() { return loadBalanceStrategy; @@ -249,7 +237,7 @@ public void setLoadBalanceStrategy(String loadBalanceStrategy) { this.loadBalanceStrategy = loadBalanceStrategy; } - @ApiModelProperty(value = "The FlowFile Attribute to use for determining which node a FlowFile will go to if the Load Balancing Strategy is set to PARTITION_BY_ATTRIBUTE") + @Schema(description = "The FlowFile Attribute to use for determining which node a FlowFile will go to if the Load Balancing Strategy is set to PARTITION_BY_ATTRIBUTE") public String getLoadBalancePartitionAttribute() { return loadBalancePartitionAttribute; } @@ -258,7 +246,7 @@ public void setLoadBalancePartitionAttribute(String partitionAttribute) { this.loadBalancePartitionAttribute = partitionAttribute; } - @ApiModelProperty(value = "Whether or not data should be compressed when being transferred between nodes in the cluster.", + @Schema(description = "Whether or not data should be compressed when being transferred between nodes in the cluster.", allowableValues = "DO_NOT_COMPRESS, COMPRESS_ATTRIBUTES_ONLY, COMPRESS_ATTRIBUTES_AND_CONTENT") public String getLoadBalanceCompression() { return loadBalanceCompression; @@ -268,10 +256,10 @@ public void setLoadBalanceCompression(String compression) { this.loadBalanceCompression = compression; } - @ApiModelProperty(value = "The current status of the Connection's Load Balancing Activities. Status can indicate that Load Balancing is not configured for the connection, that Load Balancing " + + @Schema(description = "The current status of the Connection's Load Balancing Activities. Status can indicate that Load Balancing is not configured for the connection, that Load Balancing " + "is configured but inactive (not currently transferring data to another node), or that Load Balancing is configured and actively transferring data to another node.", allowableValues = LOAD_BALANCE_NOT_CONFIGURED + ", " + LOAD_BALANCE_INACTIVE + ", " + LOAD_BALANCE_ACTIVE, - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + accessMode = Schema.AccessMode.READ_ONLY) public String getLoadBalanceStatus() { return loadBalanceStatus; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java index 8c416d0b3f338..9cae14631be6f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerConfigurationDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,8 +31,7 @@ public class ControllerConfigurationDTO { /** * @return maximum number of timer driven threads this NiFi has available */ - @ApiModelProperty( - value = "The maximum number of timer driven threads the NiFi has available." + @Schema(description = "The maximum number of timer driven threads the NiFi has available." ) public Integer getMaxTimerDrivenThreadCount() { return maxTimerDrivenThreadCount; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerDTO.java index 8e2f08bdb1cce..42e5f6b2db3cd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Set; @@ -51,8 +51,7 @@ public class ControllerDTO { /** * @return id of this NiFi controller */ - @ApiModelProperty( - value = "The id of the NiFi." + @Schema(description = "The id of the NiFi." ) public String getId() { return id; @@ -67,8 +66,7 @@ public void setId(String id) { * * @return The name of this controller */ - @ApiModelProperty( - value = "The name of the NiFi." + @Schema(description = "The name of the NiFi." ) public String getName() { return name; @@ -81,8 +79,7 @@ public void setName(String name) { /** * @return comments of this NiFi controller */ - @ApiModelProperty( - value = "The comments for the NiFi." + @Schema(description = "The comments for the NiFi." ) public String getComments() { return comments; @@ -95,8 +92,7 @@ public void setComments(String comments) { /** * @return input ports available to send data to this NiFi controller */ - @ApiModelProperty( - value = "The input ports available to send data to for the NiFi." + @Schema(description = "The input ports available to send data to for the NiFi." ) public Set getInputPorts() { return inputPorts; @@ -109,8 +105,7 @@ public void setInputPorts(Set inputPorts) { /** * @return output ports available to received data from this NiFi controller */ - @ApiModelProperty( - value = "The output ports available to received data from the NiFi." + @Schema(description = "The output ports available to received data from the NiFi." ) public Set getOutputPorts() { return outputPorts; @@ -123,8 +118,7 @@ public void setOutputPorts(Set outputPorts) { /** * @return Instance ID of the cluster, if this node is connected to a Cluster Manager, or of this individual instance of in standalone mode */ - @ApiModelProperty( - value = "If clustered, the id of the Cluster Manager, otherwise the id of the NiFi." + @Schema(description = "If clustered, the id of the Cluster Manager, otherwise the id of the NiFi." ) public String getInstanceId() { return instanceId; @@ -139,8 +133,7 @@ public void setInstanceId(String instanceId) { * * @return a integer between 1 and 65535, or null, if not configured for remote transfer */ - @ApiModelProperty( - value = "The Socket Port on which this instance is listening for Remote Transfers of Flow Files. If this instance is not configured to receive Flow Files from remote " + @Schema(description = "The Socket Port on which this instance is listening for Remote Transfers of Flow Files. If this instance is not configured to receive Flow Files from remote " + "instances, this will be null." ) public Integer getRemoteSiteListeningPort() { @@ -156,8 +149,7 @@ public void setRemoteSiteListeningPort(final Integer port) { * * @return a integer between 1 and 65535, or null, if not configured for remote transfer */ - @ApiModelProperty( - value = "The HTTP(S) Port on which this instance is listening for Remote Transfers of Flow Files. If this instance is not configured to receive Flow Files from remote " + @Schema(description = "The HTTP(S) Port on which this instance is listening for Remote Transfers of Flow Files. If this instance is not configured to receive Flow Files from remote " + "instances, this will be null." ) public Integer getRemoteSiteHttpListeningPort() { @@ -171,8 +163,7 @@ public void setRemoteSiteHttpListeningPort(Integer remoteSiteHttpListeningPort) /** * @return Indicates whether or not Site-to-Site communications with this instance is secure (2-way authentication) */ - @ApiModelProperty( - value = "Indicates whether or not Site-to-Site communications with this instance is secure (2-way authentication)." + @Schema(description = "Indicates whether or not Site-to-Site communications with this instance is secure (2-way authentication)." ) public Boolean isSiteToSiteSecure() { return siteToSiteSecure; @@ -185,8 +176,7 @@ public void setSiteToSiteSecure(Boolean siteToSiteSecure) { /** * @return number of running components in this process group */ - @ApiModelProperty( - value = "The number of running components in the NiFi." + @Schema(description = "The number of running components in the NiFi." ) public Integer getRunningCount() { return runningCount; @@ -199,8 +189,7 @@ public void setRunningCount(Integer runningCount) { /** * @return number of stopped components in this process group */ - @ApiModelProperty( - value = "The number of stopped components in the NiFi." + @Schema(description = "The number of stopped components in the NiFi." ) public Integer getStoppedCount() { return stoppedCount; @@ -213,8 +202,7 @@ public void setStoppedCount(Integer stoppedCount) { /** * @return number of active remote ports contained in this process group */ - @ApiModelProperty( - value = "The number of active remote ports contained in the NiFi." + @Schema(description = "The number of active remote ports contained in the NiFi." ) public Integer getActiveRemotePortCount() { return activeRemotePortCount; @@ -227,8 +215,7 @@ public void setActiveRemotePortCount(Integer activeRemotePortCount) { /** * @return number of inactive remote ports contained in this process group */ - @ApiModelProperty( - value = "The number of inactive remote ports contained in the NiFi." + @Schema(description = "The number of inactive remote ports contained in the NiFi." ) public Integer getInactiveRemotePortCount() { return inactiveRemotePortCount; @@ -241,8 +228,7 @@ public void setInactiveRemotePortCount(Integer inactiveRemotePortCount) { /** * @return number of input ports contained in this process group */ - @ApiModelProperty( - value = "The number of input ports contained in the NiFi." + @Schema(description = "The number of input ports contained in the NiFi." ) public Integer getInputPortCount() { return inputPortCount; @@ -255,8 +241,7 @@ public void setInputPortCount(Integer inputPortCount) { /** * @return number of invalid components in this process group */ - @ApiModelProperty( - value = "The number of invalid components in the NiFi." + @Schema(description = "The number of invalid components in the NiFi." ) public Integer getInvalidCount() { return invalidCount; @@ -269,8 +254,7 @@ public void setInvalidCount(Integer invalidCount) { /** * @return number of disabled components in this process group */ - @ApiModelProperty( - value = "The number of disabled components in the NiFi." + @Schema(description = "The number of disabled components in the NiFi." ) public Integer getDisabledCount() { return disabledCount; @@ -283,8 +267,7 @@ public void setDisabledCount(Integer disabledCount) { /** * @return number of output ports in this process group */ - @ApiModelProperty( - value = "The number of output ports in the NiFi." + @Schema(description = "The number of output ports in the NiFi." ) public Integer getOutputPortCount() { return outputPortCount; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceApiDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceApiDTO.java index 7fba1b5ac0519..7eb60bf4ad0d7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceApiDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceApiDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Objects; @@ -33,8 +33,7 @@ public class ControllerServiceApiDTO { /** * @return The type is the fully-qualified name of the service interface */ - @ApiModelProperty( - value = "The fully qualified name of the service interface." + @Schema(description = "The fully qualified name of the service interface." ) public String getType() { return type; @@ -49,8 +48,7 @@ public void setType(String type) { * * @return The bundle details */ - @ApiModelProperty( - value = "The details of the artifact that bundled this service interface." + @Schema(description = "The details of the artifact that bundled this service interface." ) public BundleDTO getBundle() { return bundle; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java index 1ed47e055128a..33f0372260577 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; import jakarta.xml.bind.annotation.XmlType; @@ -63,8 +63,7 @@ public class ControllerServiceDTO extends ComponentDTO { /** * @return controller service name */ - @ApiModelProperty( - value = "The name of the controller service." + @Schema(description = "The name of the controller service." ) public String getName() { return name; @@ -77,8 +76,7 @@ public void setName(String name) { /** * @return the controller service type */ - @ApiModelProperty( - value = "The type of the controller service." + @Schema(description = "The type of the controller service." ) public String getType() { return type; @@ -93,8 +91,7 @@ public void setType(String type) { * * @return The bundle details */ - @ApiModelProperty( - value = "The details of the artifact that bundled this processor type." + @Schema(description = "The details of the artifact that bundled this processor type." ) public BundleDTO getBundle() { return bundle; @@ -109,8 +106,7 @@ public void setBundle(BundleDTO bundle) { * * @return The listing of implemented APIs */ - @ApiModelProperty( - value = "Lists the APIs this Controller Service implements." + @Schema(description = "Lists the APIs this Controller Service implements." ) public List getControllerServiceApis() { return controllerServiceApis; @@ -123,8 +119,7 @@ public void setControllerServiceApis(List controllerSer /** * @return the comment for the Controller Service */ - @ApiModelProperty( - value = "The comments for the controller service." + @Schema(description = "The comments for the controller service." ) public String getComments() { return comments; @@ -137,8 +132,7 @@ public void setComments(String comments) { /** * @return the level at which this controller service will report bulletins */ - @ApiModelProperty( - value = "The level at which the controller service will report bulletins." + @Schema(description = "The level at which the controller service will report bulletins." ) public String getBulletinLevel() { return bulletinLevel; @@ -151,8 +145,7 @@ public void setBulletinLevel(String bulletinLevel) { /** * @return whether this controller service persists state */ - @ApiModelProperty( - value = "Whether the controller service persists state." + @Schema(description = "Whether the controller service persists state." ) public Boolean getPersistsState() { return persistsState; @@ -165,8 +158,7 @@ public void setPersistsState(Boolean persistsState) { /** * @return whether this controller service requires elevated privileges */ - @ApiModelProperty( - value = "Whether the controller service requires elevated privileges." + @Schema(description = "Whether the controller service requires elevated privileges." ) public Boolean getRestricted() { return restricted; @@ -179,8 +171,7 @@ public void setRestricted(Boolean restricted) { /** * @return Whether the controller service has been deprecated. */ - @ApiModelProperty( - value = "Whether the ontroller service has been deprecated." + @Schema(description = "Whether the ontroller service has been deprecated." ) public Boolean getDeprecated() { return deprecated; @@ -193,8 +184,7 @@ public void setDeprecated(Boolean deprecated) { /** * @return whether the underlying extension is missing */ - @ApiModelProperty( - value = "Whether the underlying extension is missing." + @Schema(description = "Whether the underlying extension is missing." ) public Boolean getExtensionMissing() { return isExtensionMissing; @@ -207,8 +197,7 @@ public void setExtensionMissing(Boolean extensionMissing) { /** * @return whether this controller service has multiple versions available */ - @ApiModelProperty( - value = "Whether the controller service has multiple versions available." + @Schema(description = "Whether the controller service has multiple versions available." ) public Boolean getMultipleVersionsAvailable() { return multipleVersionsAvailable; @@ -221,8 +210,7 @@ public void setMultipleVersionsAvailable(Boolean multipleVersionsAvailable) { /** * @return whether this controller service supports sensitive dynamic properties */ - @ApiModelProperty( - value = "Whether the controller service supports sensitive dynamic properties." + @Schema(description = "Whether the controller service supports sensitive dynamic properties." ) public Boolean getSupportsSensitiveDynamicProperties() { return supportsSensitiveDynamicProperties; @@ -235,8 +223,7 @@ public void setSupportsSensitiveDynamicProperties(final Boolean supportsSensitiv /** * @return The state of this controller service. Possible values are ENABLED, ENABLING, DISABLED, DISABLING */ - @ApiModelProperty( - value = "The state of the controller service.", + @Schema(description = "The state of the controller service.", allowableValues = "ENABLED, ENABLING, DISABLED, DISABLING" ) public String getState() { @@ -250,8 +237,7 @@ public void setState(String state) { /** * @return controller service properties */ - @ApiModelProperty( - value = "The properties of the controller service." + @Schema(description = "The properties of the controller service." ) public Map getProperties() { return properties; @@ -264,8 +250,7 @@ public void setProperties(Map properties) { /** * @return descriptors for the controller service properties */ - @ApiModelProperty( - value = "The descriptors for the controller service properties." + @Schema(description = "The descriptors for the controller service properties." ) public Map getDescriptors() { return descriptors; @@ -278,8 +263,7 @@ public void setDescriptors(Map descriptors) { /** * @return Set of sensitive dynamic property names */ - @ApiModelProperty( - value = "Set of sensitive dynamic property names" + @Schema(description = "Set of sensitive dynamic property names" ) public Set getSensitiveDynamicPropertyNames() { return sensitiveDynamicPropertyNames; @@ -292,8 +276,7 @@ public void setSensitiveDynamicPropertyNames(final Set sensitiveDynamicP /** * @return the URL for this controller services custom configuration UI if applicable. Null otherwise */ - @ApiModelProperty( - value = "The URL for the controller services custom configuration UI if applicable." + @Schema(description = "The URL for the controller services custom configuration UI if applicable." ) public String getCustomUiUrl() { return customUiUrl; @@ -306,8 +289,7 @@ public void setCustomUiUrl(String customUiUrl) { /** * @return annotation data for this controller service */ - @ApiModelProperty( - value = "The annotation for the controller service. This is how the custom UI relays configuration to the controller service." + @Schema(description = "The annotation for the controller service. This is how the custom UI relays configuration to the controller service." ) public String getAnnotationData() { return annotationData; @@ -320,8 +302,7 @@ public void setAnnotationData(String annotationData) { /** * @return all components referencing this controller service */ - @ApiModelProperty( - value = "All components referencing this controller service." + @Schema(description = "All components referencing this controller service." ) public Set getReferencingComponents() { return referencingComponents; @@ -336,8 +317,10 @@ public void setReferencingComponents(Set getValidationErrors() { return validationErrors; @@ -347,8 +330,8 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty(value = "Indicates whether the ControllerService is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the ControllerService is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "Indicates whether the ControllerService is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the ControllerService is valid)", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java index ca37a4dbfd8ec..3cfd407fd2237 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceReferencingComponentDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity; import jakarta.xml.bind.annotation.XmlType; @@ -50,8 +50,7 @@ public class ControllerServiceReferencingComponentDTO { /** * @return Group id for this component referencing a controller service. If this component is another service, this field is blank */ - @ApiModelProperty( - value = "The group id for the component referencing a controller service. If this component is another controller service or a reporting " + @Schema(description = "The group id for the component referencing a controller service. If this component is another controller service or a reporting " + "task, this field is blank." ) public String getGroupId() { @@ -65,8 +64,7 @@ public void setGroupId(String groupId) { /** * @return id for this component referencing a controller service */ - @ApiModelProperty( - value = "The id of the component referencing a controller service." + @Schema(description = "The id of the component referencing a controller service." ) public String getId() { return id; @@ -79,8 +77,7 @@ public void setId(String id) { /** * @return name for this component referencing a controller service */ - @ApiModelProperty( - value = "The name of the component referencing a controller service." + @Schema(description = "The name of the component referencing a controller service." ) public String getName() { return name; @@ -93,8 +90,7 @@ public void setName(String name) { /** * @return type for this component referencing a controller service */ - @ApiModelProperty( - value = "The type of the component referencing a controller service in simple Java class name format without package name." + @Schema(description = "The type of the component referencing a controller service in simple Java class name format without package name." ) public String getType() { return type; @@ -107,8 +103,7 @@ public void setType(String type) { /** * @return scheduled state of the processor referencing a controller service. If this component is another service, this field represents the controller service state */ - @ApiModelProperty( - value = "The scheduled state of a processor or reporting task referencing a controller service. If this component is another controller " + @Schema(description = "The scheduled state of a processor or reporting task referencing a controller service. If this component is another controller " + "service, this field represents the controller service state." ) public String getState() { @@ -122,8 +117,7 @@ public void setState(String state) { /** * @return type of reference this is (Processor, ControllerService, ParameterProvider, or ReportingTask) */ - @ApiModelProperty( - value = "The type of reference this is.", + @Schema(description = "The type of reference this is.", allowableValues = "Processor, ControllerService, ReportingTask, FlowRegistryClient" ) public String getReferenceType() { @@ -137,8 +131,7 @@ public void setReferenceType(String referenceType) { /** * @return component properties */ - @ApiModelProperty( - value = "The properties for the component." + @Schema(description = "The properties for the component." ) public Map getProperties() { return properties; @@ -151,8 +144,7 @@ public void setProperties(Map properties) { /** * @return descriptors for the components properties */ - @ApiModelProperty( - value = "The descriptors for the component properties." + @Schema(description = "The descriptors for the component properties." ) public Map getDescriptors() { return descriptors; @@ -165,8 +157,7 @@ public void setDescriptors(Map descriptors) { /** * @return Any validation error associated with this component */ - @ApiModelProperty( - value = "The validation errors for the component." + @Schema(description = "The validation errors for the component." ) public Collection getValidationErrors() { return validationErrors; @@ -179,8 +170,7 @@ public void setValidationErrors(Collection validationErrors) { /** * @return active thread count for the referencing component */ - @ApiModelProperty( - value = "The number of active threads for the referencing component." + @Schema(description = "The number of active threads for the referencing component." ) public Integer getActiveThreadCount() { return activeThreadCount; @@ -193,8 +183,7 @@ public void setActiveThreadCount(Integer activeThreadCount) { /** * @return If this referencing component represents a ControllerService, these are the components that reference it */ - @ApiModelProperty( - value = "If the referencing component represents a controller service, these are the components that reference it." + @Schema(description = "If the referencing component represents a controller service, these are the components that reference it." ) public Set getReferencingComponents() { return referencingComponents; @@ -207,8 +196,7 @@ public void setReferencingComponents(Set nodeSnapshots; - @ApiModelProperty("A Counters snapshot that represents the aggregate values of all nodes in the cluster. If the NiFi instance is " + @Schema(description = "A Counters snapshot that represents the aggregate values of all nodes in the cluster. If the NiFi instance is " + "a standalone instance, rather than a cluster, this represents the stats of the single instance.") public CountersSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; @@ -37,7 +37,7 @@ public void setAggregateSnapshot(CountersSnapshotDTO aggregateSnapshot) { this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A Counters snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + @Schema(description = "A Counters snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + "a cluster, this may be null.") public List getNodeSnapshots() { return nodeSnapshots; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/CountersSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/CountersSnapshotDTO.java index 2a80528a747ba..f6be698005641 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/CountersSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/CountersSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -35,7 +35,7 @@ public class CountersSnapshotDTO implements Cloneable { private Date generated; private Collection counters; - @ApiModelProperty("All counters in the NiFi.") + @Schema(description = "All counters in the NiFi.") public Collection getCounters() { return counters; } @@ -45,9 +45,8 @@ public void setCounters(Collection counters) { } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The timestamp when the report was generated.", - dataType = "string" + @Schema(description = "The timestamp when the report was generated.", + type = "string" ) public Date getGenerated() { return generated; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DifferenceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DifferenceDTO.java index 2781876264a93..0b1dd2a087d85 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DifferenceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DifferenceDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -26,7 +26,7 @@ public class DifferenceDTO { private String differenceType; private String difference; - @ApiModelProperty("The type of difference") + @Schema(description = "The type of difference") public String getDifferenceType() { return differenceType; } @@ -35,7 +35,7 @@ public void setDifferenceType(String differenceType) { this.differenceType = differenceType; } - @ApiModelProperty("Description of the difference") + @Schema(description = "Description of the difference") public String getDifference() { return difference; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java index 3a7888d2e38cb..cdce31202b7f9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,8 +34,7 @@ public class DimensionsDTO { /** * @return height of the label in pixels when at a 1:1 scale */ - @ApiModelProperty( - value = "The height of the label in pixels when at a 1:1 scale." + @Schema(description = "The height of the label in pixels when at a 1:1 scale." ) public Double getHeight() { return height; @@ -48,8 +47,7 @@ public void setHeight(Double height) { /** * @return width of the label in pixels when at a 1:1 scale */ - @ApiModelProperty( - value = "The width of the label in pixels when at a 1:1 scale." + @Schema(description = "The width of the label in pixels when at a 1:1 scale." ) public Double getWidth() { return width; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedTypeDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedTypeDTO.java index 2adbb758fdee9..6f5574c41755f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedTypeDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DocumentedTypeDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -42,8 +42,7 @@ public class DocumentedTypeDTO { /** * @return An optional description of the corresponding type */ - @ApiModelProperty( - value = "The description of the type." + @Schema(description = "The description of the type." ) public String getDescription() { return description; @@ -56,8 +55,7 @@ public void setDescription(String description) { /** * @return Whether this type is restricted */ - @ApiModelProperty( - value = "Whether this type is restricted." + @Schema(description = "Whether this type is restricted." ) public boolean isRestricted() { return restricted; @@ -70,8 +68,7 @@ public void setRestricted(boolean restricted) { /** * @return An optional collection of explicit restrictions */ - @ApiModelProperty( - value = "An optional collection of explicit restrictions. If specified, these explicit restrictions will be enfored." + @Schema(description = "An optional collection of explicit restrictions. If specified, these explicit restrictions will be enfored." ) public Set getExplicitRestrictions() { return explicitRestrictions; @@ -84,8 +81,7 @@ public void setExplicitRestrictions(Set explicitRestrict /** * @return An optional description of why the usage of this component is restricted */ - @ApiModelProperty( - value = "The optional description of why the usage of this component is restricted." + @Schema(description = "The optional description of why the usage of this component is restricted." ) public String getUsageRestriction() { return usageRestriction; @@ -98,8 +94,7 @@ public void setUsageRestriction(String usageRestriction) { /** * @return An optional description of why the usage of this component is deprecated */ - @ApiModelProperty( - value = "The description of why the usage of this component is restricted." + @Schema(description = "The description of why the usage of this component is restricted." ) public String getDeprecationReason() { return deprecationReason; @@ -113,8 +108,7 @@ public void setDeprecationReason(String deprecationReason) { /** * @return The type is the fully-qualified name of a Java class */ - @ApiModelProperty( - value = "The fully qualified name of the type." + @Schema(description = "The fully qualified name of the type." ) public String getType() { return type; @@ -129,8 +123,7 @@ public void setType(String type) { * * @return The bundle details */ - @ApiModelProperty( - value = "The details of the artifact that bundled this type." + @Schema(description = "The details of the artifact that bundled this type." ) public BundleDTO getBundle() { return bundle; @@ -145,8 +138,7 @@ public void setBundle(BundleDTO bundle) { * * @return The listing of implemented APIs */ - @ApiModelProperty( - value = "If this type represents a ControllerService, this lists the APIs it implements." + @Schema(description = "If this type represents a ControllerService, this lists the APIs it implements." ) public List getControllerServiceApis() { return controllerServiceApis; @@ -159,8 +151,7 @@ public void setControllerServiceApis(List controllerSer /** * @return The tags associated with this type */ - @ApiModelProperty( - value = "The tags associated with this type." + @Schema(description = "The tags associated with this type." ) public Set getTags() { return tags; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DropRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DropRequestDTO.java index 3f10430d19c85..3f77b941a59d7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DropRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DropRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -56,8 +56,7 @@ public class DropRequestDTO { * * @return The id */ - @ApiModelProperty( - value = "The id for this drop request." + @Schema(description = "The id for this drop request." ) public String getId() { return this.id; @@ -72,8 +71,7 @@ public void setId(final String id) { * * @return The uri */ - @ApiModelProperty( - value = "The URI for future requests to this drop request." + @Schema(description = "The URI for future requests to this drop request." ) public String getUri() { return uri; @@ -87,9 +85,8 @@ public void setUri(String uri) { * @return time the query was submitted */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp when the query was submitted.", - dataType = "string" + @Schema(description = "The timestamp when the query was submitted.", + type = "string" ) public Date getSubmissionTime() { return submissionTime; @@ -102,8 +99,7 @@ public void setSubmissionTime(Date submissionTime) { /** * @return percent completed */ - @ApiModelProperty( - value = "The current percent complete." + @Schema(description = "The current percent complete." ) public Integer getPercentCompleted() { return percentCompleted; @@ -116,8 +112,7 @@ public void setPercentCompleted(Integer percentCompleted) { /** * @return whether the query has finished */ - @ApiModelProperty( - value = "Whether the query has finished." + @Schema(description = "Whether the query has finished." ) public Boolean isFinished() { return finished; @@ -130,8 +125,7 @@ public void setFinished(Boolean finished) { /** * @return the reason, if any, that this drop request failed */ - @ApiModelProperty( - value = "The reason, if any, that this drop request failed." + @Schema(description = "The reason, if any, that this drop request failed." ) public String getFailureReason() { return failureReason; @@ -145,9 +139,8 @@ public void setFailureReason(String failureReason) { * @return the time this request was last updated */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The last time this drop request was updated.", - dataType = "string" + @Schema(description = "The last time this drop request was updated.", + type = "string" ) public Date getLastUpdated() { return lastUpdated; @@ -160,8 +153,7 @@ public void setLastUpdated(Date lastUpdated) { /** * @return the number of flow files currently queued. */ - @ApiModelProperty( - value = "The number of flow files currently queued." + @Schema(description = "The number of flow files currently queued." ) public Integer getCurrentCount() { return currentCount; @@ -174,8 +166,7 @@ public void setCurrentCount(Integer currentCount) { /** * @return the size of the flow files currently queued in bytes. */ - @ApiModelProperty( - value = "The size of flow files currently queued in bytes." + @Schema(description = "The size of flow files currently queued in bytes." ) public Long getCurrentSize() { return currentSize; @@ -188,8 +179,7 @@ public void setCurrentSize(Long currentSize) { /** * @return the count and size of the currently queued flow files. */ - @ApiModelProperty( - value = "The count and size of flow files currently queued." + @Schema(description = "The count and size of flow files currently queued." ) public String getCurrent() { return current; @@ -202,8 +192,7 @@ public void setCurrent(String current) { /** * @return the number of flow files to be dropped as a result of this request. */ - @ApiModelProperty( - value = "The number of flow files to be dropped as a result of this request." + @Schema(description = "The number of flow files to be dropped as a result of this request." ) public Integer getOriginalCount() { return originalCount; @@ -216,8 +205,7 @@ public void setOriginalCount(Integer originalCount) { /** * @return the size of the flow files to be dropped as a result of this request in bytes. */ - @ApiModelProperty( - value = "The size of flow files to be dropped as a result of this request in bytes." + @Schema(description = "The size of flow files to be dropped as a result of this request in bytes." ) public Long getOriginalSize() { return originalSize; @@ -230,8 +218,7 @@ public void setOriginalSize(Long originalSize) { /** * @return the count and size of flow files to be dropped as a result of this request. */ - @ApiModelProperty( - value = "The count and size of flow files to be dropped as a result of this request." + @Schema(description = "The count and size of flow files to be dropped as a result of this request." ) public String getOriginal() { return original; @@ -244,8 +231,7 @@ public void setOriginal(String original) { /** * @return the number of flow files that have been dropped thus far. */ - @ApiModelProperty( - value = "The number of flow files that have been dropped thus far." + @Schema(description = "The number of flow files that have been dropped thus far." ) public Integer getDroppedCount() { return droppedCount; @@ -258,8 +244,7 @@ public void setDroppedCount(Integer droppedCount) { /** * @return the size of the flow files that have been dropped thus far in bytes. */ - @ApiModelProperty( - value = "The size of flow files that have been dropped thus far in bytes." + @Schema(description = "The size of flow files that have been dropped thus far in bytes." ) public Long getDroppedSize() { return droppedSize; @@ -272,8 +257,7 @@ public void setDroppedSize(Long droppedSize) { /** * @return the count and size of the flow files that have been dropped thus far. */ - @ApiModelProperty( - value = "The count and size of flow files that have been dropped thus far." + @Schema(description = "The count and size of flow files that have been dropped thus far." ) public String getDropped() { return dropped; @@ -286,8 +270,7 @@ public void setDropped(String dropped) { /** * @return the current state of the drop request. */ - @ApiModelProperty( - value = "The current state of the drop request." + @Schema(description = "The current state of the drop request." ) public String getState() { return state; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ExplicitRestrictionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ExplicitRestrictionDTO.java index b8798b9ed7a51..1ecbe46cc16e5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ExplicitRestrictionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ExplicitRestrictionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,8 +32,7 @@ public class ExplicitRestrictionDTO { /** * @return The required permission necessary for this restriction. */ - @ApiModelProperty( - value = "The required permission necessary for this restriction." + @Schema(description = "The required permission necessary for this restriction." ) public RequiredPermissionDTO getRequiredPermission() { return requiredPermission; @@ -46,8 +45,7 @@ public void setRequiredPermission(RequiredPermissionDTO requiredPermission) { /** * @return The description of why the usage of this component is restricted for this required permission. */ - @ApiModelProperty( - value = "The description of why the usage of this component is restricted for this required permission." + @Schema(description = "The description of why the usage of this component is restricted for this required permission." ) public String getExplanation() { return explanation; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowAnalysisRuleDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowAnalysisRuleDTO.java index 41fcd8e0d5d60..33e2058214d26 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowAnalysisRuleDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowAnalysisRuleDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -53,8 +53,7 @@ public class FlowAnalysisRuleDTO extends ComponentDTO { /** * @return user-defined name of the flow analysis rule */ - @ApiModelProperty( - value = "The name of the flow analysis rule." + @Schema(description = "The name of the flow analysis rule." ) public String getName() { return name; @@ -67,8 +66,7 @@ public void setName(String name) { /** * @return user-defined comments for the flow analysis rule */ - @ApiModelProperty( - value = "The comments of the flow analysis rule." + @Schema(description = "The comments of the flow analysis rule." ) public String getComments() { return comments; @@ -81,8 +79,7 @@ public void setComments(String comments) { /** * @return type of flow analysis rule */ - @ApiModelProperty( - value = "The fully qualified type of the flow analysis rule." + @Schema(description = "The fully qualified type of the flow analysis rule." ) public String getType() { return type; @@ -97,8 +94,7 @@ public void setType(String type) { * * @return The bundle details */ - @ApiModelProperty( - value = "The details of the artifact that bundled this flow analysis rule type." + @Schema(description = "The details of the artifact that bundled this flow analysis rule type." ) public BundleDTO getBundle() { return bundle; @@ -110,8 +106,7 @@ public void setBundle(BundleDTO bundle) { /** * @return whether this flow analysis rule persists state */ - @ApiModelProperty( - value = "Whether the flow analysis rule persists state." + @Schema(description = "Whether the flow analysis rule persists state." ) public Boolean getPersistsState() { return persistsState; @@ -124,8 +119,7 @@ public void setPersistsState(Boolean persistsState) { /** * @return whether this flow analysis rule requires elevated privileges */ - @ApiModelProperty( - value = "Whether the flow analysis rule requires elevated privileges." + @Schema(description = "Whether the flow analysis rule requires elevated privileges." ) public Boolean getRestricted() { return restricted; @@ -138,8 +132,7 @@ public void setRestricted(Boolean restricted) { /** * @return Whether the flow analysis rule has been deprecated. */ - @ApiModelProperty( - value = "Whether the flow analysis rule has been deprecated." + @Schema(description = "Whether the flow analysis rule has been deprecated." ) public Boolean getDeprecated() { return deprecated; @@ -152,8 +145,7 @@ public void setDeprecated(Boolean deprecated) { /** * @return whether the underlying extension is missing */ - @ApiModelProperty( - value = "Whether the underlying extension is missing." + @Schema(description = "Whether the underlying extension is missing." ) public Boolean getExtensionMissing() { return isExtensionMissing; @@ -166,8 +158,7 @@ public void setExtensionMissing(Boolean extensionMissing) { /** * @return whether this flow analysis rule has multiple versions available */ - @ApiModelProperty( - value = "Whether the flow analysis rule has multiple versions available." + @Schema(description = "Whether the flow analysis rule has multiple versions available." ) public Boolean getMultipleVersionsAvailable() { return multipleVersionsAvailable; @@ -180,8 +171,7 @@ public void setMultipleVersionsAvailable(Boolean multipleVersionsAvailable) { /** * @return whether this flow analysis rule supports sensitive dynamic properties */ - @ApiModelProperty( - value = "Whether the flow analysis rule supports sensitive dynamic properties." + @Schema(description = "Whether the flow analysis rule supports sensitive dynamic properties." ) public Boolean getSupportsSensitiveDynamicProperties() { return supportsSensitiveDynamicProperties; @@ -194,8 +184,7 @@ public void setSupportsSensitiveDynamicProperties(final Boolean supportsSensitiv /** * @return current scheduling state of the flow analysis rule */ - @ApiModelProperty( - value = "The state of the flow analysis rule.", + @Schema(description = "The state of the flow analysis rule.", allowableValues = "ENABLED, DISABLED" ) public String getState() { @@ -209,8 +198,7 @@ public void setState(String state) { /** * @return Enforcement Policy */ - @ApiModelProperty( - value = "Enforcement Policy." + @Schema(description = "Enforcement Policy." ) public String getEnforcementPolicy() { return enforcementPolicy; @@ -223,8 +211,7 @@ public void setEnforcementPolicy(String enforcementPolicy) { /** * @return flow analysis rule's properties */ - @ApiModelProperty( - value = "The properties of the flow analysis rule." + @Schema(description = "The properties of the flow analysis rule." ) public Map getProperties() { return properties; @@ -237,8 +224,7 @@ public void setProperties(Map properties) { /** * @return Map of property name to descriptor */ - @ApiModelProperty( - value = "The descriptors for the flow analysis rules properties." + @Schema(description = "The descriptors for the flow analysis rules properties." ) public Map getDescriptors() { return descriptors; @@ -251,8 +237,7 @@ public void setDescriptors(Map descriptors) { /** * @return Set of sensitive dynamic property names */ - @ApiModelProperty( - value = "Set of sensitive dynamic property names" + @Schema(description = "Set of sensitive dynamic property names" ) public Set getSensitiveDynamicPropertyNames() { return sensitiveDynamicPropertyNames; @@ -267,8 +252,7 @@ public void setSensitiveDynamicPropertyNames(final Set sensitiveDynamicP * * @return The validation errors */ - @ApiModelProperty( - value = "Gets the validation errors from the flow analysis rule. These validation errors represent the problems with the flow analysis rule that must be resolved before " + @Schema(description = "Gets the validation errors from the flow analysis rule. These validation errors represent the problems with the flow analysis rule that must be resolved before " + "it can be scheduled to run." ) public Collection getValidationErrors() { @@ -279,8 +263,8 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty(value = "Indicates whether the Flow Analysis Rule is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Flow Analysis Rule is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "Indicates whether the Flow Analysis Rule is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Flow Analysis Rule is valid)", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java index 4ec721247653b..0dd5ef28bf5d7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowConfigurationDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -43,9 +43,8 @@ public class FlowConfigurationDTO { /** * @return interval in seconds between the automatic NiFi refresh requests. This value is read only */ - @ApiModelProperty( - value = "The interval in seconds between the automatic NiFi refresh requests.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The interval in seconds between the automatic NiFi refresh requests.", + accessMode = Schema.AccessMode.READ_ONLY ) public Long getAutoRefreshIntervalSeconds() { return autoRefreshIntervalSeconds; @@ -59,9 +58,8 @@ public void setAutoRefreshIntervalSeconds(Long autoRefreshIntervalSeconds) { * @return whether this NiFi supports a managed authorizer. Managed authorizers can visualize users, groups, * and policies in the UI. This value is read only */ - @ApiModelProperty( - value = "Whether this NiFi supports a managed authorizer. Managed authorizers can visualize users, groups, and policies in the UI.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Whether this NiFi supports a managed authorizer. Managed authorizers can visualize users, groups, and policies in the UI.", + accessMode = Schema.AccessMode.READ_ONLY ) public Boolean getSupportsManagedAuthorizer() { return supportsManagedAuthorizer; @@ -74,9 +72,8 @@ public void setSupportsManagedAuthorizer(Boolean supportsManagedAuthorizer) { /** * @return whether this NiFi supports configurable users and groups. This value is read only */ - @ApiModelProperty( - value = "Whether this NiFi supports configurable users and groups.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Whether this NiFi supports configurable users and groups.", + accessMode = Schema.AccessMode.READ_ONLY ) public Boolean getSupportsConfigurableUsersAndGroups() { return supportsConfigurableUsersAndGroups; @@ -89,9 +86,8 @@ public void setSupportsConfigurableUsersAndGroups(Boolean supportsConfigurableUs /** * @return whether this NiFi supports a configurable authorizer. This value is read only */ - @ApiModelProperty( - value = "Whether this NiFi supports a configurable authorizer.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Whether this NiFi supports a configurable authorizer.", + accessMode = Schema.AccessMode.READ_ONLY ) public Boolean getSupportsConfigurableAuthorizer() { return supportsConfigurableAuthorizer; @@ -105,9 +101,8 @@ public void setSupportsConfigurableAuthorizer(Boolean supportsConfigurableAuthor * @return current time on the server */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The current time on the system.", - dataType = "string" + @Schema(description = "The current time on the system.", + type = "string" ) public Date getCurrentTime() { return currentTime; @@ -120,8 +115,7 @@ public void setCurrentTime(Date currentTime) { /** * @return time offset of the server */ - @ApiModelProperty( - value = "The time offset of the system." + @Schema(description = "The time offset of the system." ) public Integer getTimeOffset() { return timeOffset; @@ -134,8 +128,7 @@ public void setTimeOffset(Integer timeOffset) { /** * @return the default back pressure object threshold */ - @ApiModelProperty( - value = "The default back pressure object threshold." + @Schema(description = "The default back pressure object threshold." ) public Long getDefaultBackPressureObjectThreshold() { return defaultBackPressureObjectThreshold; @@ -148,8 +141,7 @@ public void setDefaultBackPressureObjectThreshold(Long backPressureObjectThresho /** * @return the default back pressure data size threshold */ - @ApiModelProperty( - value = "The default back pressure data size threshold." + @Schema(description = "The default back pressure data size threshold." ) public String getDefaultBackPressureDataSizeThreshold() { return defaultBackPressureDataSizeThreshold; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java index b04adf1d9725f..030161c62160a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Map; @@ -36,8 +36,7 @@ public class FlowFileDTO extends FlowFileSummaryDTO { /** * @return the FlowFile attributes */ - @ApiModelProperty( - value = "The FlowFile attributes." + @Schema(description = "The FlowFile attributes." ) public Map getAttributes() { return attributes; @@ -50,8 +49,7 @@ public void setAttributes(Map attributes) { /** * @return the Section in which the Content Claim lives, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The section in which the content claim lives." + @Schema(description = "The section in which the content claim lives." ) public String getContentClaimSection() { return contentClaimSection; @@ -64,8 +62,7 @@ public void setContentClaimSection(String contentClaimSection) { /** * @return the Container in which the Content Claim lives, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The container in which the content claim lives." + @Schema(description = "The container in which the content claim lives." ) public String getContentClaimContainer() { return contentClaimContainer; @@ -78,8 +75,7 @@ public void setContentClaimContainer(String contentClaimContainer) { /** * @return the Identifier of the Content Claim, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The identifier of the content claim." + @Schema(description = "The identifier of the content claim." ) public String getContentClaimIdentifier() { return contentClaimIdentifier; @@ -92,8 +88,7 @@ public void setContentClaimIdentifier(String contentClaimIdentifier) { /** * @return the offset into the the Content Claim where the FlowFile's content begins, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The offset into the content claim where the flowfile's content begins." + @Schema(description = "The offset into the content claim where the flowfile's content begins." ) public Long getContentClaimOffset() { return contentClaimOffset; @@ -106,8 +101,7 @@ public void setContentClaimOffset(Long contentClaimOffset) { /** * @return the formatted file size of the content claim */ - @ApiModelProperty( - value = "The file size of the content claim formatted." + @Schema(description = "The file size of the content claim formatted." ) public String getContentClaimFileSize() { return contentClaimFileSize; @@ -120,8 +114,7 @@ public void setContentClaimFileSize(String contentClaimFileSize) { /** * @return the number of bytes of the content claim */ - @ApiModelProperty( - value = "The file size of the content claim in bytes." + @Schema(description = "The file size of the content claim in bytes." ) public Long getContentClaimFileSizeBytes() { return contentClaimFileSizeBytes; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java index 359e43b9604c8..478949121ee01 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowFileSummaryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -40,8 +40,7 @@ public class FlowFileSummaryDTO { /** * @return the FlowFile uri */ - @ApiModelProperty( - value = "The URI that can be used to access this FlowFile." + @Schema(description = "The URI that can be used to access this FlowFile." ) public String getUri() { return uri; @@ -54,8 +53,7 @@ public void setUri(String uri) { /** * @return the FlowFile uuid */ - @ApiModelProperty( - value = "The FlowFile UUID." + @Schema(description = "The FlowFile UUID." ) public String getUuid() { return uuid; @@ -68,8 +66,7 @@ public void setUuid(String uuid) { /** * @return the FlowFile filename */ - @ApiModelProperty( - value = "The FlowFile filename." + @Schema(description = "The FlowFile filename." ) public String getFilename() { return filename; @@ -82,8 +79,7 @@ public void setFilename(String filename) { /** * @return the FlowFile's position in the queue. */ - @ApiModelProperty( - value = "The FlowFile's position in the queue." + @Schema(description = "The FlowFile's position in the queue." ) public Integer getPosition() { return position; @@ -96,8 +92,7 @@ public void setPosition(Integer position) { /** * @return the FlowFile file size */ - @ApiModelProperty( - value = "The FlowFile file size." + @Schema(description = "The FlowFile file size." ) public Long getSize() { return size; @@ -110,8 +105,7 @@ public void setSize(Long size) { /** * @return how long this FlowFile has been enqueued */ - @ApiModelProperty( - value = "How long this FlowFile has been enqueued." + @Schema(description = "How long this FlowFile has been enqueued." ) public Long getQueuedDuration() { return queuedDuration; @@ -124,8 +118,7 @@ public void setQueuedDuration(Long queuedDuration) { /** * @return duration since the FlowFile's greatest ancestor entered the flow */ - @ApiModelProperty( - value = "Duration since the FlowFile's greatest ancestor entered the flow." + @Schema(description = "Duration since the FlowFile's greatest ancestor entered the flow." ) public Long getLineageDuration() { return lineageDuration; @@ -138,8 +131,7 @@ public void setLineageDuration(Long lineageDuration) { /** * @return when the FlowFile will no longer be penalized */ - @ApiModelProperty( - value = "How long in milliseconds until the FlowFile penalty expires." + @Schema(description = "How long in milliseconds until the FlowFile penalty expires." ) public Long getPenaltyExpiresIn() { return penaltyExpiresIn; @@ -152,8 +144,7 @@ public void setPenaltyExpiresIn(Long penaltyExpiration) { /** * @return if the FlowFile is penalized */ - @ApiModelProperty( - value = "If the FlowFile is penalized." + @Schema(description = "If the FlowFile is penalized." ) public Boolean getPenalized() { return isPenalized; @@ -166,8 +157,7 @@ public void setPenalized(Boolean penalized) { /** * @return The id of the node where this FlowFile resides. */ - @ApiModelProperty( - value = "The id of the node where this FlowFile resides." + @Schema(description = "The id of the node where this FlowFile resides." ) public String getClusterNodeId() { return clusterNodeId; @@ -180,8 +170,7 @@ public void setClusterNodeId(String clusterNodeId) { /** * @return label for the node where this FlowFile resides */ - @ApiModelProperty( - value = "The label for the node where this FlowFile resides." + @Schema(description = "The label for the node where this FlowFile resides." ) public String getClusterNodeAddress() { return clusterNodeAddress; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryBucketDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryBucketDTO.java index bc9685896a480..1a5553f5c3120 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryBucketDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryBucketDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,7 +31,7 @@ public class FlowRegistryBucketDTO { private String description; private Long created; - @ApiModelProperty("The bucket identifier") + @Schema(description = "The bucket identifier") public String getId() { return id; } @@ -40,7 +40,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The bucket name") + @Schema(description = "The bucket name") public String getName() { return name; } @@ -49,7 +49,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The bucket description") + @Schema(description = "The bucket description") public String getDescription() { return description; } @@ -58,7 +58,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty("The created timestamp of this bucket") + @Schema(description = "The created timestamp of this bucket") public Long getCreated() { return created; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryClientDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryClientDTO.java index a2867ff6cec9e..f26b3821b4c74 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryClientDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowRegistryClientDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -53,7 +53,7 @@ public class FlowRegistryClientDTO { private String validationStatus; private String annotationData; - @ApiModelProperty("The registry identifier") + @Schema(description = "The registry identifier") public String getId() { return id; } @@ -62,7 +62,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The registry name") + @Schema(description = "The registry name") public String getName() { return name; } @@ -71,7 +71,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The registry description") + @Schema(description = "The registry description") public String getDescription() { return description; } @@ -80,7 +80,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "The type of the registry client.") + @Schema(description = "The type of the registry client.") public String getType() { return type; } @@ -89,7 +89,7 @@ public void setType(String type) { this.type = type; } - @ApiModelProperty(value = "The details of the artifact that bundled this registry client type.") + @Schema(description = "The details of the artifact that bundled this registry client type.") public BundleDTO getBundle() { return bundle; } @@ -98,7 +98,7 @@ public void setBundle(BundleDTO bundle) { this.bundle = bundle; } - @ApiModelProperty(value = "The properties of the registry client.") + @Schema(description = "The properties of the registry client.") public Map getProperties() { return properties; } @@ -107,7 +107,7 @@ public void setProperties(Map properties) { this.properties = properties; } - @ApiModelProperty(value = "The descriptors for the registry client properties.") + @Schema(description = "The descriptors for the registry client properties.") public Map getDescriptors() { return descriptors; } @@ -116,7 +116,7 @@ public void setDescriptors(Map descriptors) { this.descriptors = descriptors; } - @ApiModelProperty(value = "Set of sensitive dynamic property names") + @Schema(description = "Set of sensitive dynamic property names") public Set getSensitiveDynamicPropertyNames() { return sensitiveDynamicPropertyNames; } @@ -125,8 +125,7 @@ public void setSensitiveDynamicPropertyNames(final Set sensitiveDynamicP this.sensitiveDynamicPropertyNames = sensitiveDynamicPropertyNames; } - @ApiModelProperty( - value = "Whether the registry client supports sensitive dynamic properties." + @Schema(description = "Whether the registry client supports sensitive dynamic properties." ) public Boolean getSupportsSensitiveDynamicProperties() { return supportsSensitiveDynamicProperties; @@ -136,8 +135,7 @@ public void setSupportsSensitiveDynamicProperties(final Boolean supportsSensitiv this.supportsSensitiveDynamicProperties = supportsSensitiveDynamicProperties; } - @ApiModelProperty( - value = "Whether the registry client requires elevated privileges." + @Schema(description = "Whether the registry client requires elevated privileges." ) public Boolean getRestricted() { return restricted; @@ -147,8 +145,7 @@ public void setRestricted(Boolean restricted) { this.restricted = restricted; } - @ApiModelProperty( - value = "Whether the registry client has been deprecated." + @Schema(description = "Whether the registry client has been deprecated." ) public Boolean getDeprecated() { return deprecated; @@ -161,8 +158,7 @@ public void setDeprecated(Boolean deprecated) { /** * @return whether the underlying extension is missing */ - @ApiModelProperty( - value = "Whether the underlying extension is missing." + @Schema(description = "Whether the underlying extension is missing." ) public Boolean getExtensionMissing() { return isExtensionMissing; @@ -175,8 +171,7 @@ public void setExtensionMissing(Boolean extensionMissing) { /** * @return whether this flow registry client has multiple versions available */ - @ApiModelProperty( - value = "Whether the flow registry client has multiple versions available." + @Schema(description = "Whether the flow registry client has multiple versions available." ) public Boolean getMultipleVersionsAvailable() { return setMultipleVersionsAvailable; @@ -186,8 +181,7 @@ public void setMultipleVersionsAvailable(Boolean setMultipleVersionsAvailable) { this.setMultipleVersionsAvailable = setMultipleVersionsAvailable; } - @ApiModelProperty( - value = "The annotation data for the registry client. This is how the custom UI relays configuration to the registry client." + @Schema(description = "The annotation data for the registry client. This is how the custom UI relays configuration to the registry client." ) public String getAnnotationData() { return annotationData; @@ -197,8 +191,7 @@ public void setAnnotationData(String annotationData) { this.annotationData = annotationData; } - @ApiModelProperty( - value = "Gets the validation errors from the registry client. These validation errors represent the problems with the registry client that must be resolved before " + @Schema(description = "Gets the validation errors from the registry client. These validation errors represent the problems with the registry client that must be resolved before " + "it can be used for interacting with the flow registry." ) public Collection getValidationErrors() { @@ -209,8 +202,8 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty(value = "Indicates whether the Registry Client is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Registry Client is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "Indicates whether the Registry Client is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Registry Client is valid)", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowSnippetDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowSnippetDTO.java index 931e27cfcd910..21b03bd4b3622 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowSnippetDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowSnippetDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.nio.charset.StandardCharsets; @@ -60,8 +60,7 @@ public FlowSnippetDTO(boolean newTemplate) { /** * @return connections in this flow snippet */ - @ApiModelProperty( - value = "The connections in this flow snippet." + @Schema(description = "The connections in this flow snippet." ) public Set getConnections() { return connections; @@ -75,8 +74,7 @@ public void setConnections(Set connections) { /** * @return input ports in this flow snippet */ - @ApiModelProperty( - value = "The input ports in this flow snippet." + @Schema(description = "The input ports in this flow snippet." ) public Set getInputPorts() { return inputPorts; @@ -90,8 +88,7 @@ public void setInputPorts(Set inputPorts) { /** * @return labels in this flow snippet */ - @ApiModelProperty( - value = "The labels in this flow snippet." + @Schema(description = "The labels in this flow snippet." ) public Set getLabels() { return labels; @@ -105,8 +102,7 @@ public void setLabels(Set labels) { /** * @return funnels in this flow snippet */ - @ApiModelProperty( - value = "The funnels in this flow snippet." + @Schema(description = "The funnels in this flow snippet." ) public Set getFunnels() { return funnels; @@ -120,8 +116,7 @@ public void setFunnels(Set funnels) { /** * @return output ports in this flow snippet */ - @ApiModelProperty( - value = "The output ports in this flow snippet." + @Schema(description = "The output ports in this flow snippet." ) public Set getOutputPorts() { return outputPorts; @@ -135,8 +130,7 @@ public void setOutputPorts(Set outputPorts) { /** * @return process groups in this flow snippet */ - @ApiModelProperty( - value = "The process groups in this flow snippet." + @Schema(description = "The process groups in this flow snippet." ) public Set getProcessGroups() { return processGroups; @@ -150,8 +144,7 @@ public void setProcessGroups(Set processGroups) { /** * @return processors in this flow group */ - @ApiModelProperty( - value = "The processors in this flow snippet." + @Schema(description = "The processors in this flow snippet." ) public Set getProcessors() { return processors; @@ -165,8 +158,7 @@ public void setProcessors(Set processors) { /** * @return remote process groups in this flow snippet */ - @ApiModelProperty( - value = "The remote process groups in this flow snippet." + @Schema(description = "The remote process groups in this flow snippet." ) public Set getRemoteProcessGroups() { return remoteProcessGroups; @@ -180,8 +172,7 @@ public void setRemoteProcessGroups(Set remoteProcessGroup /** * @return the Controller Services in this flow snippet */ - @ApiModelProperty( - value = "The controller services in this flow snippet." + @Schema(description = "The controller services in this flow snippet." ) public Set getControllerServices() { return controllerServices; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowUpdateRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowUpdateRequestDTO.java index 19366619f8d07..a5490bc919060 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowUpdateRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FlowUpdateRequestDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @@ -33,7 +33,7 @@ public abstract class FlowUpdateRequestDTO { protected int percentCompleted; protected String state; - @ApiModelProperty("The unique ID of the Process Group being updated") + @Schema(description = "The unique ID of the Process Group being updated") public String getProcessGroupId() { return processGroupId; } @@ -42,7 +42,7 @@ public void setProcessGroupId(String processGroupId) { this.processGroupId = processGroupId; } - @ApiModelProperty(value = "The unique ID of this request.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The unique ID of this request.", accessMode = Schema.AccessMode.READ_ONLY) public String getRequestId() { return requestId; } @@ -51,7 +51,7 @@ public void setRequestId(String requestId) { this.requestId = requestId; } - @ApiModelProperty(value = "The URI for future requests to this drop request.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The URI for future requests to this drop request.", accessMode = Schema.AccessMode.READ_ONLY) public String getUri() { return uri; } @@ -61,7 +61,7 @@ public void setUri(String uri) { } @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty(value = "The last time this request was updated.", dataType = "string", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The last time this request was updated.", type = "string", accessMode = Schema.AccessMode.READ_ONLY) public Date getLastUpdated() { return lastUpdated; } @@ -70,7 +70,7 @@ public void setLastUpdated(Date lastUpdated) { this.lastUpdated = lastUpdated; } - @ApiModelProperty(value = "Whether or not this request has completed", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Whether or not this request has completed", accessMode = Schema.AccessMode.READ_ONLY) public boolean isComplete() { return complete; } @@ -79,7 +79,7 @@ public void setComplete(boolean complete) { this.complete = complete; } - @ApiModelProperty(value = "An explanation of why this request failed, or null if this request has not failed", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "An explanation of why this request failed, or null if this request has not failed", accessMode = Schema.AccessMode.READ_ONLY) public String getFailureReason() { return failureReason; } @@ -88,7 +88,7 @@ public void setFailureReason(String reason) { this.failureReason = reason; } - @ApiModelProperty(value = "The state of the request", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The state of the request", accessMode = Schema.AccessMode.READ_ONLY) public String getState() { return state; } @@ -97,7 +97,7 @@ public void setState(String state) { this.state = state; } - @ApiModelProperty(value = "The percentage complete for the request, between 0 and 100", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The percentage complete for the request, between 0 and 100", accessMode = Schema.AccessMode.READ_ONLY) public int getPercentCompleted() { return percentCompleted; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java index 7d9f74c5a993f..9df53960ce315 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,17 +32,17 @@ public JmxMetricsResultDTO(final String beanName, final String attributeName, fi this.attributeValue = attributeValue; } - @ApiModelProperty("The bean name of the metrics bean.") + @Schema(description = "The bean name of the metrics bean.") public String getBeanName() { return beanName; } - @ApiModelProperty("The attribute name of the metrics bean's attribute.") + @Schema(description = "The attribute name of the metrics bean's attribute.") public String getAttributeName() { return attributeName; } - @ApiModelProperty("The attribute value of the the metrics bean's attribute") + @Schema(description = "The attribute value of the the metrics bean's attribute") public Object getAttributeValue() { return attributeValue; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java index 3f166301397af..319524751eaf0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Map; @@ -43,8 +43,7 @@ public LabelDTO() { /** * @return z index for this label */ - @ApiModelProperty( - value = "The z index of the label." + @Schema(description = "The z index of the label." ) public Long getzIndex() { return zIndex; @@ -59,8 +58,7 @@ public void setzIndex(Long zIndex) { * * @return The label text */ - @ApiModelProperty( - value = "The text that appears in the label." + @Schema(description = "The text that appears in the label." ) public String getLabel() { return label; @@ -73,8 +71,7 @@ public void setLabel(final String label) { /** * @return style for this label */ - @ApiModelProperty( - value = "The styles for this label (font-size : 12px, background-color : #eee, etc)." + @Schema(description = "The styles for this label (font-size : 12px, background-color : #eee, etc)." ) public Map getStyle() { return style; @@ -87,8 +84,7 @@ public void setStyle(Map style) { /** * @return height of the label in pixels when at a 1:1 scale */ - @ApiModelProperty( - value = "The height of the label in pixels when at a 1:1 scale." + @Schema(description = "The height of the label in pixels when at a 1:1 scale." ) public Double getHeight() { return height; @@ -101,8 +97,7 @@ public void setHeight(Double height) { /** * @return width of the label in pixels when at a 1:1 scale */ - @ApiModelProperty( - value = "The width of the label in pixels when at a 1:1 scale." + @Schema(description = "The width of the label in pixels when at a 1:1 scale." ) public Double getWidth() { return width; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ListingRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ListingRequestDTO.java index dd89a0b5896a2..0654a28aa9b48 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ListingRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ListingRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import org.apache.nifi.web.api.dto.util.TimestampAdapter; @@ -50,8 +50,7 @@ public class ListingRequestDTO { /** * @return the id for this listing request. */ - @ApiModelProperty( - value = "The id for this listing request." + @Schema(description = "The id for this listing request." ) public String getId() { return id; @@ -64,8 +63,7 @@ public void setId(String id) { /** * @return the URI for this listing request. */ - @ApiModelProperty( - value = "The URI for future requests to this listing request." + @Schema(description = "The URI for future requests to this listing request." ) public String getUri() { return uri; @@ -79,9 +77,8 @@ public void setUri(String uri) { * @return time the query was submitted */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp when the query was submitted.", - dataType = "string" + @Schema(description = "The timestamp when the query was submitted.", + type = "string" ) public Date getSubmissionTime() { return submissionTime; @@ -95,9 +92,8 @@ public void setSubmissionTime(Date submissionTime) { * @return the time this request was last updated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The last time this listing request was updated.", - dataType = "string" + @Schema(description = "The last time this listing request was updated.", + type = "string" ) public Date getLastUpdated() { return lastUpdated; @@ -110,8 +106,7 @@ public void setLastUpdated(Date lastUpdated) { /** * @return percent completed */ - @ApiModelProperty( - value = "The current percent complete." + @Schema(description = "The current percent complete." ) public Integer getPercentCompleted() { return percentCompleted; @@ -124,8 +119,7 @@ public void setPercentCompleted(Integer percentCompleted) { /** * @return whether the query has finished */ - @ApiModelProperty( - value = "Whether the query has finished." + @Schema(description = "Whether the query has finished." ) public Boolean getFinished() { return finished; @@ -138,8 +132,7 @@ public void setFinished(Boolean finished) { /** * @return the reason, if any, that this listing request failed */ - @ApiModelProperty( - value = "The reason, if any, that this listing request failed." + @Schema(description = "The reason, if any, that this listing request failed." ) public String getFailureReason() { return failureReason; @@ -152,8 +145,7 @@ public void setFailureReason(String failureReason) { /** * @return the current state of the listing request. */ - @ApiModelProperty( - value = "The current state of the listing request." + @Schema(description = "The current state of the listing request." ) public String getState() { return state; @@ -166,8 +158,7 @@ public void setState(String state) { /** * @return the FlowFile summaries. */ - @ApiModelProperty( - value = "The FlowFile summaries. The summaries will be populated once the request has completed." + @Schema(description = "The FlowFile summaries. The summaries will be populated once the request has completed." ) public List getFlowFileSummaries() { return flowFileSummaries; @@ -180,7 +171,7 @@ public void setFlowFileSummaries(List flowFileSummaries) { /** * @return the maximum number of FlowFileSummary objects to return */ - @ApiModelProperty(value = "The maximum number of FlowFileSummary objects to return") + @Schema(description = "The maximum number of FlowFileSummary objects to return") public Integer getMaxResults() { return maxResults; } @@ -192,7 +183,7 @@ public void setMaxResults(Integer maxResults) { /** * @return the size for the queue */ - @ApiModelProperty(value = "The size of the queue") + @Schema(description = "The size of the queue") public QueueSizeDTO getQueueSize() { return queueSize; } @@ -204,7 +195,7 @@ public void setQueueSize(QueueSizeDTO queueSize) { /** * @return whether the source is running */ - @ApiModelProperty(value = "Whether the source of the connection is running") + @Schema(description = "Whether the source of the connection is running") public Boolean getSourceRunning() { return isSourceRunning; } @@ -216,7 +207,7 @@ public void setSourceRunning(Boolean sourceRunning) { /** * @return whether the destination is running */ - @ApiModelProperty(value = "Whether the destination of the connection is running") + @Schema(description = "Whether the destination of the connection is running") public Boolean getDestinationRunning() { return isDestinationRunning; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeCountersSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeCountersSnapshotDTO.java index 611803a38ff00..2596933532784 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeCountersSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeCountersSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public class NodeCountersSnapshotDTO implements Cloneable { private CountersSnapshotDTO snapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The counters from the node.") + @Schema(description = "The counters from the node.") public CountersSnapshotDTO getSnapshot() { return snapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeDTO.java index e62b4913f7824..f5f3725b7d64d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -47,10 +47,9 @@ public class NodeDTO { * @return node's last heartbeat timestamp */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "the time of the nodes's last heartbeat.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, - dataType = "string" + @Schema(description = "the time of the nodes's last heartbeat.", + accessMode = Schema.AccessMode.READ_ONLY, + type = "string" ) public Date getHeartbeat() { return heartbeat; @@ -64,10 +63,9 @@ public void setHeartbeat(Date heartbeat) { * @return time of the node's last connection request */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The time of the node's last connection request.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, - dataType = "string" + @Schema(description = "The time of the node's last connection request.", + accessMode = Schema.AccessMode.READ_ONLY, + type = "string" ) public Date getConnectionRequested() { return connectionRequested; @@ -82,9 +80,8 @@ public void setConnectionRequested(Date connectionRequested) { * * @return The active thread count */ - @ApiModelProperty( - value = "The active threads for the NiFi on the node.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The active threads for the NiFi on the node.", + accessMode = Schema.AccessMode.READ_ONLY ) public Integer getActiveThreadCount() { return activeThreadCount; @@ -97,9 +94,8 @@ public void setActiveThreadCount(Integer activeThreadCount) { /** * @return queue for the controller */ - @ApiModelProperty( - value = "The queue the NiFi on the node.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The queue the NiFi on the node.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getQueued() { return queued; @@ -112,9 +108,8 @@ public void setQueued(String queued) { /** * @return node's host/IP address */ - @ApiModelProperty( - value = "The node's host/ip address.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The node's host/ip address.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getAddress() { return address; @@ -127,9 +122,8 @@ public void setAddress(String address) { /** * @return node ID */ - @ApiModelProperty( - value = "The id of the node.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The id of the node.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getNodeId() { return nodeId; @@ -142,9 +136,8 @@ public void setNodeId(String nodeId) { /** * @return port the node is listening for API requests */ - @ApiModelProperty( - value = "The port the node is listening for API requests.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The port the node is listening for API requests.", + accessMode = Schema.AccessMode.READ_ONLY ) public Integer getApiPort() { return apiPort; @@ -157,8 +150,7 @@ public void setApiPort(Integer port) { /** * @return node's status */ - @ApiModelProperty( - value = "The node's status." + @Schema(description = "The node's status." ) public String getStatus() { return status; @@ -171,9 +163,8 @@ public void setStatus(String status) { /** * @return node's events */ - @ApiModelProperty( - value = "The node's events.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The node's events.", + accessMode = Schema.AccessMode.READ_ONLY ) public List getEvents() { return events; @@ -186,9 +177,8 @@ public void setEvents(List events) { /** * @return the roles of the node */ - @ApiModelProperty( - value = "The roles of this node.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The roles of this node.", + accessMode = Schema.AccessMode.READ_ONLY ) public Set getRoles() { return roles; @@ -202,10 +192,9 @@ public void setRoles(Set roles) { * @return time at which this Node was last restarted */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The time at which this Node was last refreshed.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, - dataType = "string" + @Schema(description = "The time at which this Node was last refreshed.", + accessMode = Schema.AccessMode.READ_ONLY, + type = "string" ) public Date getNodeStartTime() { return nodeStartTime; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeEventDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeEventDTO.java index 60540cdc1d143..5fc493a4f7f28 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeEventDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeEventDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -36,8 +36,7 @@ public class NodeEventDTO { /** * @return category of the node event */ - @ApiModelProperty( - value = "The category of the node event." + @Schema(description = "The category of the node event." ) public String getCategory() { return category; @@ -50,8 +49,7 @@ public void setCategory(String category) { /** * @return message of the node event */ - @ApiModelProperty( - value = "The message in the node event." + @Schema(description = "The message in the node event." ) public String getMessage() { return message; @@ -65,9 +63,8 @@ public void setMessage(String message) { * @return timestamp of the node event */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The timestamp of the node event.", - dataType = "string" + @Schema(description = "The timestamp of the node event.", + type = "string" ) public Date getTimestamp() { return timestamp; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeSystemDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeSystemDiagnosticsSnapshotDTO.java index 0d0d209387b84..a6b3b8803d0a2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeSystemDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NodeSystemDiagnosticsSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public class NodeSystemDiagnosticsSnapshotDTO implements Cloneable { private SystemDiagnosticsSnapshotDTO snapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The System Diagnostics snapshot from the node.") + @Schema(description = "The System Diagnostics snapshot from the node.") public SystemDiagnosticsSnapshotDTO getSnapshot() { return snapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextDTO.java index c0e846551b7cc..8d98ddcdf78fe 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity; import org.apache.nifi.web.api.entity.ParameterEntity; import org.apache.nifi.web.api.entity.ParameterProviderConfigurationEntity; @@ -40,7 +40,7 @@ public void setId(String id) { this.identifier = id; } - @ApiModelProperty(value = "The ID the Parameter Context.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The ID the Parameter Context.", accessMode = Schema.AccessMode.READ_ONLY) public String getId() { return identifier; } @@ -49,7 +49,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The Name of the Parameter Context.") + @Schema(description = "The Name of the Parameter Context.") public String getName() { return name; } @@ -58,7 +58,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty("The Description of the Parameter Context.") + @Schema(description = "The Description of the Parameter Context.") public String getDescription() { return description; } @@ -67,7 +67,7 @@ public void setParameters(final Set parameters) { this.parameters = parameters; } - @ApiModelProperty("The Parameters for the Parameter Context") + @Schema(description = "The Parameters for the Parameter Context") public Set getParameters() { return parameters; } @@ -76,7 +76,7 @@ public void setBoundProcessGroups(final Set boundProcessGrou this.boundProcessGroups = boundProcessGroups; } - @ApiModelProperty("A list of references of Parameter Contexts from which this one inherits parameters") + @Schema(description = "A list of references of Parameter Contexts from which this one inherits parameters") public List getInheritedParameterContexts() { return inheritedParameterContexts; } @@ -85,12 +85,12 @@ public void setInheritedParameterContexts(final List getBoundProcessGroups() { return boundProcessGroups; } - @ApiModelProperty(value = "Optional configuration for a Parameter Provider") + @Schema(description = "Optional configuration for a Parameter Provider") public ParameterProviderConfigurationEntity getParameterProviderConfiguration() { return parameterProviderConfiguration; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextReferenceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextReferenceDTO.java index 37ab22741804b..add9695493cf2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextReferenceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextReferenceDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,12 +29,12 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The ID of the Parameter Context") + @Schema(description = "The ID of the Parameter Context") public String getId() { return id; } - @ApiModelProperty("The name of the Parameter Context") + @Schema(description = "The name of the Parameter Context") public String getName() { return name; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextUpdateRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextUpdateRequestDTO.java index 5038debf5dffc..7688298b15579 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextUpdateRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextUpdateRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AffectedComponentEntity; import jakarta.xml.bind.annotation.XmlType; @@ -27,8 +27,8 @@ public class ParameterContextUpdateRequestDTO extends AsynchronousRequestDTO referencingComponents; - @ApiModelProperty(value = "The Parameter Context that is being operated on. This may not be populated until the request has successfully completed.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The Parameter Context that is being operated on. This may not be populated until the request has successfully completed.", + accessMode = Schema.AccessMode.READ_ONLY) public ParameterContextDTO getParameterContext() { return parameterContext; } @@ -37,7 +37,7 @@ public void setParameterContext(final ParameterContextDTO parameterContext) { this.parameterContext = parameterContext; } - @ApiModelProperty(value = "The components that are referenced by the update.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The components that are referenced by the update.", accessMode = Schema.AccessMode.READ_ONLY) public Set getReferencingComponents() { return referencingComponents; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextValidationRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextValidationRequestDTO.java index ac48b9e1d9407..a1112f847eb6a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextValidationRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterContextValidationRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ComponentValidationResultsEntity; import jakarta.xml.bind.annotation.XmlType; @@ -26,8 +26,8 @@ public class ParameterContextValidationRequestDTO extends AsynchronousRequestDTO private ParameterContextDTO parameterContext; private ComponentValidationResultsEntity componentValidationResults; - @ApiModelProperty(value = "The Validation Results that were calculated for each component. This value may not be set until the request completes.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The Validation Results that were calculated for each component. This value may not be set until the request completes.", + accessMode = Schema.AccessMode.READ_ONLY) public ComponentValidationResultsEntity getComponentValidationResults() { return componentValidationResults; } @@ -36,7 +36,7 @@ public void setComponentValidationResults(final ComponentValidationResultsEntity this.componentValidationResults = componentValidationResults; } - @ApiModelProperty("The Parameter Context that is being operated on.") + @Schema(description = "The Parameter Context that is being operated on.") public ParameterContextDTO getParameterContext() { return parameterContext; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java index 96277e5007e75..c50857da9a4fe 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AffectedComponentEntity; import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity; @@ -35,7 +35,7 @@ public class ParameterDTO { private ParameterContextReferenceEntity parameterContext; private Boolean inherited; - @ApiModelProperty("The name of the Parameter") + @Schema(description = "The name of the Parameter") public String getName() { return name; } @@ -44,7 +44,7 @@ public void setName(final String name) { this.name = name; } - @ApiModelProperty(value = "Whether or not the Parameter is inherited from another context", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Whether or not the Parameter is inherited from another context", accessMode = Schema.AccessMode.READ_ONLY) public Boolean getInherited() { return inherited; } @@ -53,7 +53,7 @@ public void setInherited(final Boolean inherited) { this.inherited = inherited; } - @ApiModelProperty("The description of the Parameter") + @Schema(description = "The description of the Parameter") public String getDescription() { return description; } @@ -62,7 +62,7 @@ public void setDescription(final String description) { this.description = description; } - @ApiModelProperty("Whether or not the Parameter is sensitive") + @Schema(description = "Whether or not the Parameter is sensitive") public Boolean getSensitive() { return sensitive; } @@ -71,7 +71,7 @@ public void setSensitive(final Boolean sensitive) { this.sensitive = sensitive; } - @ApiModelProperty("Whether or not the Parameter is provided by a ParameterProvider") + @Schema(description = "Whether or not the Parameter is provided by a ParameterProvider") public Boolean getProvided() { return provided; } @@ -80,7 +80,7 @@ public void setProvided(final Boolean provided) { this.provided = provided; } - @ApiModelProperty("The value of the Parameter") + @Schema(description = "The value of the Parameter") public String getValue() { return value; } @@ -89,8 +89,13 @@ public void setValue(final String value) { this.value = value; } - @ApiModelProperty("Whether or not the value of the Parameter was removed. When a request is made to change a parameter, the value may be null. The absence of the value may be used either to " + - "indicate that the value is not to be changed, or that the value is to be set to null (i.e., removed). This denotes which of the two scenarios is being encountered.") + @Schema(description = """ + Whether or not the value of the Parameter was removed. + When a request is made to change a parameter, the value may be null. + The absence of the value may be used either to indicate that the value is not to be changed, or that the value is to be set to null (i.e., removed). + This denotes which of the two scenarios is being encountered. + """ + ) public Boolean getValueRemoved() { return valueRemoved; } @@ -99,7 +104,7 @@ public void setValueRemoved(final Boolean valueRemoved) { this.valueRemoved = valueRemoved; } - @ApiModelProperty("The set of all components in the flow that are referencing this Parameter") + @Schema(description = "The set of all components in the flow that are referencing this Parameter") public Set getReferencingComponents() { return referencingComponents; } @@ -108,7 +113,7 @@ public void setParameterContext(final ParameterContextReferenceEntity parameterC this.parameterContext = parameterContext; } - @ApiModelProperty("A reference to the Parameter Context that contains this one") + @Schema(description = "A reference to the Parameter Context that contains this one") public ParameterContextReferenceEntity getParameterContext() { return parameterContext; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderApplyParametersRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderApplyParametersRequestDTO.java index 1eca8dbe59c00..058422cda1cd1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderApplyParametersRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderApplyParametersRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AffectedComponentEntity; import org.apache.nifi.web.api.entity.ParameterContextUpdateEntity; @@ -30,8 +30,8 @@ public class ParameterProviderApplyParametersRequestDTO extends AsynchronousRequ private List parameterContextUpdates; private Set referencingComponents; - @ApiModelProperty(value = "The Parameter Contexts updated by this Parameter Provider. This may not be populated until the request has successfully completed.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The Parameter Contexts updated by this Parameter Provider. This may not be populated until the request has successfully completed.", + accessMode = Schema.AccessMode.READ_ONLY) public List getParameterContextUpdates() { return parameterContextUpdates; } @@ -40,8 +40,8 @@ public void setParameterContextUpdates(final List this.parameterContextUpdates = parameterContextUpdates; } - @ApiModelProperty(value = "The Parameter Provider that is being operated on. This may not be populated until the request has successfully completed.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The Parameter Provider that is being operated on. This may not be populated until the request has successfully completed.", + accessMode = Schema.AccessMode.READ_ONLY) public ParameterProviderDTO getParameterProvider() { return parameterProvider; } @@ -50,7 +50,7 @@ public void setParameterProvider(final ParameterProviderDTO parameterProvider) { this.parameterProvider = parameterProvider; } - @ApiModelProperty(value = "The components that are referenced by the update.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The components that are referenced by the update.", accessMode = Schema.AccessMode.READ_ONLY) public Set getReferencingComponents() { return referencingComponents; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderConfigurationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderConfigurationDTO.java index d0b32737d6366..9e3506c5cf728 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderConfigurationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderConfigurationDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -27,7 +27,7 @@ public class ParameterProviderConfigurationDTO { private String parameterGroupName; private Boolean isSynchronized; - @ApiModelProperty("The ID of the Parameter Provider") + @Schema(description = "The ID of the Parameter Provider") public String getParameterProviderId() { return parameterProviderId; } @@ -36,7 +36,7 @@ public void setParameterProviderId(String parameterProviderId) { this.parameterProviderId = parameterProviderId; } - @ApiModelProperty("The name of the Parameter Provider") + @Schema(description = "The name of the Parameter Provider") public String getParameterProviderName() { return parameterProviderName; } @@ -45,7 +45,7 @@ public void setParameterProviderName(String parameterProviderName) { this.parameterProviderName = parameterProviderName; } - @ApiModelProperty("The Parameter Group name that maps to the Parameter Context") + @Schema(description = "The Parameter Group name that maps to the Parameter Context") public String getParameterGroupName() { return parameterGroupName; } @@ -54,7 +54,7 @@ public void setParameterGroupName(String parameterGroupName) { this.parameterGroupName = parameterGroupName; } - @ApiModelProperty("True if the Parameter Context should receive the parameters from the mapped Parameter Group") + @Schema(description = "True if the Parameter Context should receive the parameters from the mapped Parameter Group") public Boolean getSynchronized() { return isSynchronized; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java index 73aadb749762f..635bf925d4bb7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AffectedComponentEntity; import org.apache.nifi.web.api.entity.ParameterProviderReferencingComponentEntity; import org.apache.nifi.web.api.entity.ParameterGroupConfigurationEntity; @@ -61,8 +61,7 @@ public class ParameterProviderDTO extends ComponentDTO { /** * @return user-defined name of the parameter provider */ - @ApiModelProperty( - value = "The name of the parameter provider." + @Schema(description = "The name of the parameter provider." ) public String getName() { return name; @@ -72,7 +71,7 @@ public void setName(final String name) { this.name = name; } - @ApiModelProperty("The set of all components in the flow that are referencing Parameters provided by this provider") + @Schema(description = "The set of all components in the flow that are referencing Parameters provided by this provider") public Set getAffectedComponents() { return affectedComponents; } @@ -85,7 +84,7 @@ public void setReferencingParameterContexts(final Set getParameterStatus() { return parameterStatus; } @@ -94,13 +93,12 @@ public void setParameterStatus(Set parameterStatus) { this.parameterStatus = parameterStatus; } - @ApiModelProperty(value = "The Parameter Contexts that reference this Parameter Provider", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The Parameter Contexts that reference this Parameter Provider", accessMode = Schema.AccessMode.READ_ONLY) public Set getReferencingParameterContexts() { return referencingParameterContexts; } - @ApiModelProperty( - value = "Configuration for any fetched parameter groups." + @Schema(description = "Configuration for any fetched parameter groups." ) public Collection getParameterGroupConfigurations() { return parameterGroupConfigurations; @@ -113,8 +111,7 @@ public void setParameterGroupConfigurations(final Collection getProperties() { return properties; @@ -241,8 +230,7 @@ public void setProperties(Map properties) { /** * @return Map of property name to descriptor */ - @ApiModelProperty( - value = "The descriptors for the parameter providers properties." + @Schema(description = "The descriptors for the parameter providers properties." ) public Map getDescriptors() { return descriptors; @@ -255,8 +243,7 @@ public void setDescriptors(Map descriptors) { /** * @return the URL for this parameter provider custom configuration UI if applicable. Null otherwise */ - @ApiModelProperty( - value = "The URL for the custom configuration UI for the parameter provider." + @Schema(description = "The URL for the custom configuration UI for the parameter provider." ) public String getCustomUiUrl() { return customUiUrl; @@ -269,8 +256,7 @@ public void setCustomUiUrl(String customUiUrl) { /** * @return currently configured annotation data for the parameter provider */ - @ApiModelProperty( - value = "The annotation data for the parameter provider. This is how the custom UI relays configuration to the parameter provider." + @Schema(description = "The annotation data for the parameter provider. This is how the custom UI relays configuration to the parameter provider." ) public String getAnnotationData() { return annotationData; @@ -285,8 +271,7 @@ public void setAnnotationData(String annotationData) { * * @return The validation errors */ - @ApiModelProperty( - value = "Gets the validation errors from the parameter provider. These validation errors represent the problems with the parameter provider that must be resolved before " + @Schema(description = "Gets the validation errors from the parameter provider. These validation errors represent the problems with the parameter provider that must be resolved before " + "it can be scheduled to run." ) public Collection getValidationErrors() { @@ -297,8 +282,8 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty(value = "Indicates whether the Parameter Provider is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Parameter Provider is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "Indicates whether the Parameter Provider is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Parameter Provider is valid)", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderReferencingComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderReferencingComponentDTO.java index 6eacc71dd6ece..025b8be24654a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderReferencingComponentDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterProviderReferencingComponentDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,8 +32,7 @@ public class ParameterProviderReferencingComponentDTO { /** * @return id for this component referencing a parameter provider */ - @ApiModelProperty( - value = "The id of the component referencing a parameter provider." + @Schema(description = "The id of the component referencing a parameter provider." ) public String getId() { return id; @@ -46,8 +45,7 @@ public void setId(String id) { /** * @return name for this component referencing a parameter provider */ - @ApiModelProperty( - value = "The name of the component referencing a parameter provider." + @Schema(description = "The name of the component referencing a parameter provider." ) public String getName() { return name; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java index eb373e9a1bcf1..c88e29209f474 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ParameterStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ParameterEntity; import jakarta.xml.bind.annotation.XmlType; @@ -26,7 +26,7 @@ public class ParameterStatusDTO { private ParameterEntity parameter; private ParameterStatus status; - @ApiModelProperty("The name of the Parameter") + @Schema(description = "The name of the Parameter") public ParameterEntity getParameter() { return parameter; } @@ -35,7 +35,7 @@ public void setParameter(final ParameterEntity parameter) { this.parameter = parameter; } - @ApiModelProperty("Indicates the status of the parameter, compared to the existing parameter context") + @Schema(description = "Indicates the status of the parameter, compared to the existing parameter context") public ParameterStatus getStatus() { return status; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PermissionsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PermissionsDTO.java index 70a1a91293ef5..32f283912c9dd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PermissionsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PermissionsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,9 +32,8 @@ public class PermissionsDTO implements ReadablePermission, WritablePermission { /** * @return Indicates whether the user can read a given resource. */ - @ApiModelProperty( - value = "Indicates whether the user can read a given resource.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Indicates whether the user can read a given resource.", + accessMode = Schema.AccessMode.READ_ONLY ) @Override public Boolean getCanRead() { @@ -49,9 +48,8 @@ public void setCanRead(Boolean canRead) { /** * @return Indicates whether the user can write a given resource. */ - @ApiModelProperty( - value = "Indicates whether the user can write a given resource.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Indicates whether the user can write a given resource.", + accessMode = Schema.AccessMode.READ_ONLY ) @Override public Boolean getCanWrite() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java index c8ac9b328f1b0..8e2364aa95551 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -41,8 +41,7 @@ public class PortDTO extends ComponentDTO { /** * @return name of this port */ - @ApiModelProperty( - value = "The name of the port." + @Schema(description = "The name of the port." ) public String getName() { return name; @@ -55,8 +54,7 @@ public void setName(final String name) { /** * @return The state of this port. Possible states are 'RUNNING', 'STOPPED', and 'DISABLED' */ - @ApiModelProperty( - value = "The state of the port.", + @Schema(description = "The state of the port.", allowableValues = "RUNNING, STOPPED, DISABLED" ) public String getState() { @@ -72,8 +70,7 @@ public void setState(String state) { * * @return The type of port */ - @ApiModelProperty( - value = "The type of port.", + @Schema(description = "The type of port.", allowableValues = "INPUT_PORT, OUTPUT_PORT" ) public String getType() { @@ -87,8 +84,7 @@ public void setType(String type) { /** * @return number of tasks that should be concurrently scheduled for this port */ - @ApiModelProperty( - value = "The number of tasks that should be concurrently scheduled for the port." + @Schema(description = "The number of tasks that should be concurrently scheduled for the port." ) public Integer getConcurrentlySchedulableTaskCount() { return concurrentlySchedulableTaskCount; @@ -101,8 +97,7 @@ public void setConcurrentlySchedulableTaskCount(Integer concurrentlySchedulableT /** * @return comments for this port */ - @ApiModelProperty( - value = "The comments for the port." + @Schema(description = "The comments for the port." ) public String getComments() { return comments; @@ -115,8 +110,7 @@ public void setComments(String comments) { /** * @return whether this port has incoming or outgoing connections to a remote NiFi. This is only applicable when the port is allowed to be accessed remotely. */ - @ApiModelProperty( - value = "Whether the port has incoming or output connections to a remote NiFi. This is only applicable when the port is allowed to be accessed remotely." + @Schema(description = "Whether the port has incoming or output connections to a remote NiFi. This is only applicable when the port is allowed to be accessed remotely." ) public Boolean isTransmitting() { return transmitting; @@ -131,8 +125,7 @@ public void setTransmitting(Boolean transmitting) { * * @return The validation errors */ - @ApiModelProperty( - value = "Gets the validation errors from this port. These validation errors represent the problems with the port that must be resolved before it can be started." + @Schema(description = "Gets the validation errors from this port. These validation errors represent the problems with the port that must be resolved before it can be started." ) public Collection getValidationErrors() { return validationErrors; @@ -146,8 +139,7 @@ public void setValidationErrors(Collection validationErrors) { /** * @return whether this port can be accessed remotely via Site-to-Site protocol. */ - @ApiModelProperty( - value = "Whether this port can be accessed remotely via Site-to-Site protocol." + @Schema(description = "Whether this port can be accessed remotely via Site-to-Site protocol." ) public Boolean getAllowRemoteAccess() { return allowRemoteAccess; @@ -157,7 +149,7 @@ public void setAllowRemoteAccess(Boolean allowRemoteAccess) { this.allowRemoteAccess = allowRemoteAccess; } - @ApiModelProperty(value = "Specifies how the Port functions", + @Schema(description = "Specifies how the Port functions", allowableValues = "STANDARD, FAILURE" ) public String getPortFunction() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PositionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PositionDTO.java index 53bcc4fc14360..35844d1e651e7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PositionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PositionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -41,8 +41,7 @@ public PositionDTO(Double x, Double y) { /** * @return the x coordinate */ - @ApiModelProperty( - value = "The x coordinate." + @Schema(description = "The x coordinate." ) public Double getX() { return x; @@ -55,8 +54,7 @@ public void setX(Double x) { /** * @return the y coordinate */ - @ApiModelProperty( - value = "The y coordinate." + @Schema(description = "The y coordinate." ) public Double getY() { return y; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PreviousValueDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PreviousValueDTO.java index d7706177f72bf..6669bc56d7a5e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PreviousValueDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PreviousValueDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -36,8 +36,7 @@ public class PreviousValueDTO { /** * @return previous value */ - @ApiModelProperty( - value = "The previous value." + @Schema(description = "The previous value." ) public String getPreviousValue() { return previousValue; @@ -51,9 +50,8 @@ public void setPreviousValue(String previousValue) { * @return when it was modified */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The timestamp when the value was modified.", - dataType = "string" + @Schema(description = "The timestamp when the value was modified.", + type = "string" ) public Date getTimestamp() { return timestamp; @@ -66,8 +64,7 @@ public void setTimestamp(Date timestamp) { /** * @return user who changed the previous value */ - @ApiModelProperty( - value = "The user who changed the previous value." + @Schema(description = "The user who changed the previous value." ) public String getUserIdentity() { return userIdentity; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java index 41ba6cad4d022..b2b22d0f708bb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.NumberUtil; import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity; @@ -74,8 +74,7 @@ public ProcessGroupDTO() { * * @return The name of this Process Group */ - @ApiModelProperty( - value = "The name of the process group." + @Schema(description = "The name of the process group." ) public String getName() { return name; @@ -88,8 +87,7 @@ public void setName(String name) { /** * @return comments for this process group */ - @ApiModelProperty( - value = "The comments for the process group." + @Schema(description = "The comments for the process group." ) public String getComments() { return comments; @@ -102,8 +100,7 @@ public void setComments(String comments) { /** * @return contents of this process group. */ - @ApiModelProperty( - value = "The contents of this process group." + @Schema(description = "The contents of this process group." ) public FlowSnippetDTO getContents() { return contents; @@ -116,9 +113,8 @@ public void setContents(FlowSnippetDTO contents) { /** * @return number of input ports contained in this process group */ - @ApiModelProperty( - value = "The number of input ports in the process group.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The number of input ports in the process group.", + accessMode = Schema.AccessMode.READ_ONLY ) public Integer getInputPortCount() { return NumberUtil.sumNullableIntegers(localInputPortCount, publicInputPortCount); @@ -134,8 +130,7 @@ public void setInputPortCount(Integer inputPortCount) { /** * @return number of local input ports contained in this process group */ - @ApiModelProperty( - value = "The number of local input ports in the process group." + @Schema(description = "The number of local input ports in the process group." ) public Integer getLocalInputPortCount() { return localInputPortCount; @@ -148,8 +143,7 @@ public void setLocalInputPortCount(Integer localInputPortCount) { /** * @return number of public input ports contained in this process group */ - @ApiModelProperty( - value = "The number of public input ports in the process group." + @Schema(description = "The number of public input ports in the process group." ) public Integer getPublicInputPortCount() { return publicInputPortCount; @@ -162,8 +156,7 @@ public void setPublicInputPortCount(Integer publicInputPortCount) { /** * @return number of invalid components in this process group */ - @ApiModelProperty( - value = "The number of invalid components in the process group." + @Schema(description = "The number of invalid components in the process group." ) public Integer getInvalidCount() { return invalidCount; @@ -176,9 +169,8 @@ public void setInvalidCount(Integer invalidCount) { /** * @return number of output ports in this process group */ - @ApiModelProperty( - value = "The number of output ports in the process group.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The number of output ports in the process group.", + accessMode = Schema.AccessMode.READ_ONLY ) public Integer getOutputPortCount() { return NumberUtil.sumNullableIntegers(localOutputPortCount, publicOutputPortCount); @@ -191,8 +183,7 @@ public void setOutputPortCount(Integer outputPortCount) { /** * @return number of local output ports in this process group */ - @ApiModelProperty( - value = "The number of local output ports in the process group." + @Schema(description = "The number of local output ports in the process group." ) public Integer getLocalOutputPortCount() { return localOutputPortCount; @@ -205,8 +196,7 @@ public void setLocalOutputPortCount(Integer localOutputPortCount) { /** * @return number of public output ports in this process group */ - @ApiModelProperty( - value = "The number of public output ports in the process group." + @Schema(description = "The number of public output ports in the process group." ) public Integer getPublicOutputPortCount() { return publicOutputPortCount; @@ -219,8 +209,7 @@ public void setPublicOutputPortCount(Integer publicOutputPortCount) { /** * @return number of running component in this process group */ - @ApiModelProperty( - value = "The number of running components in this process group." + @Schema(description = "The number of running components in this process group." ) public Integer getRunningCount() { return runningCount; @@ -233,8 +222,7 @@ public void setRunningCount(Integer runningCount) { /** * @return number of stopped components in this process group */ - @ApiModelProperty( - value = "The number of stopped components in the process group." + @Schema(description = "The number of stopped components in the process group." ) public Integer getStoppedCount() { return stoppedCount; @@ -247,8 +235,7 @@ public void setStoppedCount(Integer stoppedCount) { /** * @return number of disabled components in this process group */ - @ApiModelProperty( - value = "The number of disabled components in the process group." + @Schema(description = "The number of disabled components in the process group." ) public Integer getDisabledCount() { return disabledCount; @@ -261,8 +248,7 @@ public void setDisabledCount(Integer disabledCount) { /** * @return number of active remote ports in this process group */ - @ApiModelProperty( - value = "The number of active remote ports in the process group." + @Schema(description = "The number of active remote ports in the process group." ) public Integer getActiveRemotePortCount() { return activeRemotePortCount; @@ -275,8 +261,7 @@ public void setActiveRemotePortCount(Integer activeRemotePortCount) { /** * @return number of inactive remote ports in this process group */ - @ApiModelProperty( - value = "The number of inactive remote ports in the process group." + @Schema(description = "The number of inactive remote ports in the process group." ) public Integer getInactiveRemotePortCount() { return inactiveRemotePortCount; @@ -286,7 +271,7 @@ public void setInactiveRemotePortCount(Integer inactiveRemotePortCount) { this.inactiveRemotePortCount = inactiveRemotePortCount; } - @ApiModelProperty("The number of up to date versioned process groups in the process group.") + @Schema(description = "The number of up to date versioned process groups in the process group.") public Integer getUpToDateCount() { return upToDateCount; } @@ -295,7 +280,7 @@ public void setUpToDateCount(Integer upToDateCount) { this.upToDateCount = upToDateCount; } - @ApiModelProperty("The number of locally modified versioned process groups in the process group.") + @Schema(description = "The number of locally modified versioned process groups in the process group.") public Integer getLocallyModifiedCount() { return locallyModifiedCount; } @@ -304,7 +289,7 @@ public void setLocallyModifiedCount(Integer locallyModifiedCount) { this.locallyModifiedCount = locallyModifiedCount; } - @ApiModelProperty("The number of stale versioned process groups in the process group.") + @Schema(description = "The number of stale versioned process groups in the process group.") public Integer getStaleCount() { return staleCount; } @@ -313,7 +298,7 @@ public void setStaleCount(Integer staleCount) { this.staleCount = staleCount; } - @ApiModelProperty("The number of locally modified and stale versioned process groups in the process group.") + @Schema(description = "The number of locally modified and stale versioned process groups in the process group.") public Integer getLocallyModifiedAndStaleCount() { return locallyModifiedAndStaleCount; } @@ -322,7 +307,7 @@ public void setLocallyModifiedAndStaleCount(Integer locallyModifiedAndStaleCount this.locallyModifiedAndStaleCount = locallyModifiedAndStaleCount; } - @ApiModelProperty("The number of versioned process groups in the process group that are unable to sync to a registry.") + @Schema(description = "The number of versioned process groups in the process group that are unable to sync to a registry.") public Integer getSyncFailureCount() { return syncFailureCount; } @@ -331,7 +316,7 @@ public void setSyncFailureCount(Integer syncFailureCount) { this.syncFailureCount = syncFailureCount; } - @ApiModelProperty("The Version Control information that indicates which Flow Registry, and where in the Flow Registry, " + @Schema(description = "The Version Control information that indicates which Flow Registry, and where in the Flow Registry, " + "this Process Group is tracking to; or null if this Process Group is not under version control") public VersionControlInformationDTO getVersionControlInformation() { return versionControlInformation; @@ -341,7 +326,7 @@ public void setVersionControlInformation(final VersionControlInformationDTO vers this.versionControlInformation = versionControlInformation; } - @ApiModelProperty("The Parameter Context that this Process Group is bound to.") + @Schema(description = "The Parameter Context that this Process Group is bound to.") public ParameterContextReferenceEntity getParameterContext() { return parameterContext; } @@ -350,7 +335,7 @@ public void setParameterContext(final ParameterContextReferenceEntity parameterC this.parameterContext = parameterContext; } - @ApiModelProperty(value = "The FlowFile Concurrency for this Process Group.", allowableValues = "UNBOUNDED, SINGLE_FLOWFILE_PER_NODE, SINGLE_BATCH_PER_NODE") + @Schema(description = "The FlowFile Concurrency for this Process Group.", allowableValues = "UNBOUNDED, SINGLE_FLOWFILE_PER_NODE, SINGLE_BATCH_PER_NODE") public String getFlowfileConcurrency() { return flowfileConcurrency; } @@ -359,7 +344,7 @@ public void setFlowfileConcurrency(final String flowfileConcurrency) { this.flowfileConcurrency = flowfileConcurrency; } - @ApiModelProperty(value = "The Outbound Policy that is used for determining how FlowFiles should be transferred out of the Process Group.", + @Schema(description = "The Outbound Policy that is used for determining how FlowFiles should be transferred out of the Process Group.", allowableValues = "STREAM_WHEN_AVAILABLE, BATCH_OUTPUT") public String getFlowfileOutboundPolicy() { return flowfileOutboundPolicy; @@ -369,7 +354,7 @@ public void setFlowfileOutboundPolicy(final String flowfileOutboundPolicy) { this.flowfileOutboundPolicy = flowfileOutboundPolicy; } - @ApiModelProperty(value = "The default FlowFile Expiration for this Process Group.") + @Schema(description = "The default FlowFile Expiration for this Process Group.") public String getDefaultFlowFileExpiration() { return defaultFlowFileExpiration; } @@ -378,7 +363,7 @@ public void setDefaultFlowFileExpiration(String defaultFlowFileExpiration) { this.defaultFlowFileExpiration = defaultFlowFileExpiration; } - @ApiModelProperty(value = "Default value used in this Process Group for the maximum number of objects that can be queued before back pressure is applied.") + @Schema(description = "Default value used in this Process Group for the maximum number of objects that can be queued before back pressure is applied.") public Long getDefaultBackPressureObjectThreshold() { return defaultBackPressureObjectThreshold; } @@ -387,7 +372,7 @@ public void setDefaultBackPressureObjectThreshold(final Long defaultBackPressure this.defaultBackPressureObjectThreshold = defaultBackPressureObjectThreshold; } - @ApiModelProperty(value = "Default value used in this Process Group for the maximum data size of objects that can be queued before back pressure is applied.") + @Schema(description = "Default value used in this Process Group for the maximum data size of objects that can be queued before back pressure is applied.") public String getDefaultBackPressureDataSizeThreshold() { return defaultBackPressureDataSizeThreshold; } @@ -396,7 +381,7 @@ public void setDefaultBackPressureDataSizeThreshold(final String defaultBackPres this.defaultBackPressureDataSizeThreshold = defaultBackPressureDataSizeThreshold; } - @ApiModelProperty(value = "The log file suffix for this Process Group for dedicated logging.") + @Schema(description = "The log file suffix for this Process Group for dedicated logging.") public String getLogFileSuffix() { return logFileSuffix; } @@ -405,7 +390,7 @@ public void setLogFileSuffix(final String logFileSuffix) { this.logFileSuffix = logFileSuffix; } - @ApiModelProperty(value = "The Execution Engine that should be used to run the flow represented by this Process Group.", + @Schema(description = "The Execution Engine that should be used to run the flow represented by this Process Group.", allowableValues = "STATELESS, STANDARD, INHERITED") public String getExecutionEngine() { return executionEngine; @@ -415,7 +400,7 @@ public void setExecutionEngine(final String executionEngine) { this.executionEngine = executionEngine; } - @ApiModelProperty(value = "If the Process Group is configured to run in using the Stateless Engine, represents the current state. Otherwise, will be STOPPED.", + @Schema(description = "If the Process Group is configured to run in using the Stateless Engine, represents the current state. Otherwise, will be STOPPED.", allowableValues = "STOPPED, RUNNING") public String getStatelessGroupScheduledState() { return statelessGroupScheduledState; @@ -425,7 +410,7 @@ public void setStatelessGroupScheduledState(final String state) { this.statelessGroupScheduledState = state; } - @ApiModelProperty("The maximum number of concurrent tasks to use when running the flow using the Stateless Engine") + @Schema(description = "The maximum number of concurrent tasks to use when running the flow using the Stateless Engine") public Integer getMaxConcurrentTasks() { return maxConcurrentTasks; } @@ -434,7 +419,7 @@ public void setMaxConcurrentTasks(final Integer maxConcurrentTasks) { this.maxConcurrentTasks = maxConcurrentTasks; } - @ApiModelProperty("The maximum amount of time that the flow can be run using the Stateless Engine before the flow times out") + @Schema(description = "The maximum amount of time that the flow can be run using the Stateless Engine before the flow times out") public String getStatelessFlowTimeout() { return statelessFlowTimeout; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupNameDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupNameDTO.java index c12b96810542f..bc2cd867fdb74 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupNameDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupNameDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The ID of the Process Group") + @Schema(description = "The ID of the Process Group") public String getId() { return id; } @@ -38,7 +38,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The name of the Process Group, or the ID of the Process Group if the user does not have the READ policy for the Process Group") + @Schema(description = "The name of the Process Group, or the ID of the Process Group if the user does not have the READ policy for the Process Group") public String getName() { return name; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java index 8be3c0f824105..5f8bd5a7bf96f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorConfigDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Map; @@ -67,8 +67,7 @@ public ProcessorConfigDTO() { * * @return The scheduling period */ - @ApiModelProperty( - value = "The frequency with which to schedule the processor. The format of the value will depend on th value of schedulingStrategy." + @Schema(description = "The frequency with which to schedule the processor. The format of the value will depend on th value of schedulingStrategy." ) public String getSchedulingPeriod() { return schedulingPeriod; @@ -83,8 +82,7 @@ public void setSchedulingPeriod(String setSchedulingPeriod) { * * @return scheduling strategy */ - @ApiModelProperty( - value = "Indicates how the processor should be scheduled to run." + @Schema(description = "Indicates how the processor should be scheduled to run." ) public String getSchedulingStrategy() { return schedulingStrategy; @@ -99,8 +97,7 @@ public void setSchedulingStrategy(String schedulingStrategy) { * * @return execution node */ - @ApiModelProperty( - value = "Indicates the node where the process will execute." + @Schema(description = "Indicates the node where the process will execute." ) public String getExecutionNode() { return executionNode; @@ -113,8 +110,7 @@ public void setExecutionNode(String executionNode) { /** * @return the amount of time that is used when this processor penalizes a flowfile */ - @ApiModelProperty( - value = "The amount of time that is used when the process penalizes a flowfile." + @Schema(description = "The amount of time that is used when the process penalizes a flowfile." ) public String getPenaltyDuration() { return penaltyDuration; @@ -127,8 +123,7 @@ public void setPenaltyDuration(String penaltyDuration) { /** * @return amount of time must elapse before this processor is scheduled again when yielding */ - @ApiModelProperty( - value = "The amount of time that must elapse before this processor is scheduled again after yielding." + @Schema(description = "The amount of time that must elapse before this processor is scheduled again after yielding." ) public String getYieldDuration() { return yieldDuration; @@ -141,8 +136,7 @@ public void setYieldDuration(String yieldDuration) { /** * @return the level at this this processor will report bulletins */ - @ApiModelProperty( - value = "The level at which the processor will report bulletins." + @Schema(description = "The level at which the processor will report bulletins." ) public String getBulletinLevel() { return bulletinLevel; @@ -157,8 +151,7 @@ public void setBulletinLevel(String bulletinLevel) { * * @return the concurrently schedulable task count */ - @ApiModelProperty( - value = "The number of tasks that should be concurrently schedule for the processor. If the processor doesn't allow parallol processing then any positive input will be ignored." + @Schema(description = "The number of tasks that should be concurrently schedule for the processor. If the processor doesn't allow parallol processing then any positive input will be ignored." ) public Integer getConcurrentlySchedulableTaskCount() { return concurrentlySchedulableTaskCount; @@ -171,8 +164,7 @@ public void setConcurrentlySchedulableTaskCount(Integer concurrentlySchedulableT /** * @return whether or not this Processor is Loss Tolerant */ - @ApiModelProperty( - value = "Whether the processor is loss tolerant." + @Schema(description = "Whether the processor is loss tolerant." ) public Boolean isLossTolerant() { return lossTolerant; @@ -185,8 +177,7 @@ public void setLossTolerant(final Boolean lossTolerant) { /** * @return the comments */ - @ApiModelProperty( - value = "The comments for the processor." + @Schema(description = "The comments for the processor." ) public String getComments() { return comments; @@ -202,8 +193,7 @@ public void setComments(String comments) { * * @return The optional properties */ - @ApiModelProperty( - value = "The properties for the processor. Properties whose value is not set will only contain the property name." + @Schema(description = "The properties for the processor. Properties whose value is not set will only contain the property name." ) public Map getProperties() { return properties; @@ -216,8 +206,7 @@ public void setProperties(Map properties) { /** * @return descriptors for this processor's properties */ - @ApiModelProperty( - value = "Descriptors for the processor's properties." + @Schema(description = "Descriptors for the processor's properties." ) public Map getDescriptors() { return descriptors; @@ -230,8 +219,7 @@ public void setDescriptors(Map descriptors) { /** * @return Set of sensitive dynamic property names */ - @ApiModelProperty( - value = "Set of sensitive dynamic property names" + @Schema(description = "Set of sensitive dynamic property names" ) public Set getSensitiveDynamicPropertyNames() { return sensitiveDynamicPropertyNames; @@ -246,8 +234,7 @@ public void setSensitiveDynamicPropertyNames(final Set sensitiveDynamicP * * @return The annotation data */ - @ApiModelProperty( - value = "The annotation data for the processor used to relay configuration between a custom UI and the procesosr." + @Schema(description = "The annotation data for the processor used to relay configuration between a custom UI and the procesosr." ) public String getAnnotationData() { return annotationData; @@ -260,8 +247,7 @@ public void setAnnotationData(String annotationData) { /** * @return the URL for this processors custom configuration UI if applicable. Null otherwise. */ - @ApiModelProperty( - value = "The URL for the processor's custom configuration UI if applicable." + @Schema(description = "The URL for the processor's custom configuration UI if applicable." ) public String getCustomUiUrl() { return customUiUrl; @@ -274,8 +260,7 @@ public void setCustomUiUrl(String customUiUrl) { /** * @return the names of all processor relationships that cause a flow file to be terminated if the relationship is not connected to anything */ - @ApiModelProperty( - value = "The names of all relationships that cause a flow file to be terminated if the relationship is not connected elsewhere. This property differs " + @Schema(description = "The names of all relationships that cause a flow file to be terminated if the relationship is not connected elsewhere. This property differs " + "from the 'isAutoTerminate' property of the RelationshipDTO in that the RelationshipDTO is meant to depict the current configuration, whereas this " + "property can be set in a DTO when updating a Processor in order to change which Relationships should be auto-terminated." ) @@ -290,8 +275,7 @@ public void setAutoTerminatedRelationships(final Set autoTerminatedRelat /** * @return maps default values for concurrent tasks for each applicable scheduling strategy. */ - @ApiModelProperty( - value = "Maps default values for concurrent tasks for each applicable scheduling strategy." + @Schema(description = "Maps default values for concurrent tasks for each applicable scheduling strategy." ) public Map getDefaultConcurrentTasks() { return defaultConcurrentTasks; @@ -304,8 +288,7 @@ public void setDefaultConcurrentTasks(Map defaultConcurrentTasks /** * @return run duration in milliseconds */ - @ApiModelProperty( - value = "The run duration for the processor in milliseconds." + @Schema(description = "The run duration for the processor in milliseconds." ) public Long getRunDurationMillis() { return runDurationMillis; @@ -318,8 +301,7 @@ public void setRunDurationMillis(Long runDurationMillis) { /** * @return Maps default values for scheduling period for each applicable scheduling strategy */ - @ApiModelProperty( - value = "Maps default values for scheduling period for each applicable scheduling strategy." + @Schema(description = "Maps default values for scheduling period for each applicable scheduling strategy." ) public Map getDefaultSchedulingPeriod() { return defaultSchedulingPeriod; @@ -329,8 +311,7 @@ public void setDefaultSchedulingPeriod(Map defaultSchedulingPeri this.defaultSchedulingPeriod = defaultSchedulingPeriod; } - @ApiModelProperty( - value = "Overall number of retries." + @Schema(description = "Overall number of retries." ) public Integer getRetryCount() { return retryCount; @@ -340,8 +321,7 @@ public void setRetryCount(Integer retryCount) { this.retryCount = retryCount; } - @ApiModelProperty( - value = "All the relationships should be retried." + @Schema(description = "All the relationships should be retried." ) public Set getRetriedRelationships() { return retriedRelationships; @@ -351,8 +331,7 @@ public void setRetriedRelationships(Set retriedRelationships) { this.retriedRelationships = retriedRelationships; } - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY, - value = "Determines whether the FlowFile should be penalized or the processor should be yielded between retries.", + @Schema(description = "Determines whether the FlowFile should be penalized or the processor should be yielded between retries.", allowableValues = "PENALIZE_FLOWFILE, YIELD_PROCESSOR" ) public String getBackoffMechanism() { @@ -363,8 +342,7 @@ public void setBackoffMechanism(String backoffMechanism) { this.backoffMechanism = backoffMechanism; } - @ApiModelProperty( - value = "Maximum amount of time to be waited during a retry period." + @Schema(description = "Maximum amount of time to be waited during a retry period." ) public String getMaxBackoffPeriod() { return maxBackoffPeriod; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java index b15b7d80f75c2..1e9ce740b0be3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -64,8 +64,7 @@ public ProcessorDTO() { * * @return This processors name */ - @ApiModelProperty( - value = "The name of the processor." + @Schema(description = "The name of the processor." ) public String getName() { return name; @@ -80,8 +79,7 @@ public void setName(String name) { * * @return This processors type */ - @ApiModelProperty( - value = "The type of the processor." + @Schema(description = "The type of the processor." ) public String getType() { return type; @@ -96,8 +94,7 @@ public void setType(String type) { * * @return The bundle details */ - @ApiModelProperty( - value = "The details of the artifact that bundled this processor type." + @Schema(description = "The details of the artifact that bundled this processor type." ) public BundleDTO getBundle() { return bundle; @@ -110,8 +107,7 @@ public void setBundle(BundleDTO bundle) { /** * @return The state of this processor. Possible states are 'RUNNING', 'STOPPED', and 'DISABLED' */ - @ApiModelProperty( - value = "The state of the processor", + @Schema(description = "The state of the processor", allowableValues = "RUNNING, STOPPED, DISABLED" ) public String getState() { @@ -125,8 +121,7 @@ public void setState(String state) { /** * @return The styles for this processor. (Currently only supports color) */ - @ApiModelProperty( - value = "Styles for the processor (background-color : #eee)." + @Schema(description = "Styles for the processor (background-color : #eee)." ) public Map getStyle() { return style; @@ -139,8 +134,7 @@ public void setStyle(Map style) { /** * @return whether this processor supports parallel processing */ - @ApiModelProperty( - value = "Whether the processor supports parallel processing." + @Schema(description = "Whether the processor supports parallel processing." ) public Boolean getSupportsParallelProcessing() { return supportsParallelProcessing; @@ -153,8 +147,7 @@ public void setSupportsParallelProcessing(Boolean supportsParallelProcessing) { /** * @return whether this processor supports sensitive dynamic properties */ - @ApiModelProperty( - value = "Whether the processor supports sensitive dynamic properties." + @Schema(description = "Whether the processor supports sensitive dynamic properties." ) public Boolean getSupportsSensitiveDynamicProperties() { return supportsSensitiveDynamicProperties; @@ -167,8 +160,7 @@ public void setSupportsSensitiveDynamicProperties(final Boolean supportsSensitiv /** * @return whether this processor persists state */ - @ApiModelProperty( - value = "Whether the processor persists state." + @Schema(description = "Whether the processor persists state." ) public Boolean getPersistsState() { return persistsState; @@ -181,8 +173,7 @@ public void setPersistsState(Boolean persistsState) { /** * @return whether this processor has multiple versions available */ - @ApiModelProperty( - value = "Whether the processor has multiple versions available." + @Schema(description = "Whether the processor has multiple versions available." ) public Boolean getMultipleVersionsAvailable() { return multipleVersionsAvailable; @@ -195,8 +186,7 @@ public void setMultipleVersionsAvailable(Boolean multipleVersionsAvailable) { /** * @return whether the underlying extension is missing */ - @ApiModelProperty( - value = "Whether the underlying extension is missing." + @Schema(description = "Whether the underlying extension is missing." ) public Boolean getExtensionMissing() { return isExtensionMissing; @@ -209,8 +199,7 @@ public void setExtensionMissing(Boolean extensionMissing) { /** * @return whether this processor requires elevated privileges */ - @ApiModelProperty( - value = "Whether the processor requires elevated privileges." + @Schema(description = "Whether the processor requires elevated privileges." ) public Boolean getRestricted() { return restricted; @@ -223,8 +212,7 @@ public void setRestricted(Boolean restricted) { /** * @return Whether the processor has been deprecated. */ - @ApiModelProperty( - value = "Whether the processor has been deprecated." + @Schema(description = "Whether the processor has been deprecated." ) public Boolean getDeprecated() { return deprecated; @@ -237,8 +225,7 @@ public void setDeprecated(Boolean deprecated) { /** * @return the input requirement of this processor */ - @ApiModelProperty( - value = "The input requirement for this processor." + @Schema(description = "The input requirement for this processor." ) public String getInputRequirement() { return inputRequirement; @@ -251,8 +238,7 @@ public void setInputRequirement(String inputRequirement) { /** * @return whether this processor supports batching */ - @ApiModelProperty( - value = "Whether the processor supports batching. This makes the run duration settings available." + @Schema(description = "Whether the processor supports batching. This makes the run duration settings available." ) public Boolean getSupportsBatching() { return supportsBatching; @@ -267,9 +253,8 @@ public void setSupportsBatching(Boolean supportsBatching) { * * @return The available relationships */ - @ApiModelProperty( - value = "The available relationships that the processor currently supports.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The available relationships that the processor currently supports.", + accessMode = Schema.AccessMode.READ_ONLY ) public List getRelationships() { return relationships; @@ -284,8 +269,7 @@ public void setRelationships(List relationships) { * * @return The processor configuration details */ - @ApiModelProperty( - value = "The configuration details for the processor. These details will be included in a response if the verbose flag is included in a request." + @Schema(description = "The configuration details for the processor. These details will be included in a response if the verbose flag is included in a request." ) public ProcessorConfigDTO getConfig() { return config; @@ -300,8 +284,7 @@ public void setConfig(ProcessorConfigDTO config) { * * @return The validation errors */ - @ApiModelProperty( - value = "The validation errors for the processor. These validation errors represent the problems with the processor that must be resolved before it can be started." + @Schema(description = "The validation errors for the processor. These validation errors represent the problems with the processor that must be resolved before it can be started." ) public Collection getValidationErrors() { return validationErrors; @@ -311,8 +294,8 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty(value = "Indicates whether the Processor is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Processor is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "Indicates whether the Processor is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Processor is valid)", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; @@ -325,8 +308,7 @@ public void setValidationStatus(String validationStatus) { /** * @return the description for this processor */ - @ApiModelProperty( - value = "The description of the processor." + @Schema(description = "The description of the processor." ) public String getDescription() { return description; @@ -339,8 +321,7 @@ public void setDescription(final String description) { /** * @return whether or not this processor is restricted to run only in primary node */ - @ApiModelProperty( - value = "Indicates if the execution node of a processor is restricted to run only on the primary node" + @Schema(description = "Indicates if the execution node of a processor is restricted to run only on the primary node" ) public Boolean isExecutionNodeRestricted() { return executionNodeRestricted; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorRunStatusDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorRunStatusDetailsDTO.java index 6b2c9ddd35d4a..da2161856a8ed 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorRunStatusDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorRunStatusDetailsDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Set; @@ -37,7 +37,7 @@ public class ProcessorRunStatusDetailsDTO { private int activeThreads; private Set validationErrors; - @ApiModelProperty("The ID of the processor") + @Schema(description = "The ID of the processor") public String getId() { return id; } @@ -46,7 +46,7 @@ public void setId(final String id) { this.id = id; } - @ApiModelProperty("The name of the processor") + @Schema(description = "The name of the processor") public String getName() { return name; } @@ -55,8 +55,7 @@ public void setName(final String name) { this.name = name; } - @ApiModelProperty( - value = "The run status of the processor", + @Schema(description = "The run status of the processor", allowableValues = RUNNING + ", " + STOPPED + ", " + INVALID + ", " + VALIDATING + ", " + DISABLED ) public String getRunStatus() { @@ -67,7 +66,7 @@ public void setRunStatus(final String runStatus) { this.runStatus = runStatus; } - @ApiModelProperty("The current number of threads that the processor is currently using") + @Schema(description = "The current number of threads that the processor is currently using") public int getActiveThreadCount() { return activeThreads; } @@ -77,7 +76,7 @@ public void setActiveThreadCount(final int activeThreads) { } - @ApiModelProperty("The processor's validation errors") + @Schema(description = "The processor's validation errors") public Set getValidationErrors() { return validationErrors; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDependencyDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDependencyDTO.java index 8abd687e59ade..e930ab1269ce7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDependencyDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDependencyDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Set; @@ -27,7 +27,7 @@ public class PropertyDependencyDTO { private String propertyName; private Set dependentValues; - @ApiModelProperty("The name of the property that is being depended upon") + @Schema(description = "The name of the property that is being depended upon") public String getPropertyName() { return propertyName; } @@ -36,7 +36,7 @@ public void setPropertyName(final String propertyName) { this.propertyName = propertyName; } - @ApiModelProperty("The values for the property that satisfies the dependency, or null if the dependency is satisfied by the presence of any value for the associated property name") + @Schema(description = "The values for the property that satisfies the dependency, or null if the dependency is satisfied by the presence of any value for the associated property name") public Set getDependentValues() { return dependentValues; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java index 59bdb06077e19..65594f31e3593 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyDescriptorDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AllowableValueEntity; import jakarta.xml.bind.annotation.XmlType; @@ -45,8 +45,7 @@ public class PropertyDescriptorDTO { /** * @return set of allowable values for this property. If empty then the allowable values are not constrained */ - @ApiModelProperty( - value = "Allowable values for the property. If empty then the allowed values are not constrained." + @Schema(description = "Allowable values for the property. If empty then the allowed values are not constrained." ) public List getAllowableValues() { return allowableValues; @@ -59,8 +58,7 @@ public void setAllowableValues(List allowableValues) { /** * @return default value for this property */ - @ApiModelProperty( - value = "The default value for the property." + @Schema(description = "The default value for the property." ) public String getDefaultValue() { return defaultValue; @@ -73,8 +71,7 @@ public void setDefaultValue(String defaultValue) { /** * @return An explanation of the meaning of the given property. This description is meant to be displayed to a user or simply provide a mechanism of documenting intent */ - @ApiModelProperty( - value = "The description for the property. Used to relay additional details to a user or provide a mechanism of documenting intent." + @Schema(description = "The description for the property. Used to relay additional details to a user or provide a mechanism of documenting intent." ) public String getDescription() { return description; @@ -87,8 +84,7 @@ public void setDescription(String description) { /** * @return property name */ - @ApiModelProperty( - value = "The name for the property." + @Schema(description = "The name for the property." ) public String getName() { return name; @@ -101,8 +97,7 @@ public void setName(String name) { /** * @return human-readable name to display to users */ - @ApiModelProperty( - value = "The human readable name for the property." + @Schema(description = "The human readable name for the property." ) public String getDisplayName() { return displayName; @@ -115,8 +110,7 @@ public void setDisplayName(String displayName) { /** * @return whether the property is required for this processor */ - @ApiModelProperty( - value = "Whether the property is required." + @Schema(description = "Whether the property is required." ) public Boolean isRequired() { return required; @@ -129,8 +123,7 @@ public void setRequired(Boolean required) { /** * @return indicates that the value for this property should be considered sensitive and protected whenever stored or represented */ - @ApiModelProperty( - value = "Whether the property is sensitive and protected whenever stored or represented." + @Schema(description = "Whether the property is sensitive and protected whenever stored or represented." ) public Boolean isSensitive() { return sensitive; @@ -143,8 +136,7 @@ public void setSensitive(Boolean sensitive) { /** * @return indicates whether this property is dynamic */ - @ApiModelProperty( - value = "Whether the property is dynamic (user-defined)." + @Schema(description = "Whether the property is dynamic (user-defined)." ) public Boolean isDynamic() { return dynamic; @@ -157,8 +149,7 @@ public void setDynamic(Boolean dynamic) { /** * @return specifies whether or not this property support expression language */ - @ApiModelProperty( - value = "Whether the property supports expression language." + @Schema(description = "Whether the property supports expression language." ) public Boolean getSupportsEl() { return supportsEl; @@ -171,8 +162,7 @@ public void setSupportsEl(Boolean supportsEl) { /** * @return specifies the scope of expression language evaluation */ - @ApiModelProperty( - value = "Scope of the Expression Language evaluation for the property." + @Schema(description = "Scope of the Expression Language evaluation for the property." ) public String getExpressionLanguageScope() { return expressionLanguageScope; @@ -185,8 +175,7 @@ public void setExpressionLanguageScope(String scope) { /** * @return if this property identifies a controller service this returns the fully qualified type, null otherwise */ - @ApiModelProperty( - value = "If the property identifies a controller service this returns the fully qualified type." + @Schema(description = "If the property identifies a controller service this returns the fully qualified type." ) public String getIdentifiesControllerService() { return identifiesControllerService; @@ -199,8 +188,7 @@ public void setIdentifiesControllerService(String identifiesControllerService) { /** * @return if this property identifies a controller service this returns the bundle of the type, null otherwise */ - @ApiModelProperty( - value = "If the property identifies a controller service this returns the bundle of the type, null otherwise." + @Schema(description = "If the property identifies a controller service this returns the bundle of the type, null otherwise." ) public BundleDTO getIdentifiesControllerServiceBundle() { return identifiesControllerServiceBundle; @@ -210,7 +198,7 @@ public void setIdentifiesControllerServiceBundle(BundleDTO identifiesControllerS this.identifiesControllerServiceBundle = identifiesControllerServiceBundle; } - @ApiModelProperty(value="A list of dependencies that must be met in order for this Property to be relevant. If any of these dependencies is not met, the property described by this " + + @Schema(description = "A list of dependencies that must be met in order for this Property to be relevant. If any of these dependencies is not met, the property described by this " + "Property Descriptor is not relevant.") public List getDependencies() { return dependencies; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyHistoryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyHistoryDTO.java index 489b830b774f2..9575f87f036d4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyHistoryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PropertyHistoryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -32,8 +32,7 @@ public class PropertyHistoryDTO { /** * @return previous values */ - @ApiModelProperty( - value = "Previous values for a given property." + @Schema(description = "Previous values for a given property." ) public List getPreviousValues() { return previousValues; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/QueueSizeDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/QueueSizeDTO.java index 6b08819bc4ece..0d524755b5b4f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/QueueSizeDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/QueueSizeDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,8 +32,7 @@ public class QueueSizeDTO { /** * @return the count of objects in a queue */ - @ApiModelProperty( - value = "The count of objects in a queue." + @Schema(description = "The count of objects in a queue." ) public int getObjectCount() { return objectCount; @@ -46,8 +45,7 @@ public void setObjectCount(int objectCount) { /** * @return the size of objects in a queue */ - @ApiModelProperty( - value = "The size of objects in a queue." + @Schema(description = "The size of objects in a queue." ) public long getByteCount() { return byteCount; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReadablePermission.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReadablePermission.java index f06e927376dc9..d9e516cce8cc4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReadablePermission.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReadablePermission.java @@ -16,12 +16,11 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public interface ReadablePermission { - @ApiModelProperty( - value = "Indicates whether the user can read a given resource.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Indicates whether the user can read a given resource.", + accessMode = Schema.AccessMode.READ_ONLY ) Boolean getCanRead(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RelationshipDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RelationshipDTO.java index 25f8f19baeb99..e75ba96bbbbd3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RelationshipDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RelationshipDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,8 +34,7 @@ public class RelationshipDTO { /** * @return the relationship name */ - @ApiModelProperty( - value = "The relationship name." + @Schema(description = "The relationship name." ) public String getName() { return name; @@ -48,8 +47,7 @@ public void setName(String name) { /** * @return the relationship description */ - @ApiModelProperty( - value = "The relationship description." + @Schema(description = "The relationship description." ) public String getDescription() { return description; @@ -62,8 +60,7 @@ public void setDescription(String description) { /** * @return true if relationship is auto terminated;false otherwise */ - @ApiModelProperty( - value = "Whether or not flowfiles sent to this relationship should auto terminate." + @Schema(description = "Whether or not flowfiles sent to this relationship should auto terminate." ) public Boolean isAutoTerminate() { return autoTerminate; @@ -76,8 +73,7 @@ public void setAutoTerminate(Boolean autoTerminate) { /** * @return true if relationship is retry;false otherwise */ - @ApiModelProperty( - value = "Whether or not flowfiles sent to this relationship should retry." + @Schema(description = "Whether or not flowfiles sent to this relationship should retry." ) public Boolean isRetry() { return retry; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupContentsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupContentsDTO.java index 0ce7d1026e714..e5d2962b7f049 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupContentsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupContentsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Set; @@ -33,8 +33,7 @@ public class RemoteProcessGroupContentsDTO { /** * @return Controller Input Ports to which data can be sent */ - @ApiModelProperty( - value = "The input ports to which data can be sent." + @Schema(description = "The input ports to which data can be sent." ) public Set getInputPorts() { return inputPorts; @@ -47,8 +46,7 @@ public void setInputPorts(Set inputPorts) { /** * @return Controller Output Ports from which data can be retrieved */ - @ApiModelProperty( - value = "The output ports from which data can be retrieved." + @Schema(description = "The output ports from which data can be retrieved." ) public Set getOutputPorts() { return outputPorts; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java index 63f6920033643..068422e12775e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -81,8 +81,7 @@ public void setTargetUri(final String targetUri) { * If target uri is not set, but uris are set, then returns the first url in the urls. * If neither target uri nor uris are set, then returns null. */ - @ApiModelProperty( - value = "The target URI of the remote process group." + + @Schema(description = "The target URI of the remote process group." + " If target uri is not set, but uris are set, then returns the first url in the urls." + " If neither target uri nor uris are set, then returns null." ) @@ -113,8 +112,7 @@ public void setTargetUris(String targetUris) { * If targetUris was not set but target uri was set, then returns a collection containing the single uri. * If neither target uris nor uri were set, then returns null. */ - @ApiModelProperty( - value = "The target URI of the remote process group." + + @Schema(description = "The target URI of the remote process group." + " If target uris is not set but target uri is set," + " then returns a collection containing the single target uri." + " If neither target uris nor uris are set, then returns null." @@ -134,8 +132,7 @@ public String getTargetUris() { /** * @param name of this remote process group */ - @ApiModelProperty( - value = "The name of the remote process group." + @Schema(description = "The name of the remote process group." ) public void setName(final String name) { this.name = name; @@ -148,8 +145,7 @@ public String getName() { /** * @return Comments for this remote process group */ - @ApiModelProperty( - value = "The comments for the remote process group." + @Schema(description = "The comments for the remote process group." ) public String getComments() { return comments; @@ -162,8 +158,7 @@ public void setComments(String comments) { /** * @return any remote authorization issues for this remote process group */ - @ApiModelProperty( - value = "Any remote authorization issues for the remote process group." + @Schema(description = "Any remote authorization issues for the remote process group." ) public Collection getAuthorizationIssues() { return authorizationIssues; @@ -176,8 +171,7 @@ public void setAuthorizationIssues(Collection authorizationIssues) { /** * @return whether or not this remote process group is actively transmitting */ - @ApiModelProperty( - value = "Whether the remote process group is actively transmitting." + @Schema(description = "Whether the remote process group is actively transmitting." ) public Boolean isTransmitting() { return transmitting; @@ -190,8 +184,7 @@ public void setTransmitting(Boolean transmitting) { /** * @return whether or not the target is running securely */ - @ApiModelProperty( - value = "Whether the target is running securely." + @Schema(description = "Whether the target is running securely." ) public Boolean isTargetSecure() { return targetSecure; @@ -204,8 +197,7 @@ public void setTargetSecure(Boolean targetSecure) { /** * @return the time period used for the timeout when communicating with this RemoteProcessGroup */ - @ApiModelProperty( - value = "The time period used for the timeout when communicating with the target." + @Schema(description = "The time period used for the timeout when communicating with the target." ) public String getCommunicationsTimeout() { return communicationsTimeout; @@ -218,8 +210,7 @@ public void setCommunicationsTimeout(String communicationsTimeout) { /** * @return when yielding, this amount of time must elapse before this remote process group is scheduled again */ - @ApiModelProperty( - value = "When yielding, this amount of time must elapse before the remote process group is scheduled again." + @Schema(description = "When yielding, this amount of time must elapse before the remote process group is scheduled again." ) public String getYieldDuration() { return yieldDuration; @@ -232,8 +223,7 @@ public void setYieldDuration(String yieldDuration) { /** * @return number of active remote input ports */ - @ApiModelProperty( - value = "The number of active remote input ports." + @Schema(description = "The number of active remote input ports." ) public Integer getActiveRemoteInputPortCount() { return activeRemoteInputPortCount; @@ -246,8 +236,7 @@ public void setActiveRemoteInputPortCount(Integer activeRemoteInputPortCount) { /** * @return number of inactive remote input ports */ - @ApiModelProperty( - value = "The number of inactive remote input ports." + @Schema(description = "The number of inactive remote input ports." ) public Integer getInactiveRemoteInputPortCount() { return inactiveRemoteInputPortCount; @@ -260,8 +249,7 @@ public void setInactiveRemoteInputPortCount(Integer inactiveRemoteInputPortCount /** * @return number of active remote output ports */ - @ApiModelProperty( - value = "The number of active remote output ports." + @Schema(description = "The number of active remote output ports." ) public Integer getActiveRemoteOutputPortCount() { return activeRemoteOutputPortCount; @@ -274,8 +262,7 @@ public void setActiveRemoteOutputPortCount(Integer activeRemoteOutputPortCount) /** * @return number of inactive remote output ports */ - @ApiModelProperty( - value = "The number of inactive remote output ports." + @Schema(description = "The number of inactive remote output ports." ) public Integer getInactiveRemoteOutputPortCount() { return inactiveRemoteOutputPortCount; @@ -288,8 +275,7 @@ public void setInactiveRemoteOutputPortCount(Integer inactiveRemoteOutputPortCou /** * @return number of Remote Input Ports currently available in the remote NiFi instance */ - @ApiModelProperty( - value = "The number of remote input ports currently available on the target." + @Schema(description = "The number of remote input ports currently available on the target." ) public Integer getInputPortCount() { return inputPortCount; @@ -302,8 +288,7 @@ public void setInputPortCount(Integer inputPortCount) { /** * @return number of Remote Output Ports currently available in the remote NiFi instance */ - @ApiModelProperty( - value = "The number of remote output ports currently available on the target." + @Schema(description = "The number of remote output ports currently available on the target." ) public Integer getOutputPortCount() { return outputPortCount; @@ -316,8 +301,7 @@ public void setOutputPortCount(Integer outputPortCount) { /** * @return contents of this remote process group. Will contain available input/output ports */ - @ApiModelProperty( - value = "The contents of the remote process group. Will contain available input/output ports." + @Schema(description = "The contents of the remote process group. Will contain available input/output ports." ) public RemoteProcessGroupContentsDTO getContents() { return contents; @@ -331,9 +315,8 @@ public void setContents(RemoteProcessGroupContentsDTO contents) { * @return the flow for this remote group was last refreshed */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The timestamp when this remote process group was last refreshed.", - dataType = "string" + @Schema(description = "The timestamp when this remote process group was last refreshed.", + type = "string" ) public Date getFlowRefreshed() { return flowRefreshed; @@ -351,7 +334,7 @@ public void setTransportProtocol(String transportProtocol) { this.transportProtocol = transportProtocol; } - @ApiModelProperty("The local network interface to send/receive data. If not specified, any local address is used. If clustered, all nodes must have an interface with this identifier.") + @Schema(description = "The local network interface to send/receive data. If not specified, any local address is used. If clustered, all nodes must have an interface with this identifier.") public String getLocalNetworkInterface() { return localNetworkInterface; } @@ -360,8 +343,10 @@ public void setLocalNetworkInterface(String localNetworkInterface) { this.localNetworkInterface = localNetworkInterface; } - @ApiModelProperty( - "The validation errors for the remote process group. These validation errors represent the problems with the remote process group that must be resolved before it can transmit." + @Schema(description = """ + The validation errors for the remote process group. + These validation errors represent the problems with the remote process group that must be resolved before it can transmit. + """ ) public Collection getValidationErrors() { return validationErrors; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupPortDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupPortDTO.java index 333e8999ff780..524641fcbe93c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupPortDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupPortDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; /** @@ -42,8 +42,7 @@ public class RemoteProcessGroupPortDTO { /** * @return comments as configured in the target port */ - @ApiModelProperty( - value = "The comments as configured on the target port." + @Schema(description = "The comments as configured on the target port." ) public String getComments() { return comments; @@ -53,7 +52,7 @@ public void setComments(String comments) { this.comments = comments; } - @ApiModelProperty("The ID of the corresponding component that is under version control") + @Schema(description = "The ID of the corresponding component that is under version control") public String getVersionedComponentId() { return versionedComponentId; } @@ -65,8 +64,7 @@ public void setVersionedComponentId(final String id) { /** * @return number tasks that may transmit flow files to the target port concurrently */ - @ApiModelProperty( - value = "The number of task that may transmit flowfiles to the target port concurrently." + @Schema(description = "The number of task that may transmit flowfiles to the target port concurrently." ) public Integer getConcurrentlySchedulableTaskCount() { return concurrentlySchedulableTaskCount; @@ -79,8 +77,7 @@ public void setConcurrentlySchedulableTaskCount(Integer concurrentlySchedulableT /** * @return id of the target port */ - @ApiModelProperty( - value = "The id of the port." + @Schema(description = "The id of the port." ) public String getId() { return id; @@ -90,7 +87,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The id of the target port.") + @Schema(description = "The id of the target port.") public String getTargetId() { return targetId; } @@ -102,8 +99,7 @@ public void setTargetId(String targetId) { /** * @return id of the remote process group that this port resides in */ - @ApiModelProperty( - value = "The id of the remote process group that the port resides in." + @Schema(description = "The id of the remote process group that the port resides in." ) public String getGroupId() { return groupId; @@ -116,8 +112,7 @@ public void setGroupId(String groupId) { /** * @return name of the target port */ - @ApiModelProperty( - value = "The name of the target port." + @Schema(description = "The name of the target port." ) public String getName() { return name; @@ -130,8 +125,7 @@ public void setName(String name) { /** * @return whether or not this remote group port is configured for transmission */ - @ApiModelProperty( - value = "Whether the remote port is configured for transmission." + @Schema(description = "Whether the remote port is configured for transmission." ) public Boolean isTransmitting() { return transmitting; @@ -144,8 +138,7 @@ public void setTransmitting(Boolean transmitting) { /** * @return whether or not flow file are compressed when sent to this target port */ - @ApiModelProperty( - value = "Whether the flowfiles are compressed when sent to the target port." + @Schema(description = "Whether the flowfiles are compressed when sent to the target port." ) public Boolean getUseCompression() { return useCompression; @@ -158,8 +151,7 @@ public void setUseCompression(Boolean useCompression) { /** * @return whether or not the target port exists */ - @ApiModelProperty( - value = "Whether the target port exists." + @Schema(description = "Whether the target port exists." ) public Boolean getExists() { return exists; @@ -172,8 +164,7 @@ public void setExists(Boolean exists) { /** * @return whether or not the target port is running */ - @ApiModelProperty( - value = "Whether the target port is running." + @Schema(description = "Whether the target port is running." ) public Boolean isTargetRunning() { return targetRunning; @@ -186,8 +177,7 @@ public void setTargetRunning(Boolean targetRunning) { /** * @return whether or not this port has either an incoming or outgoing connection */ - @ApiModelProperty( - value = "Whether the port has either an incoming or outgoing connection." + @Schema(description = "Whether the port has either an incoming or outgoing connection." ) public Boolean isConnected() { return connected; @@ -200,8 +190,7 @@ public void setConnected(Boolean connected) { /** * @return batch settings for data transmission */ - @ApiModelProperty( - value = "The batch settings for data transmission." + @Schema(description = "The batch settings for data transmission." ) public BatchSettingsDTO getBatchSettings() { return batchSettings; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java index 22d15f78fd6b7..bec8284aaf25d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -62,8 +62,7 @@ public class ReportingTaskDTO extends ComponentDTO { /** * @return user-defined name of the reporting task */ - @ApiModelProperty( - value = "The name of the reporting task." + @Schema(description = "The name of the reporting task." ) public String getName() { return name; @@ -76,8 +75,7 @@ public void setName(String name) { /** * @return user-defined comments for the reporting task */ - @ApiModelProperty( - value = "The comments of the reporting task." + @Schema(description = "The comments of the reporting task." ) public String getComments() { return comments; @@ -90,8 +88,7 @@ public void setComments(String comments) { /** * @return type of reporting task */ - @ApiModelProperty( - value = "The fully qualified type of the reporting task." + @Schema(description = "The fully qualified type of the reporting task." ) public String getType() { return type; @@ -106,8 +103,7 @@ public void setType(String type) { * * @return The bundle details */ - @ApiModelProperty( - value = "The details of the artifact that bundled this reporting task type." + @Schema(description = "The details of the artifact that bundled this reporting task type." ) public BundleDTO getBundle() { return bundle; @@ -122,8 +118,7 @@ public void setBundle(BundleDTO bundle) { * * @return The scheduling period */ - @ApiModelProperty( - value = "The frequency with which to schedule the reporting task. The format of the value will depend on the value of the schedulingStrategy." + @Schema(description = "The frequency with which to schedule the reporting task. The format of the value will depend on the value of the schedulingStrategy." ) public String getSchedulingPeriod() { return schedulingPeriod; @@ -136,8 +131,7 @@ public void setSchedulingPeriod(String schedulingPeriod) { /** * @return whether this reporting task persists state */ - @ApiModelProperty( - value = "Whether the reporting task persists state." + @Schema(description = "Whether the reporting task persists state." ) public Boolean getPersistsState() { return persistsState; @@ -150,8 +144,7 @@ public void setPersistsState(Boolean persistsState) { /** * @return whether this reporting task requires elevated privileges */ - @ApiModelProperty( - value = "Whether the reporting task requires elevated privileges." + @Schema(description = "Whether the reporting task requires elevated privileges." ) public Boolean getRestricted() { return restricted; @@ -164,8 +157,7 @@ public void setRestricted(Boolean restricted) { /** * @return Whether the reporting task has been deprecated. */ - @ApiModelProperty( - value = "Whether the reporting task has been deprecated." + @Schema(description = "Whether the reporting task has been deprecated." ) public Boolean getDeprecated() { return deprecated; @@ -178,8 +170,7 @@ public void setDeprecated(Boolean deprecated) { /** * @return whether the underlying extension is missing */ - @ApiModelProperty( - value = "Whether the underlying extension is missing." + @Schema(description = "Whether the underlying extension is missing." ) public Boolean getExtensionMissing() { return isExtensionMissing; @@ -192,8 +183,7 @@ public void setExtensionMissing(Boolean extensionMissing) { /** * @return whether this reporting task has multiple versions available */ - @ApiModelProperty( - value = "Whether the reporting task has multiple versions available." + @Schema(description = "Whether the reporting task has multiple versions available." ) public Boolean getMultipleVersionsAvailable() { return multipleVersionsAvailable; @@ -206,8 +196,7 @@ public void setMultipleVersionsAvailable(Boolean multipleVersionsAvailable) { /** * @return whether this reporting task supports sensitive dynamic properties */ - @ApiModelProperty( - value = "Whether the reporting task supports sensitive dynamic properties." + @Schema(description = "Whether the reporting task supports sensitive dynamic properties." ) public Boolean getSupportsSensitiveDynamicProperties() { return supportsSensitiveDynamicProperties; @@ -220,8 +209,7 @@ public void setSupportsSensitiveDynamicProperties(final Boolean supportsSensitiv /** * @return current scheduling state of the reporting task */ - @ApiModelProperty( - value = "The state of the reporting task.", + @Schema(description = "The state of the reporting task.", allowableValues = "RUNNING, STOPPED, DISABLED" ) public String getState() { @@ -235,8 +223,7 @@ public void setState(String state) { /** * @return The scheduling strategy that determines how the {@link #getSchedulingPeriod()} value should be interpreted */ - @ApiModelProperty( - value = "The scheduling strategy that determines how the schedulingPeriod value should be interpreted." + @Schema(description = "The scheduling strategy that determines how the schedulingPeriod value should be interpreted." ) public String getSchedulingStrategy() { return schedulingStrategy; @@ -249,8 +236,7 @@ public void setSchedulingStrategy(String schedulingStrategy) { /** * @return reporting task's properties */ - @ApiModelProperty( - value = "The properties of the reporting task." + @Schema(description = "The properties of the reporting task." ) public Map getProperties() { return properties; @@ -263,8 +249,7 @@ public void setProperties(Map properties) { /** * @return Map of property name to descriptor */ - @ApiModelProperty( - value = "The descriptors for the reporting tasks properties." + @Schema(description = "The descriptors for the reporting tasks properties." ) public Map getDescriptors() { return descriptors; @@ -277,8 +262,7 @@ public void setDescriptors(Map descriptors) { /** * @return Set of sensitive dynamic property names */ - @ApiModelProperty( - value = "Set of sensitive dynamic property names" + @Schema(description = "Set of sensitive dynamic property names" ) public Set getSensitiveDynamicPropertyNames() { return sensitiveDynamicPropertyNames; @@ -291,8 +275,7 @@ public void setSensitiveDynamicPropertyNames(final Set sensitiveDynamicP /** * @return the URL for this reporting task custom configuration UI if applicable. Null otherwise */ - @ApiModelProperty( - value = "The URL for the custom configuration UI for the reporting task." + @Schema(description = "The URL for the custom configuration UI for the reporting task." ) public String getCustomUiUrl() { return customUiUrl; @@ -305,8 +288,7 @@ public void setCustomUiUrl(String customUiUrl) { /** * @return currently configured annotation data for the reporting task */ - @ApiModelProperty( - value = "The annotation data for the repoting task. This is how the custom UI relays configuration to the reporting task." + @Schema(description = "The annotation data for the repoting task. This is how the custom UI relays configuration to the reporting task." ) public String getAnnotationData() { return annotationData; @@ -321,8 +303,7 @@ public void setAnnotationData(String annotationData) { * * @return The validation errors */ - @ApiModelProperty( - value = "Gets the validation errors from the reporting task. These validation errors represent the problems with the reporting task that must be resolved before " + @Schema(description = "Gets the validation errors from the reporting task. These validation errors represent the problems with the reporting task that must be resolved before " + "it can be scheduled to run." ) public Collection getValidationErrors() { @@ -333,8 +314,8 @@ public void setValidationErrors(Collection validationErrors) { this.validationErrors = validationErrors; } - @ApiModelProperty(value = "Indicates whether the Reporting Task is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Reporting Task is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "Indicates whether the Reporting Task is valid, invalid, or still in the process of validating (i.e., it is unknown whether or not the Reporting Task is valid)", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; @@ -347,8 +328,7 @@ public void setValidationStatus(String validationStatus) { /** * @return default scheduling period for the different scheduling strategies */ - @ApiModelProperty( - value = "The default scheduling period for the different scheduling strategies." + @Schema(description = "The default scheduling period for the different scheduling strategies." ) public Map getDefaultSchedulingPeriod() { return defaultSchedulingPeriod; @@ -361,8 +341,7 @@ public void setDefaultSchedulingPeriod(Map defaultSchedulingPeri /** * @return number of active threads for this reporting task */ - @ApiModelProperty( - value = "The number of active threads for the reporting task." + @Schema(description = "The number of active threads for the reporting task." ) public Integer getActiveThreadCount() { return activeThreadCount; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RequiredPermissionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RequiredPermissionDTO.java index 083d12cf47af7..f9c735cb9aa3c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RequiredPermissionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RequiredPermissionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Objects; @@ -33,8 +33,7 @@ public class RequiredPermissionDTO { /** * @return The required sub-permission necessary for this restriction. */ - @ApiModelProperty( - value = "The required sub-permission necessary for this restriction." + @Schema(description = "The required sub-permission necessary for this restriction." ) public String getId() { return id; @@ -47,8 +46,7 @@ public void setId(String id) { /** * @return The label for the required sub-permission necessary for this restriction. */ - @ApiModelProperty( - value = "The label for the required sub-permission necessary for this restriction." + @Schema(description = "The label for the required sub-permission necessary for this restriction." ) public String getLabel() { return label; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ResourceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ResourceDTO.java index 69cb9fa2774d8..2a5b2105b0e29 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ResourceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ResourceDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -35,8 +35,7 @@ public class ResourceDTO { * * @return The name of the resource */ - @ApiModelProperty( - value = "The name of the resource." + @Schema(description = "The name of the resource." ) public String getName() { return name; @@ -51,8 +50,7 @@ public void setName(String name) { * * @return The identifier of the resource */ - @ApiModelProperty( - value = "The identifier of the resource." + @Schema(description = "The identifier of the resource." ) public String getIdentifier() { return identifier; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java index f85cbe4205dfa..74bdc89071823 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RevisionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -37,9 +37,11 @@ public class RevisionDTO { * * @return The client id */ - @ApiModelProperty( - value = "A client identifier used to make a request. By including a client identifier, the API can allow multiple requests without needing the current revision. Due to the asynchronous " - + "nature of requests/responses this was implemented to allow the client to make numerous requests without having to wait for the previous response to come back" + @Schema(description = """ + A client identifier used to make a request. + By including a client identifier, the API can allow multiple requests without needing the current revision. + Due to the asynchronous nature of requests/responses this was implemented to allow the client to make numerous requests without having to wait for the previous response to come back + """ ) public String getClientId() { return clientId; @@ -54,9 +56,10 @@ public void setClientId(String clientId) { * * @return The revision */ - @ApiModelProperty( - value = "NiFi employs an optimistic locking strategy where the client must include a revision in their request when performing an update. In a response to a mutable flow request, this " - + "field represents the updated base version." + @Schema(description = """ + NiFi employs an optimistic locking strategy where the client must include a revision in their request when performing an update. + In a response to a mutable flow request, this field represents the updated base version. + """ ) public Long getVersion() { return version; @@ -69,9 +72,8 @@ public void setVersion(Long version) { /** * @return The user that last modified the flow */ - @ApiModelProperty( - value = "The user that last modified the flow.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The user that last modified the flow.", + accessMode = Schema.AccessMode.READ_ONLY ) public String getLastModifier() { return lastModifier; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java index 6d6ab3c9797a6..cc4aa71f6e9a3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.HashMap; @@ -45,8 +45,7 @@ public class SnippetDTO { /** * @return id of this snippet */ - @ApiModelProperty( - value = "The id of the snippet." + @Schema(description = "The id of the snippet." ) public String getId() { return id; @@ -59,8 +58,7 @@ public void setId(String id) { /** * @return uri of this snippet */ - @ApiModelProperty( - value = "The URI of the snippet." + @Schema(description = "The URI of the snippet." ) public String getUri() { return uri; @@ -73,8 +71,7 @@ public void setUri(String uri) { /** * @return group id for the components in this snippet */ - @ApiModelProperty( - value = "The group id for the components in the snippet." + @Schema(description = "The group id for the components in the snippet." ) public String getParentGroupId() { return parentGroupId; @@ -88,8 +85,7 @@ public void setParentGroupId(String parentGroupId) { * @return the ids of the connections in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created its * contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the connections in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the connections in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getConnections() { @@ -104,8 +100,7 @@ public void setConnections(Map connections) { * @return the ids of the funnels in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created its * contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the funnels in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the funnels in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getFunnels() { @@ -120,8 +115,7 @@ public void setFunnels(Map funnels) { * @return the ids of the input port in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created its * contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the input ports in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the input ports in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getInputPorts() { @@ -136,8 +130,7 @@ public void setInputPorts(Map inputPorts) { * @return the ids of the labels in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created its * contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the labels in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the labels in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getLabels() { @@ -152,8 +145,7 @@ public void setLabels(Map labels) { * @return the ids of the output ports in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created * its contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the output ports in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the output ports in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getOutputPorts() { @@ -168,8 +160,7 @@ public void setOutputPorts(Map outputPorts) { * @return The ids of the process groups in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created * its contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the process groups in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the process groups in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getProcessGroups() { @@ -184,8 +175,7 @@ public void setProcessGroups(Map processGroups) { * @return The ids of the processors in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been created its * contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the processors in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + @Schema(description = "The ids of the processors in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " + "has been created its contents cannot be modified (these ids are ignored during update requests)." ) public Map getProcessors() { @@ -200,9 +190,12 @@ public void setProcessors(Map processors) { * @return the ids of the remote process groups in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet has been * created its contents cannot be modified (these ids are ignored during update requests) */ - @ApiModelProperty( - value = "The ids of the remote process groups in this snippet. These ids will be populated within each response. They can be specified when creating a snippet. However, once a snippet " - + "has been created its contents cannot be modified (these ids are ignored during update requests)." + @Schema(description = """ + The ids of the remote process groups in this snippet. + These ids will be populated within each response. + They can be specified when creating a snippet. + However, once a snippet has been created its contents cannot be modified (these ids are ignored during update requests). + """ ) public Map getRemoteProcessGroups() { return remoteProcessGroups; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateEntryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateEntryDTO.java index 59ea99848befc..f4f8e84271a18 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateEntryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateEntryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -35,8 +35,7 @@ public class StateEntryDTO { /** * @return the key for this state */ - @ApiModelProperty( - value = "The key for this state." + @Schema(description = "The key for this state." ) public String getKey() { return key; @@ -49,8 +48,7 @@ public void setKey(String key) { /** * @return the value for this state */ - @ApiModelProperty( - value = "The value for this state." + @Schema(description = "The value for this state." ) public String getValue() { return value; @@ -63,8 +61,7 @@ public void setValue(String value) { /** * @return identifier of the node where this state originated */ - @ApiModelProperty( - value = "The identifier for the node where the state originated." + @Schema(description = "The identifier for the node where the state originated." ) public String getClusterNodeId() { return clusterNodeId; @@ -77,8 +74,7 @@ public void setClusterNodeId(String clusterNodeId) { /** * @return label to use to show which node this state originated from */ - @ApiModelProperty( - value = "The label for the node where the state originated." + @Schema(description = "The label for the node where the state originated." ) public String getClusterNodeAddress() { return clusterNodeAddress; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateMapDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateMapDTO.java index d4bc5210560e8..00361ab7a5316 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateMapDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/StateMapDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -34,8 +34,7 @@ public class StateMapDTO { /** * @return The scope of this StateMap */ - @ApiModelProperty( - value = "The scope of this StateMap." + @Schema(description = "The scope of this StateMap." ) public String getScope() { return scope; @@ -48,8 +47,7 @@ public void setScope(String scope) { /** * @return The total number of state entries. When the state map is lengthy, only of portion of the entries are returned. */ - @ApiModelProperty( - value = "The total number of state entries. When the state map is lengthy, only of portion of the entries are returned." + @Schema(description = "The total number of state entries. When the state map is lengthy, only of portion of the entries are returned." ) public int getTotalEntryCount() { return totalEntryCount; @@ -62,8 +60,7 @@ public void setTotalEntryCount(int totalEntryCount) { /** * @return The state */ - @ApiModelProperty( - value = "The state." + @Schema(description = "The state." ) public List getState() { return state; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsDTO.java index 6e4d02aa9458b..40cc2980748f4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -28,7 +28,7 @@ public class SystemDiagnosticsDTO { private List nodeSnapshots; - @ApiModelProperty("A systems diagnostic snapshot that represents the aggregate values of all nodes in the cluster. If the NiFi instance is " + @Schema(description = "A systems diagnostic snapshot that represents the aggregate values of all nodes in the cluster. If the NiFi instance is " + "a standalone instance, rather than a cluster, this represents the stats of the single instance.") public SystemDiagnosticsSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; @@ -38,7 +38,7 @@ public void setAggregateSnapshot(SystemDiagnosticsSnapshotDTO aggregateSnapshot) this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A systems diagnostics snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + @Schema(description = "A systems diagnostics snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + "a cluster, this may be null.") public List getNodeSnapshots() { return nodeSnapshots; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsSnapshotDTO.java index cf54a28f8d7c5..028c2dbd0f50b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SystemDiagnosticsSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import org.apache.nifi.web.api.dto.util.TimeAdapter; @@ -72,7 +72,7 @@ public class SystemDiagnosticsSnapshotDTO implements Cloneable { private VersionInfoDTO versionInfo; - @ApiModelProperty("Number of available processors if supported by the underlying system.") + @Schema(description = "Number of available processors if supported by the underlying system.") public Integer getAvailableProcessors() { return availableProcessors; } @@ -81,7 +81,7 @@ public void setAvailableProcessors(Integer availableProcessors) { this.availableProcessors = availableProcessors; } - @ApiModelProperty("Number of daemon threads.") + @Schema(description = "Number of daemon threads.") public Integer getDaemonThreads() { return daemonThreads; } @@ -90,7 +90,7 @@ public void setDaemonThreads(Integer daemonThreads) { this.daemonThreads = daemonThreads; } - @ApiModelProperty("Amount of free heap.") + @Schema(description = "Amount of free heap.") public String getFreeHeap() { return freeHeap; } @@ -99,7 +99,7 @@ public void setFreeHeap(String freeHeap) { this.freeHeap = freeHeap; } - @ApiModelProperty("Amount of free non heap.") + @Schema(description = "Amount of free non heap.") public String getFreeNonHeap() { return freeNonHeap; } @@ -108,7 +108,7 @@ public void setFreeNonHeap(String freeNonHeap) { this.freeNonHeap = freeNonHeap; } - @ApiModelProperty("Maximum size of heap.") + @Schema(description = "Maximum size of heap.") public String getMaxHeap() { return maxHeap; } @@ -117,7 +117,7 @@ public void setMaxHeap(String maxHeap) { this.maxHeap = maxHeap; } - @ApiModelProperty("Maximum size of non heap.") + @Schema(description = "Maximum size of non heap.") public String getMaxNonHeap() { return maxNonHeap; } @@ -126,7 +126,7 @@ public void setMaxNonHeap(String maxNonHeap) { this.maxNonHeap = maxNonHeap; } - @ApiModelProperty("The processor load average if supported by the underlying system.") + @Schema(description = "The processor load average if supported by the underlying system.") public Double getProcessorLoadAverage() { return processorLoadAverage; } @@ -135,7 +135,7 @@ public void setProcessorLoadAverage(Double processorLoadAverage) { this.processorLoadAverage = processorLoadAverage; } - @ApiModelProperty("Total size of heap.") + @Schema(description = "Total size of heap.") public String getTotalHeap() { return totalHeap; } @@ -144,7 +144,7 @@ public void setTotalHeap(String totalHeap) { this.totalHeap = totalHeap; } - @ApiModelProperty("Total size of non heap.") + @Schema(description = "Total size of non heap.") public String getTotalNonHeap() { return totalNonHeap; } @@ -153,7 +153,7 @@ public void setTotalNonHeap(String totalNonHeap) { this.totalNonHeap = totalNonHeap; } - @ApiModelProperty("Total number of threads.") + @Schema(description = "Total number of threads.") public Integer getTotalThreads() { return totalThreads; } @@ -162,7 +162,7 @@ public void setTotalThreads(Integer totalThreads) { this.totalThreads = totalThreads; } - @ApiModelProperty("Amount of used heap.") + @Schema(description = "Amount of used heap.") public String getUsedHeap() { return usedHeap; } @@ -171,7 +171,7 @@ public void setUsedHeap(String usedHeap) { this.usedHeap = usedHeap; } - @ApiModelProperty("Amount of use non heap.") + @Schema(description = "Amount of use non heap.") public String getUsedNonHeap() { return usedNonHeap; } @@ -180,7 +180,7 @@ public void setUsedNonHeap(String usedNonHeap) { this.usedNonHeap = usedNonHeap; } - @ApiModelProperty("Utilization of heap.") + @Schema(description = "Utilization of heap.") public String getHeapUtilization() { return heapUtilization; } @@ -189,7 +189,7 @@ public void setHeapUtilization(String heapUtilization) { this.heapUtilization = heapUtilization; } - @ApiModelProperty("Utilization of non heap.") + @Schema(description = "Utilization of non heap.") public String getNonHeapUtilization() { return nonHeapUtilization; } @@ -198,7 +198,7 @@ public void setNonHeapUtilization(String nonHeapUsage) { this.nonHeapUtilization = nonHeapUsage; } - @ApiModelProperty("The content repository storage usage.") + @Schema(description = "The content repository storage usage.") public Set getContentRepositoryStorageUsage() { return contentRepositoryStorageUsage; } @@ -207,7 +207,7 @@ public void setContentRepositoryStorageUsage(Set contentReposit this.contentRepositoryStorageUsage = contentRepositoryStorageUsage; } - @ApiModelProperty("The provenance repository storage usage.") + @Schema(description = "The provenance repository storage usage.") public Set getProvenanceRepositoryStorageUsage() { return provenanceRepositoryStorageUsage; } @@ -216,7 +216,7 @@ public void setProvenanceRepositoryStorageUsage(Set provenanceR this.provenanceRepositoryStorageUsage = provenanceRepositoryStorageUsage; } - @ApiModelProperty("The flowfile repository storage usage.") + @Schema(description = "The flowfile repository storage usage.") public StorageUsageDTO getFlowFileRepositoryStorageUsage() { return flowFileRepositoryStorageUsage; } @@ -225,7 +225,7 @@ public void setFlowFileRepositoryStorageUsage(StorageUsageDTO flowFileRepository this.flowFileRepositoryStorageUsage = flowFileRepositoryStorageUsage; } - @ApiModelProperty("The garbage collection details.") + @Schema(description = "The garbage collection details.") public Set getGarbageCollection() { return garbageCollection; } @@ -243,9 +243,8 @@ public void setResourceClaimDetails(final List resource } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "When the diagnostics were generated.", - dataType = "string" + @Schema(description = "When the diagnostics were generated.", + type = "string" ) public Date getStatsLastRefreshed() { return statsLastRefreshed; @@ -256,7 +255,7 @@ public void setStatsLastRefreshed(Date statsLastRefreshed) { } - @ApiModelProperty("Total number of bytes allocated to the JVM not used for heap") + @Schema(description = "Total number of bytes allocated to the JVM not used for heap") public Long getTotalNonHeapBytes() { return totalNonHeapBytes; } @@ -265,7 +264,7 @@ public void setTotalNonHeapBytes(Long totalNonHeapBytes) { this.totalNonHeapBytes = totalNonHeapBytes; } - @ApiModelProperty("Total number of bytes used by the JVM not in the heap space") + @Schema(description = "Total number of bytes used by the JVM not in the heap space") public Long getUsedNonHeapBytes() { return usedNonHeapBytes; } @@ -274,7 +273,7 @@ public void setUsedNonHeapBytes(Long usedNonHeapBytes) { this.usedNonHeapBytes = usedNonHeapBytes; } - @ApiModelProperty("Total number of free non-heap bytes available to the JVM") + @Schema(description = "Total number of free non-heap bytes available to the JVM") public Long getFreeNonHeapBytes() { return freeNonHeapBytes; } @@ -283,7 +282,7 @@ public void setFreeNonHeapBytes(Long freeNonHeapBytes) { this.freeNonHeapBytes = freeNonHeapBytes; } - @ApiModelProperty("The maximum number of bytes that the JVM can use for non-heap purposes") + @Schema(description = "The maximum number of bytes that the JVM can use for non-heap purposes") public Long getMaxNonHeapBytes() { return maxNonHeapBytes; } @@ -292,7 +291,7 @@ public void setMaxNonHeapBytes(Long maxNonHeapBytes) { this.maxNonHeapBytes = maxNonHeapBytes; } - @ApiModelProperty("The total number of bytes that are available for the JVM heap to use") + @Schema(description = "The total number of bytes that are available for the JVM heap to use") public Long getTotalHeapBytes() { return totalHeapBytes; } @@ -301,7 +300,7 @@ public void setTotalHeapBytes(Long totalHeapBytes) { this.totalHeapBytes = totalHeapBytes; } - @ApiModelProperty("The number of bytes of JVM heap that are currently being used") + @Schema(description = "The number of bytes of JVM heap that are currently being used") public Long getUsedHeapBytes() { return usedHeapBytes; } @@ -310,7 +309,7 @@ public void setUsedHeapBytes(Long usedHeapBytes) { this.usedHeapBytes = usedHeapBytes; } - @ApiModelProperty("The number of bytes that are allocated to the JVM heap but not currently being used") + @Schema(description = "The number of bytes that are allocated to the JVM heap but not currently being used") public Long getFreeHeapBytes() { return freeHeapBytes; } @@ -319,7 +318,7 @@ public void setFreeHeapBytes(Long freeHeapBytes) { this.freeHeapBytes = freeHeapBytes; } - @ApiModelProperty("The maximum number of bytes that can be used by the JVM") + @Schema(description = "The maximum number of bytes that can be used by the JVM") public Long getMaxHeapBytes() { return maxHeapBytes; } @@ -328,7 +327,7 @@ public void setMaxHeapBytes(Long maxHeapBytes) { this.maxHeapBytes = maxHeapBytes; } - @ApiModelProperty("The nifi, os, java, and build version information") + @Schema(description = "The nifi, os, java, and build version information") public VersionInfoDTO getVersionInfo() { return versionInfo; } @@ -337,7 +336,7 @@ public void setVersionInfo(VersionInfoDTO versionInfo) { this.versionInfo = versionInfo; } - @ApiModelProperty("The uptime of the Java virtual machine") + @Schema(description = "The uptime of the Java virtual machine") public String getUptime() { return uptime; } @@ -420,18 +419,16 @@ public static class StorageUsageDTO implements Cloneable { private Long freeSpaceBytes; private Long totalSpaceBytes; private Long usedSpaceBytes; - private String utilization; - /** * @return identifier for this storage location */ - @ApiModelProperty( - value = "The identifier of this storage location. The identifier will correspond to the identifier keyed in the storage configuration." - ) + @Schema(description = "The identifier of this storage location. The identifier will correspond to the identifier keyed in the storage configuration.") public String getIdentifier() { return identifier; } + private String utilization; + public void setIdentifier(String identifier) { this.identifier = identifier; } @@ -439,9 +436,7 @@ public void setIdentifier(String identifier) { /** * @return amount of free space */ - @ApiModelProperty( - value = "Amount of free space." - ) + @Schema(description = "Amount of free space.") public String getFreeSpace() { return freeSpace; } @@ -453,9 +448,7 @@ public void setFreeSpace(String freeSpace) { /** * @return freeSpace amount of total space */ - @ApiModelProperty( - value = "Amount of total space." - ) + @Schema(description = "Amount of total space.") public String getTotalSpace() { return totalSpace; } @@ -467,9 +460,7 @@ public void setTotalSpace(String totalSpace) { /** * @return amount of used space */ - @ApiModelProperty( - value = "Amount of used space." - ) + @Schema(description = "Amount of used space.") public String getUsedSpace() { return usedSpace; } @@ -481,9 +472,7 @@ public void setUsedSpace(String usedSpace) { /** * @return utilization of this storage location */ - @ApiModelProperty( - value = "Utilization of this storage location." - ) + @Schema(description = "Utilization of this storage location.") public String getUtilization() { return utilization; } @@ -495,9 +484,7 @@ public void setUtilization(String utilization) { /** * @return number of bytes of free space */ - @ApiModelProperty( - value = "The number of bytes of free space." - ) + @Schema(description = "The number of bytes of free space.") public Long getFreeSpaceBytes() { return freeSpaceBytes; } @@ -509,9 +496,7 @@ public void setFreeSpaceBytes(Long freeSpaceBytes) { /** * @return number of bytes of total space */ - @ApiModelProperty( - value = "The number of bytes of total space." - ) + @Schema(description = "The number of bytes of total space.") public Long getTotalSpaceBytes() { return totalSpaceBytes; } @@ -523,9 +508,7 @@ public void setTotalSpaceBytes(Long totalSpaceBytes) { /** * @return number of bytes of used space */ - @ApiModelProperty( - value = "The number of bytes of used space." - ) + @Schema(description = "The number of bytes of used space.") public Long getUsedSpaceBytes() { return usedSpaceBytes; } @@ -560,7 +543,7 @@ public static class ResourceClaimDetailsDTO implements Cloneable { private Integer claimantCount; - @ApiModelProperty("The container of the Content Repository in which the Resource Claim exists") + @Schema(description = "The container of the Content Repository in which the Resource Claim exists") public String getContainer() { return container; } @@ -569,7 +552,7 @@ public void setContainer(final String container) { this.container = container; } - @ApiModelProperty("The section of the Content Repository in which the Resource Claim exists") + @Schema(description = "The section of the Content Repository in which the Resource Claim exists") public String getSection() { return section; } @@ -578,7 +561,7 @@ public void setSection(final String section) { this.section = section; } - @ApiModelProperty("The identifier of the Resource Claim") + @Schema(description = "The identifier of the Resource Claim") public String getIdentifier() { return identifier; } @@ -587,7 +570,7 @@ public void setIdentifier(final String identifier) { this.identifier = identifier; } - @ApiModelProperty("Whether or not the Resource Claim is in use") + @Schema(description = "Whether or not the Resource Claim is in use") public Boolean getInUse() { return inUse; } @@ -596,7 +579,7 @@ public void setInUse(final Boolean inUse) { this.inUse = inUse; } - @ApiModelProperty("Whether or not the Resource Claim is awaiting destruction") + @Schema(description = "Whether or not the Resource Claim is awaiting destruction") public Boolean getAwaitingDestruction() { return awaitingDestruction; } @@ -605,7 +588,7 @@ public void setAwaitingDestruction(final Boolean awaitingDestruction) { this.awaitingDestruction = awaitingDestruction; } - @ApiModelProperty("The number of FlowFiles that have a claim to the Resource") + @Schema(description = "The number of FlowFiles that have a claim to the Resource") public Integer getClaimantCount() { return claimantCount; } @@ -614,7 +597,7 @@ public void setClaimantCount(final Integer claimantCount) { this.claimantCount = claimantCount; } - @ApiModelProperty("Whether or not the Resource Claim can still have more data written to it") + @Schema(description = "Whether or not the Resource Claim can still have more data written to it") public Boolean getWritable() { return writable; } @@ -647,7 +630,7 @@ public static class GarbageCollectionDTO implements Cloneable { private String collectionTime; private Long collectionMillis; - @ApiModelProperty("The name of the garbage collector.") + @Schema(description = "The name of the garbage collector.") public String getName() { return name; } @@ -656,7 +639,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The number of times garbage collection has run.") + @Schema(description = "The number of times garbage collection has run.") public long getCollectionCount() { return collectionCount; } @@ -665,7 +648,7 @@ public void setCollectionCount(long collectionCount) { this.collectionCount = collectionCount; } - @ApiModelProperty("The total amount of time spent garbage collecting.") + @Schema(description = "The total amount of time spent garbage collecting.") public String getCollectionTime() { return collectionTime; } @@ -674,7 +657,7 @@ public void setCollectionTime(String collectionTime) { this.collectionTime = collectionTime; } - @ApiModelProperty("The total number of milliseconds spent garbage collecting.") + @Schema(description = "The total number of milliseconds spent garbage collecting.") public Long getCollectionMillis() { return collectionMillis; } @@ -711,7 +694,7 @@ public static class VersionInfoDTO implements Cloneable { private String buildBranch; private Date buildTimestamp; - @ApiModelProperty("The version of this NiFi.") + @Schema(description = "The version of this NiFi.") public String getNiFiVersion() { return niFiVersion; } @@ -720,7 +703,7 @@ public void setNiFiVersion(String niFiVersion) { this.niFiVersion = niFiVersion; } - @ApiModelProperty("Java JVM vendor") + @Schema(description = "Java JVM vendor") public String getJavaVendor() { return javaVendor; } @@ -729,7 +712,7 @@ public void setJavaVendor(String javaVendor) { this.javaVendor = javaVendor; } - @ApiModelProperty("Java version") + @Schema(description = "Java version") public String getJavaVersion() { return javaVersion; } @@ -738,7 +721,7 @@ public void setJavaVersion(String javaVersion) { this.javaVersion = javaVersion; } - @ApiModelProperty("Host operating system name") + @Schema(description = "Host operating system name") public String getOsName() { return osName; } @@ -747,7 +730,7 @@ public void setOsName(String osName) { this.osName = osName; } - @ApiModelProperty("Host operating system version") + @Schema(description = "Host operating system version") public String getOsVersion() { return osVersion; } @@ -756,7 +739,7 @@ public void setOsVersion(String osVersion) { this.osVersion = osVersion; } - @ApiModelProperty("Host operating system architecture") + @Schema(description = "Host operating system architecture") public String getOsArchitecture() { return osArchitecture; } @@ -765,7 +748,7 @@ public void setOsArchitecture(String osArchitecture) { this.osArchitecture = osArchitecture; } - @ApiModelProperty("Build tag") + @Schema(description = "Build tag") public String getBuildTag() { return buildTag; } @@ -774,7 +757,7 @@ public void setBuildTag(String buildTag) { this.buildTag = buildTag; } - @ApiModelProperty("Build revision or commit hash") + @Schema(description = "Build revision or commit hash") public String getBuildRevision() { return buildRevision; } @@ -783,7 +766,7 @@ public void setBuildRevision(String buildRevision) { this.buildRevision = buildRevision; } - @ApiModelProperty("Build branch") + @Schema(description = "Build branch") public String getBuildBranch() { return buildBranch; } @@ -793,7 +776,7 @@ public void setBuildBranch(String buildBranch) { } @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty("Build timestamp") + @Schema(description = "Build timestamp") public Date getBuildTimestamp() { return buildTimestamp; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/TenantDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/TenantDTO.java index ccf0ee198a8ea..a2156562b78a9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/TenantDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/TenantDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,7 +31,7 @@ public class TenantDTO extends ComponentDTO { /** * @return tenant's identity */ - @ApiModelProperty(value = "The identity of the tenant.") + @Schema(description = "The identity of the tenant.") public String getIdentity() { return identity; } @@ -43,7 +43,7 @@ public void setIdentity(String identity) { /** * @return whether this tenant is configurable */ - @ApiModelProperty(value = "Whether this tenant is configurable.") + @Schema(description = "Whether this tenant is configurable.") public Boolean getConfigurable() { return configurable; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UpdateStepDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UpdateStepDTO.java index ce3816b5e9473..a244ddb1f33d7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UpdateStepDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UpdateStepDTO.java @@ -16,14 +16,14 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public abstract class UpdateStepDTO { private String description; private boolean complete; private String failureReason; - @ApiModelProperty(value = "Explanation of what happens in this step", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Explanation of what happens in this step", accessMode = Schema.AccessMode.READ_ONLY) public String getDescription() { return description; } @@ -32,7 +32,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty(value = "Whether or not this step has completed", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Whether or not this step has completed", accessMode = Schema.AccessMode.READ_ONLY) public boolean isComplete() { return complete; } @@ -41,7 +41,7 @@ public void setComplete(boolean complete) { this.complete = complete; } - @ApiModelProperty(value = "An explanation of why this step failed, or null if this step did not fail", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "An explanation of why this step failed, or null if this step did not fail", accessMode = Schema.AccessMode.READ_ONLY) public String getFailureReason() { return failureReason; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserDTO.java index 5d0ec23d40f57..fe4e2eae7237e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity; import org.apache.nifi.web.api.entity.TenantEntity; @@ -35,9 +35,8 @@ public class UserDTO extends TenantDTO { /** * @return groups to which the user belongs */ - @ApiModelProperty( - value = "The groups to which the user belongs. This field is read only and it provided for convenience.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The groups to which the user belongs. This field is read only and it provided for convenience.", + accessMode = Schema.AccessMode.READ_ONLY ) public Set getUserGroups() { return userGroups; @@ -50,9 +49,8 @@ public void setUserGroups(Set userGroups) { /** * @return policies this user is part of */ - @ApiModelProperty( - value = "The access policies this user belongs to.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The access policies this user belongs to.", + accessMode = Schema.AccessMode.READ_ONLY ) public Set getAccessPolicies() { return accessPolicies; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserGroupDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserGroupDTO.java index b5a556b319551..2cffd46a2e951 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserGroupDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/UserGroupDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.AccessPolicyEntity; import org.apache.nifi.web.api.entity.TenantEntity; @@ -35,7 +35,7 @@ public class UserGroupDTO extends TenantDTO { /** * @return users in this group */ - @ApiModelProperty(value = "The users that belong to the user group.") + @Schema(description = "The users that belong to the user group.") public Set getUsers() { return users; } @@ -47,11 +47,10 @@ public void setUsers(Set users) { /** * @return policies this user group is part of */ - @ApiModelProperty( - value = "The access policies this user group belongs to. This field was incorrectly defined as an AccessPolicyEntity. For " + @Schema(description = "The access policies this user group belongs to. This field was incorrectly defined as an AccessPolicyEntity. For " + "compatibility reasons the field will remain of this type, however only the fields that are present in the " + "AccessPolicySummaryEntity will be populated here.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + accessMode = Schema.AccessMode.READ_ONLY ) public Set getAccessPolicies() { return accessPolicies; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VerifyConfigRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VerifyConfigRequestDTO.java index 059af1b5bfe16..966964943b72b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VerifyConfigRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VerifyConfigRequestDTO.java @@ -17,8 +17,8 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; -import io.swagger.annotations.ApiModelProperty.AccessMode; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Schema.AccessMode; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -31,7 +31,7 @@ public class VerifyConfigRequestDTO extends AsynchronousRequestDTO attributes; private List results; - @ApiModelProperty("The ID of the component whose configuration was verified") + @Schema(description = "The ID of the component whose configuration was verified") public String getComponentId() { return componentId; } @@ -40,7 +40,7 @@ public void setComponentId(final String componentId) { this.componentId = componentId; } - @ApiModelProperty("The configured component properties") + @Schema(description = "The configured component properties") public Map getProperties() { return properties; } @@ -49,7 +49,7 @@ public void setProperties(final Map properties) { this.properties = properties; } - @ApiModelProperty("FlowFile Attributes that should be used to evaluate Expression Language for resolving property values") + @Schema(description = "FlowFile Attributes that should be used to evaluate Expression Language for resolving property values") public Map getAttributes() { return attributes; } @@ -58,7 +58,7 @@ public void setAttributes(final Map attributes) { this.attributes = attributes; } - @ApiModelProperty(value="The Results of the verification", accessMode = AccessMode.READ_ONLY) + @Schema(description = "The Results of the verification", accessMode = AccessMode.READ_ONLY) public List getResults() { return results; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionControlInformationDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionControlInformationDTO.java index 1a80ebc0f50c1..6648983374a19 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionControlInformationDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionControlInformationDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -43,7 +43,7 @@ public class VersionControlInformationDTO { private String state; private String stateExplanation; - @ApiModelProperty("The ID of the Process Group that is under version control") + @Schema(description = "The ID of the Process Group that is under version control") public String getGroupId() { return groupId; } @@ -52,7 +52,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty("The ID of the registry that the flow is stored in") + @Schema(description = "The ID of the registry that the flow is stored in") public String getRegistryId() { return registryId; } @@ -61,7 +61,7 @@ public void setRegistryId(final String registryId) { this.registryId = registryId; } - @ApiModelProperty(value = "The name of the registry that the flow is stored in", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The name of the registry that the flow is stored in", accessMode = Schema.AccessMode.READ_ONLY) public String getRegistryName() { return registryName; } @@ -70,7 +70,7 @@ public void setRegistryName(final String registryName) { this.registryName = registryName; } - @ApiModelProperty("The ID of the bucket that the flow is stored in") + @Schema(description = "The ID of the bucket that the flow is stored in") public String getBucketId() { return bucketId; } @@ -79,7 +79,7 @@ public void setBucketId(final String bucketId) { this.bucketId = bucketId; } - @ApiModelProperty(value = "The name of the bucket that the flow is stored in", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The name of the bucket that the flow is stored in", accessMode = Schema.AccessMode.READ_ONLY) public String getBucketName() { return bucketName; } @@ -88,7 +88,7 @@ public void setBucketName(String bucketName) { this.bucketName = bucketName; } - @ApiModelProperty("The ID of the flow") + @Schema(description = "The ID of the flow") public String getFlowId() { return flowId; } @@ -97,7 +97,7 @@ public void setFlowId(final String flowId) { this.flowId = flowId; } - @ApiModelProperty("The name of the flow") + @Schema(description = "The name of the flow") public String getFlowName() { return flowName; } @@ -106,7 +106,7 @@ public void setFlowName(String flowName) { this.flowName = flowName; } - @ApiModelProperty("The description of the flow") + @Schema(description = "The description of the flow") public String getFlowDescription() { return flowDescription; } @@ -115,7 +115,7 @@ public void setFlowDescription(String flowDescription) { this.flowDescription = flowDescription; } - @ApiModelProperty("The version of the flow") + @Schema(description = "The version of the flow") public Integer getVersion() { return version; } @@ -124,7 +124,7 @@ public void setVersion(final Integer version) { this.version = version; } - @ApiModelProperty("The storage location") + @Schema(description = "The storage location") public String getStorageLocation() { return storageLocation; } @@ -133,8 +133,8 @@ public void setStorageLocation(String storageLocation) { this.storageLocation = storageLocation; } - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY, - value = "The current state of the Process Group, as it relates to the Versioned Flow", + @Schema(accessMode = Schema.AccessMode.READ_ONLY, + description = "The current state of the Process Group, as it relates to the Versioned Flow", allowableValues = LOCALLY_MODIFIED + ", " + STALE + ", " + LOCALLY_MODIFIED_AND_STALE + ", " + UP_TO_DATE + ", " + SYNC_FAILURE) public String getState() { return state; @@ -144,7 +144,7 @@ public void setState(final String state) { this.state = state; } - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY, value = "Explanation of why the group is in the specified state") + @Schema(description = "Explanation of why the group is in the specified state", accessMode = Schema.AccessMode.READ_ONLY) public String getStateExplanation() { return stateExplanation; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowDTO.java index 8239de24a2ce1..68761a1356ccc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,7 +34,7 @@ public class VersionedFlowDTO { private String comments; private String action; - @ApiModelProperty("The ID of the registry that the flow is tracked to") + @Schema(description = "The ID of the registry that the flow is tracked to") public String getRegistryId() { return registryId; } @@ -43,7 +43,7 @@ public void setRegistryId(String registryId) { this.registryId = registryId; } - @ApiModelProperty("The ID of the bucket where the flow is stored") + @Schema(description = "The ID of the bucket where the flow is stored") public String getBucketId() { return bucketId; } @@ -52,7 +52,7 @@ public void setBucketId(String bucketId) { this.bucketId = bucketId; } - @ApiModelProperty(value = "The ID of the flow") + @Schema(description = "The ID of the flow") public String getFlowId() { return flowId; } @@ -61,7 +61,7 @@ public void setFlowId(String flowId) { this.flowId = flowId; } - @ApiModelProperty("The name of the flow") + @Schema(description = "The name of the flow") public String getFlowName() { return flowName; } @@ -70,7 +70,7 @@ public void setFlowName(String flowName) { this.flowName = flowName; } - @ApiModelProperty("A description of the flow") + @Schema(description = "A description of the flow") public String getDescription() { return description; } @@ -79,7 +79,7 @@ public void setDescription(String description) { this.description = description; } - @ApiModelProperty("Comments for the changeset") + @Schema(description = "Comments for the changeset") public String getComments() { return comments; } @@ -88,7 +88,7 @@ public void setComments(String comments) { this.comments = comments; } - @ApiModelProperty(value = "The action being performed", allowableValues = COMMIT_ACTION + ", " + FORCE_COMMIT_ACTION) + @Schema(description = "The action being performed", allowableValues = COMMIT_ACTION + ", " + FORCE_COMMIT_ACTION) public String getAction() { return action; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowUpdateRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowUpdateRequestDTO.java index 08b6bc594cd28..62c9b91b9b032 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowUpdateRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/VersionedFlowUpdateRequestDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -25,8 +25,8 @@ public class VersionedFlowUpdateRequestDTO extends FlowUpdateRequestDTO { private VersionControlInformationDTO versionControlInformation; - @ApiModelProperty(value = "The VersionControlInformation that describes where the Versioned Flow is located; this may not be populated until the request is completed.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The VersionControlInformation that describes where the Versioned Flow is located; this may not be populated until the request is completed.", + accessMode = Schema.AccessMode.READ_ONLY) public VersionControlInformationDTO getVersionControlInformation() { return versionControlInformation; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/WritablePermission.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/WritablePermission.java index 17e3f7b65b9bd..459bff30e5d5a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/WritablePermission.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/WritablePermission.java @@ -16,12 +16,11 @@ */ package org.apache.nifi.web.api.dto; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public interface WritablePermission { - @ApiModelProperty( - value = "Indicates whether the user can write a given resource.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "Indicates whether the user can write a given resource.", + accessMode = Schema.AccessMode.READ_ONLY ) Boolean getCanWrite(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/ActionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/ActionDTO.java index 4ce9d547a747c..b2a27037745d1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/ActionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/ActionDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.action.component.details.ComponentDetailsDTO; import org.apache.nifi.web.api.dto.action.details.ActionDetailsDTO; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; @@ -46,8 +46,7 @@ public class ActionDTO { /** * @return action id */ - @ApiModelProperty( - value = "The action id." + @Schema(description = "The action id." ) public Integer getId() { return id; @@ -60,8 +59,7 @@ public void setId(Integer id) { /** * @return user identity who perform this action */ - @ApiModelProperty( - value = "The identity of the user that performed the action." + @Schema(description = "The identity of the user that performed the action." ) public String getUserIdentity() { return userIdentity; @@ -75,9 +73,8 @@ public void setUserIdentity(String userIdentity) { * @return action's timestamp */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The timestamp of the action.", - dataType = "string" + @Schema(description = "The timestamp of the action.", + type = "string" ) public Date getTimestamp() { return timestamp; @@ -90,8 +87,7 @@ public void setTimestamp(Date timestamp) { /** * @return id of the source component of this action */ - @ApiModelProperty( - value = "The id of the source component." + @Schema(description = "The id of the source component." ) public String getSourceId() { return sourceId; @@ -104,8 +100,7 @@ public void setSourceId(String sourceId) { /** * @return name of the source component of this action */ - @ApiModelProperty( - value = "The name of the source component." + @Schema(description = "The name of the source component." ) public String getSourceName() { return sourceName; @@ -118,8 +113,7 @@ public void setSourceName(String sourceName) { /** * @return type of the source component of this action */ - @ApiModelProperty( - value = "The type of the source component." + @Schema(description = "The type of the source component." ) public String getSourceType() { return sourceType; @@ -132,8 +126,7 @@ public void setSourceType(String sourceType) { /** * @return component details (if any) for this action */ - @ApiModelProperty( - value = "The details of the source component." + @Schema(description = "The details of the source component." ) public ComponentDetailsDTO getComponentDetails() { return componentDetails; @@ -146,8 +139,7 @@ public void setComponentDetails(ComponentDetailsDTO componentDetails) { /** * @return operation being performed in this action */ - @ApiModelProperty( - value = "The operation that was performed." + @Schema(description = "The operation that was performed." ) public String getOperation() { return operation; @@ -160,8 +152,7 @@ public void setOperation(String operation) { /** * @return action details (if any) for this action */ - @ApiModelProperty( - value = "The details of the action." + @Schema(description = "The details of the action." ) public ActionDetailsDTO getActionDetails() { return actionDetails; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryDTO.java index a33ac788d49a6..f67b56b511ca0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import org.apache.nifi.web.api.entity.ActionEntity; @@ -38,8 +38,7 @@ public class HistoryDTO { /** * @return total number of actions */ - @ApiModelProperty( - value = "The number of number of actions that matched the search criteria.." + @Schema(description = "The number of number of actions that matched the search criteria.." ) public Integer getTotal() { return total; @@ -53,9 +52,8 @@ public void setTotal(Integer total) { * @return timestamp when these records were returned */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The timestamp when the report was generated.", - dataType = "string" + @Schema(description = "The timestamp when the report was generated.", + type = "string" ) public Date getLastRefreshed() { return lastRefreshed; @@ -68,8 +66,7 @@ public void setLastRefreshed(Date lastRefreshed) { /** * @return actions for this range */ - @ApiModelProperty( - value = "The actions." + @Schema(description = "The actions." ) public Collection getActions() { return actions; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryQueryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryQueryDTO.java index 5a74916b56f63..3e0c7c2881826 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryQueryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/HistoryQueryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -41,8 +41,7 @@ public class HistoryQueryDTO { /** * @return user identity */ - @ApiModelProperty( - value = "The user identity." + @Schema(description = "The user identity." ) public String getUserIdentity() { return userIdentity; @@ -55,8 +54,7 @@ public void setUserIdentity(String userIdentity) { /** * @return source component id */ - @ApiModelProperty( - value = "The id of the source component." + @Schema(description = "The id of the source component." ) public String getSourceId() { return sourceId; @@ -70,9 +68,8 @@ public void setSourceId(String sourceId) { * @return start date */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The start date of actions to return.", - dataType = "string" + @Schema(description = "The start date of actions to return.", + type = "string" ) public Date getStartDate() { return startDate; @@ -86,9 +83,8 @@ public void setStartDate(Date startDate) { * @return end date */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The end date of actions to return.", - dataType = "string" + @Schema(description = "The end date of actions to return.", + type = "string" ) public Date getEndDate() { return endDate; @@ -101,8 +97,7 @@ public void setEndDate(Date endDate) { /** * @return offset */ - @ApiModelProperty( - value = "The offset into the result set." + @Schema(description = "The offset into the result set." ) public Integer getOffset() { return offset; @@ -115,8 +110,7 @@ public void setOffset(Integer offset) { /** * @return desired row count */ - @ApiModelProperty( - value = "The number of actions to return." + @Schema(description = "The number of actions to return." ) public Integer getCount() { return count; @@ -129,8 +123,7 @@ public void setCount(Integer count) { /** * @return desired sort column */ - @ApiModelProperty( - value = "The field to sort on." + @Schema(description = "The field to sort on." ) public String getSortColumn() { return sortColumn; @@ -143,8 +136,7 @@ public void setSortColumn(String sortColumn) { /** * @return desired sort order */ - @ApiModelProperty( - value = "The sort order." + @Schema(description = "The sort order." ) public String getSortOrder() { return sortOrder; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/ExtensionDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/ExtensionDetailsDTO.java index 42272fb3204f0..dd4f4a9dae179 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/ExtensionDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/ExtensionDetailsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action.component.details; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,8 +31,7 @@ public class ExtensionDetailsDTO extends ComponentDetailsDTO { /** * @return extension type */ - @ApiModelProperty( - value = "The fully qualified type of extension." + @Schema(description = "The fully qualified type of extension." ) public String getType() { return type; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/RemoteProcessGroupDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/RemoteProcessGroupDetailsDTO.java index d0384e0826cbc..35b9a219c0ae9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/RemoteProcessGroupDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/component/details/RemoteProcessGroupDetailsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action.component.details; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,8 +31,7 @@ public class RemoteProcessGroupDetailsDTO extends ComponentDetailsDTO { /** * @return URI of the remote process group */ - @ApiModelProperty( - value = "The uri of the target of the remote process group." + @Schema(description = "The uri of the target of the remote process group." ) public String getUri() { return uri; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConfigureDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConfigureDetailsDTO.java index 10c1c651f8e7f..a9f5349023d0c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConfigureDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConfigureDetailsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action.details; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class ConfigureDetailsDTO extends ActionDetailsDTO { /** * @return name of the property that was modified */ - @ApiModelProperty( - value = "The name of the property that was modified." + @Schema(description = "The name of the property that was modified." ) public String getName() { return name; @@ -47,8 +46,7 @@ public void setName(String name) { /** * @return previous value */ - @ApiModelProperty( - value = "The previous value." + @Schema(description = "The previous value." ) public String getPreviousValue() { return previousValue; @@ -61,8 +59,7 @@ public void setPreviousValue(String previousValue) { /** * @return new value */ - @ApiModelProperty( - value = "The new value." + @Schema(description = "The new value." ) public String getValue() { return value; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConnectDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConnectDetailsDTO.java index 09325ef0776c9..49060e8e69aaf 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConnectDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/ConnectDetailsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action.details; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -37,8 +37,7 @@ public class ConnectDetailsDTO extends ActionDetailsDTO { /** * @return id of the source of the connection */ - @ApiModelProperty( - value = "The id of the source of the connection." + @Schema(description = "The id of the source of the connection." ) public String getSourceId() { return sourceId; @@ -51,8 +50,7 @@ public void setSourceId(String sourceId) { /** * @return name of the source of the connection */ - @ApiModelProperty( - value = "The name of the source of the connection." + @Schema(description = "The name of the source of the connection." ) public String getSourceName() { return sourceName; @@ -65,8 +63,7 @@ public void setSourceName(String sourceName) { /** * @return type of the source of the connection */ - @ApiModelProperty( - value = "The type of the source of the connection." + @Schema(description = "The type of the source of the connection." ) public String getSourceType() { return sourceType; @@ -79,8 +76,7 @@ public void setSourceType(String sourceType) { /** * @return name of the relationship that was connected */ - @ApiModelProperty( - value = "The name of the relationship that was connected." + @Schema(description = "The name of the relationship that was connected." ) public String getRelationship() { return relationship; @@ -93,8 +89,7 @@ public void setRelationship(String relationship) { /** * @return id of the destination of the connection */ - @ApiModelProperty( - value = "The id of the destination of the connection." + @Schema(description = "The id of the destination of the connection." ) public String getDestinationId() { return destinationId; @@ -107,8 +102,7 @@ public void setDestinationId(String destinationId) { /** * @return name of the destination of the connection */ - @ApiModelProperty( - value = "The name of the destination of the connection." + @Schema(description = "The name of the destination of the connection." ) public String getDestinationName() { return destinationName; @@ -121,8 +115,7 @@ public void setDestinationName(String destinationName) { /** * @return type of the destination of the connection */ - @ApiModelProperty( - value = "The type of the destination of the connection." + @Schema(description = "The type of the destination of the connection." ) public String getDestinationType() { return destinationType; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/MoveDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/MoveDetailsDTO.java index 9100955febf71..e48ae84ad8e14 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/MoveDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/MoveDetailsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action.details; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,8 +34,7 @@ public class MoveDetailsDTO extends ActionDetailsDTO { /** * @return id of the group the components previously belonged to */ - @ApiModelProperty( - value = "The id of the group the components previously belonged to." + @Schema(description = "The id of the group the components previously belonged to." ) public String getPreviousGroupId() { return previousGroupId; @@ -48,8 +47,7 @@ public void setPreviousGroupId(String previousGroupId) { /** * @return name of the group of the components previously belonged to */ - @ApiModelProperty( - value = "The name of the group the components previously belonged to." + @Schema(description = "The name of the group the components previously belonged to." ) public String getPreviousGroup() { return previousGroup; @@ -62,8 +60,7 @@ public void setPreviousGroup(String previousGroup) { /** * @return id of the group the components belong to */ - @ApiModelProperty( - value = "The id of the group that components belong to." + @Schema(description = "The id of the group that components belong to." ) public String getGroupId() { return groupId; @@ -76,8 +73,7 @@ public void setGroupId(String groupId) { /** * @return name of the group the components belong to */ - @ApiModelProperty( - value = "The name of the group the components belong to." + @Schema(description = "The name of the group the components belong to." ) public String getGroup() { return group; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/PurgeDetailsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/PurgeDetailsDTO.java index f592dc0be6ef5..3cbd8bb2dd649 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/PurgeDetailsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/action/details/PurgeDetailsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.action.details; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -35,9 +35,8 @@ public class PurgeDetailsDTO extends ActionDetailsDTO { * @return end date for this purge action */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The end date for the purge action.", - dataType = "string" + @Schema(description = "The end date for the purge action.", + type = "string" ) public Date getEndDate() { return endDate; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ClassLoaderDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ClassLoaderDiagnosticsDTO.java index 7594cde0012c1..97117cebf8fd7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ClassLoaderDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ClassLoaderDiagnosticsDTO.java @@ -21,14 +21,14 @@ import org.apache.nifi.web.api.dto.BundleDTO; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "classLoaderDiagnostics") public class ClassLoaderDiagnosticsDTO { private BundleDTO bundle; private ClassLoaderDiagnosticsDTO parentClassLoader; - @ApiModelProperty("Information about the Bundle that the ClassLoader belongs to, if any") + @Schema(description = "Information about the Bundle that the ClassLoader belongs to, if any") public BundleDTO getBundle() { return bundle; } @@ -37,7 +37,7 @@ public void setBundle(BundleDTO bundle) { this.bundle = bundle; } - @ApiModelProperty("A ClassLoaderDiagnosticsDTO that provides information about the parent ClassLoader") + @Schema(description = "A ClassLoaderDiagnosticsDTO that provides information about the parent ClassLoader") public ClassLoaderDiagnosticsDTO getParentClassLoader() { return parentClassLoader; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsDTO.java index 319cd34eede28..8e67071441ab1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.diagnostics; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ConnectionDTO; import jakarta.xml.bind.annotation.XmlType; @@ -28,7 +28,7 @@ public class ConnectionDiagnosticsDTO { private ConnectionDiagnosticsSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty(value = "Details about the connection", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Details about the connection", accessMode = Schema.AccessMode.READ_ONLY) public ConnectionDTO getConnection() { return connection; } @@ -37,8 +37,8 @@ public void setConnection(final ConnectionDTO connection) { this.connection = connection; } - @ApiModelProperty(value = "Aggregate values for all nodes in the cluster, or for this instance if not clustered", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Aggregate values for all nodes in the cluster, or for this instance if not clustered", + accessMode = Schema.AccessMode.READ_ONLY) public ConnectionDiagnosticsSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; } @@ -47,7 +47,7 @@ public void setAggregateSnapshot(final ConnectionDiagnosticsSnapshotDTO aggregat this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty(value = "A list of values for each node in the cluster, if clustered.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "A list of values for each node in the cluster, if clustered.", accessMode = Schema.AccessMode.READ_ONLY) public List getNodeSnapshots() { return nodeSnapshots; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsSnapshotDTO.java index 1875138cd1111..8938b20d41ab8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ConnectionDiagnosticsSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.diagnostics; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -30,7 +30,7 @@ public class ConnectionDiagnosticsSnapshotDTO { private LocalQueuePartitionDTO localQueuePartition; private List remoteQueuePartitions; - @ApiModelProperty("Total number of FlowFiles owned by the Connection") + @Schema(description = "Total number of FlowFiles owned by the Connection") public int getTotalFlowFileCount() { return totalFlowFileCount; } @@ -39,7 +39,7 @@ public void setTotalFlowFileCount(int totalFlowFileCount) { this.totalFlowFileCount = totalFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles owned by this Connection") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles owned by this Connection") public long getTotalByteCount() { return totalByteCount; } @@ -48,7 +48,7 @@ public void setTotalByteCount(long totalByteCount) { this.totalByteCount = totalByteCount; } - @ApiModelProperty("The Node Identifier that this information pertains to") + @Schema(description = "The Node Identifier that this information pertains to") public String getNodeIdentifier() { return nodeIdentifier; } @@ -57,7 +57,7 @@ public void setNodeIdentifier(final String nodeIdentifier) { this.nodeIdentifier = nodeIdentifier; } - @ApiModelProperty("The local queue partition, from which components can pull FlowFiles on this node.") + @Schema(description = "The local queue partition, from which components can pull FlowFiles on this node.") public LocalQueuePartitionDTO getLocalQueuePartition() { return localQueuePartition; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ControllerServiceDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ControllerServiceDiagnosticsDTO.java index 7741489d67cf9..a795f644ffe2a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ControllerServiceDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ControllerServiceDiagnosticsDTO.java @@ -21,7 +21,7 @@ import org.apache.nifi.web.api.entity.ControllerServiceEntity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "controllerServiceDiagnostics") public class ControllerServiceDiagnosticsDTO { @@ -32,7 +32,7 @@ public void setControllerService(final ControllerServiceEntity controllerService this.controllerService = controllerService; } - @ApiModelProperty("The Controller Service") + @Schema(description = "The Controller Service") public ControllerServiceEntity getControllerService() { return controllerService; } @@ -41,7 +41,7 @@ public void setClassLoaderDiagnostics(ClassLoaderDiagnosticsDTO classLoaderDiagn this.classLoaderDiagnostics = classLoaderDiagnostics; } - @ApiModelProperty("Information about the Controller Service's Class Loader") + @Schema(description = "Information about the Controller Service's Class Loader") public ClassLoaderDiagnosticsDTO getClassLoaderDiagnostics() { return classLoaderDiagnostics; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GCDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GCDiagnosticsSnapshotDTO.java index 15c598a776a8f..c9d40886ae19c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GCDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GCDiagnosticsSnapshotDTO.java @@ -21,7 +21,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "gcDiagnosticsSnapshot") public class GCDiagnosticsSnapshotDTO implements Cloneable { @@ -29,7 +29,7 @@ public class GCDiagnosticsSnapshotDTO implements Cloneable { private Long collectionCount; private Long collectionMillis; - @ApiModelProperty("The timestamp of when the Snapshot was taken") + @Schema(description = "The timestamp of when the Snapshot was taken") public Date getTimestamp() { return timestamp; } @@ -38,7 +38,7 @@ public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } - @ApiModelProperty("The number of times that Garbage Collection has occurred") + @Schema(description = "The number of times that Garbage Collection has occurred") public Long getCollectionCount() { return collectionCount; } @@ -47,7 +47,7 @@ public void setCollectionCount(Long collectionCount) { this.collectionCount = collectionCount; } - @ApiModelProperty("The number of milliseconds that the Garbage Collector spent performing Garbage Collection duties") + @Schema(description = "The number of milliseconds that the Garbage Collector spent performing Garbage Collection duties") public Long getCollectionMillis() { return collectionMillis; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GarbageCollectionDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GarbageCollectionDiagnosticsDTO.java index eb02c508c2b2f..16da751f57d2c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GarbageCollectionDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/GarbageCollectionDiagnosticsDTO.java @@ -22,14 +22,14 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "garbageCollectionDiagnostics") public class GarbageCollectionDiagnosticsDTO implements Cloneable { private String memoryManagerName; private List snapshots; - @ApiModelProperty("The name of the Memory Manager that this Garbage Collection information pertains to") + @Schema(description = "The name of the Memory Manager that this Garbage Collection information pertains to") public String getMemoryManagerName() { return memoryManagerName; } @@ -38,7 +38,7 @@ public void setMemoryManagerName(String memoryManagerName) { this.memoryManagerName = memoryManagerName; } - @ApiModelProperty("A list of snapshots that have been taken to determine the health of the JVM's heap") + @Schema(description = "A list of snapshots that have been taken to determine the health of the JVM's heap") public List getSnapshots() { return snapshots; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMControllerDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMControllerDiagnosticsSnapshotDTO.java index 3c58665b1ec2a..2444c836792c2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMControllerDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMControllerDiagnosticsSnapshotDTO.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "jvmControllerDiagnosticsSnapshot") public class JVMControllerDiagnosticsSnapshotDTO implements Cloneable { @@ -27,7 +27,7 @@ public class JVMControllerDiagnosticsSnapshotDTO implements Cloneable { private Boolean clusterCoordinator; private Integer maxTimerDrivenThreads; - @ApiModelProperty("Whether or not this node is primary node") + @Schema(description = "Whether or not this node is primary node") public Boolean getPrimaryNode() { return primaryNode; } @@ -36,7 +36,7 @@ public void setPrimaryNode(Boolean primaryNode) { this.primaryNode = primaryNode; } - @ApiModelProperty("Whether or not this node is cluster coordinator") + @Schema(description = "Whether or not this node is cluster coordinator") public Boolean getClusterCoordinator() { return clusterCoordinator; } @@ -45,7 +45,7 @@ public void setClusterCoordinator(Boolean clusterCoordinator) { this.clusterCoordinator = clusterCoordinator; } - @ApiModelProperty("The maximum number of timer-driven threads") + @Schema(description = "The maximum number of timer-driven threads") public Integer getMaxTimerDrivenThreads() { return maxTimerDrivenThreads; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsDTO.java index 1396c49885f46..64af8114834d4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsDTO.java @@ -21,7 +21,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "jvmDiagnostics") public class JVMDiagnosticsDTO { @@ -30,7 +30,7 @@ public class JVMDiagnosticsDTO { private JVMDiagnosticsSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty("Whether or not the NiFi instance is clustered") + @Schema(description = "Whether or not the NiFi instance is clustered") public Boolean getClustered() { return clustered; } @@ -39,7 +39,7 @@ public void setClustered(Boolean clustered) { this.clustered = clustered; } - @ApiModelProperty("Whether or not the node is connected to the cluster") + @Schema(description = "Whether or not the node is connected to the cluster") public Boolean getConnected() { return connected; } @@ -48,7 +48,7 @@ public void setConnected(Boolean connected) { this.connected = connected; } - @ApiModelProperty("Aggregate JVM diagnostic information about the entire cluster") + @Schema(description = "Aggregate JVM diagnostic information about the entire cluster") public JVMDiagnosticsSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; } @@ -57,7 +57,7 @@ public void setAggregateSnapshot(JVMDiagnosticsSnapshotDTO aggregateSnapshot) { this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("Node-wise breakdown of JVM diagnostic information") + @Schema(description = "Node-wise breakdown of JVM diagnostic information") public List getNodeSnapshots() { return nodeSnapshots; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsSnapshotDTO.java index c0c1c2359dbfa..365502bfa4c90 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMDiagnosticsSnapshotDTO.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "jvmDiagnosticsSnapshot") public class JVMDiagnosticsSnapshotDTO implements Cloneable { @@ -27,7 +27,7 @@ public class JVMDiagnosticsSnapshotDTO implements Cloneable { private JVMFlowDiagnosticsSnapshotDTO flowDiagnosticsDto; private JVMControllerDiagnosticsSnapshotDTO controllerDiagnosticsDto; - @ApiModelProperty("System-related diagnostics information") + @Schema(description = "System-related diagnostics information") public JVMSystemDiagnosticsSnapshotDTO getSystemDiagnosticsDto() { return systemDiagnosticsDto; } @@ -36,7 +36,7 @@ public void setSystemDiagnosticsDto(JVMSystemDiagnosticsSnapshotDTO systemDiagno this.systemDiagnosticsDto = systemDiagnosticsDto; } - @ApiModelProperty("Flow-related diagnostics information") + @Schema(description = "Flow-related diagnostics information") public JVMFlowDiagnosticsSnapshotDTO getFlowDiagnosticsDto() { return flowDiagnosticsDto; } @@ -45,7 +45,7 @@ public void setFlowDiagnosticsDto(JVMFlowDiagnosticsSnapshotDTO flowDiagnosticsD this.flowDiagnosticsDto = flowDiagnosticsDto; } - @ApiModelProperty("Controller-related diagnostics information") + @Schema(description = "Controller-related diagnostics information") public JVMControllerDiagnosticsSnapshotDTO getControllerDiagnostics() { return controllerDiagnosticsDto; } @@ -78,7 +78,7 @@ public static class VersionInfoDTO implements Cloneable { private String osVersion; private String osArchitecture; - @ApiModelProperty("The version of this NiFi.") + @Schema(description = "The version of this NiFi.") public String getNiFiVersion() { return niFiVersion; } @@ -87,7 +87,7 @@ public void setNiFiVersion(String niFiVersion) { this.niFiVersion = niFiVersion; } - @ApiModelProperty("Java vendor") + @Schema(description = "Java vendor") public String getJavaVendor() { return javaVendor; } @@ -96,7 +96,7 @@ public void setJavaVendor(String javaVendor) { this.javaVendor = javaVendor; } - @ApiModelProperty("Java VM Vendor") + @Schema(description = "Java VM Vendor") public String getJavaVmVendor() { return javaVmVendor; } @@ -105,7 +105,7 @@ public void setJavaVmVendor(String javaVmVendor) { this.javaVmVendor = javaVmVendor; } - @ApiModelProperty("Java version") + @Schema(description = "Java version") public String getJavaVersion() { return javaVersion; } @@ -114,7 +114,7 @@ public void setJavaVersion(String javaVersion) { this.javaVersion = javaVersion; } - @ApiModelProperty("Host operating system name") + @Schema(description = "Host operating system name") public String getOsName() { return osName; } @@ -123,7 +123,7 @@ public void setOsName(String osName) { this.osName = osName; } - @ApiModelProperty("Host operating system version") + @Schema(description = "Host operating system version") public String getOsVersion() { return osVersion; } @@ -132,7 +132,7 @@ public void setOsVersion(String osVersion) { this.osVersion = osVersion; } - @ApiModelProperty("Host operating system architecture") + @Schema(description = "Host operating system architecture") public String getOsArchitecture() { return osArchitecture; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMFlowDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMFlowDiagnosticsSnapshotDTO.java index d7025d0a8b0e8..c3f1d074f5053 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMFlowDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMFlowDiagnosticsSnapshotDTO.java @@ -24,7 +24,7 @@ import org.apache.nifi.web.api.dto.BundleDTO; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "jvmFlowDiagnosticsSnapshot") public class JVMFlowDiagnosticsSnapshotDTO implements Cloneable { @@ -33,7 +33,7 @@ public class JVMFlowDiagnosticsSnapshotDTO implements Cloneable { private Integer activeTimerDrivenThreads; private Set bundlesLoaded; - @ApiModelProperty("How long this node has been running, formatted as hours:minutes:seconds.milliseconds") + @Schema(description = "How long this node has been running, formatted as hours:minutes:seconds.milliseconds") public String getUptime() { return uptime; } @@ -42,7 +42,7 @@ public void setUptime(String uptime) { this.uptime = uptime; } - @ApiModelProperty("The name of the Time Zone that is configured, if available") + @Schema(description = "The name of the Time Zone that is configured, if available") public String getTimeZone() { return timeZone; } @@ -52,7 +52,7 @@ public void setTimeZone(String timeZone) { } - @ApiModelProperty("The number of timer-driven threads that are active") + @Schema(description = "The number of timer-driven threads that are active") public Integer getActiveTimerDrivenThreads() { return activeTimerDrivenThreads; } @@ -61,7 +61,7 @@ public void setActiveTimerDrivenThreads(Integer activeTimerDrivenThreads) { this.activeTimerDrivenThreads = activeTimerDrivenThreads; } - @ApiModelProperty("The NiFi Bundles (NARs) that are loaded by NiFi") + @Schema(description = "The NiFi Bundles (NARs) that are loaded by NiFi") public Set getBundlesLoaded() { return bundlesLoaded; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMSystemDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMSystemDiagnosticsSnapshotDTO.java index 85a9781c5b6cf..26ec2ca667b7c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMSystemDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/JVMSystemDiagnosticsSnapshotDTO.java @@ -23,7 +23,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "jvmSystemDiagnosticsSnapshot") public class JVMSystemDiagnosticsSnapshotDTO implements Cloneable { @@ -45,7 +45,7 @@ public class JVMSystemDiagnosticsSnapshotDTO implements Cloneable { private Long maxOpenFileDescriptors; - @ApiModelProperty("Information about the FlowFile Repository's usage") + @Schema(description = "Information about the FlowFile Repository's usage") public RepositoryUsageDTO getFlowFileRepositoryStorageUsage() { return flowFileRepositoryStorageUsage; } @@ -54,7 +54,7 @@ public void setFlowFileRepositoryStorageUsage(RepositoryUsageDTO flowFileReposit this.flowFileRepositoryStorageUsage = flowFileRepositoryStorageUsage; } - @ApiModelProperty("Information about the Content Repository's usage") + @Schema(description = "Information about the Content Repository's usage") public Set getContentRepositoryStorageUsage() { return contentRepositoryStorageUsage; } @@ -63,7 +63,7 @@ public void setContentRepositoryStorageUsage(Set contentRepo this.contentRepositoryStorageUsage = contentRepositoryStorageUsage; } - @ApiModelProperty("Information about the Provenance Repository's usage") + @Schema(description = "Information about the Provenance Repository's usage") public Set getProvenanceRepositoryStorageUsage() { return provenanceRepositoryStorageUsage; } @@ -72,7 +72,7 @@ public void setProvenanceRepositoryStorageUsage(Set provenan this.provenanceRepositoryStorageUsage = provenanceRepositoryStorageUsage; } - @ApiModelProperty("The maximum number of bytes that the JVM heap is configured to use for heap") + @Schema(description = "The maximum number of bytes that the JVM heap is configured to use for heap") public Long getMaxHeapBytes() { return maxHeapBytes; } @@ -81,7 +81,7 @@ public void setMaxHeapBytes(Long heapBytes) { this.maxHeapBytes = heapBytes; } - @ApiModelProperty("The maximum number of bytes that the JVM heap is configured to use, as a human-readable value") + @Schema(description = "The maximum number of bytes that the JVM heap is configured to use, as a human-readable value") public String getMaxHeap() { return maxHeap; } @@ -90,7 +90,7 @@ public void setMaxHeap(String maxHeap) { this.maxHeap = maxHeap; } - @ApiModelProperty("The number of CPU Cores available on the system") + @Schema(description = "The number of CPU Cores available on the system") public Integer getCpuCores() { return cpuCores; } @@ -99,7 +99,7 @@ public void setCpuCores(Integer cpuCores) { this.cpuCores = cpuCores; } - @ApiModelProperty("The 1-minute CPU Load Average") + @Schema(description = "The 1-minute CPU Load Average") public Double getCpuLoadAverage() { return cpuLoadAverage; } @@ -108,7 +108,7 @@ public void setCpuLoadAverage(Double cpuLoadAverage) { this.cpuLoadAverage = cpuLoadAverage; } - @ApiModelProperty("The number of bytes of RAM available on the system") + @Schema(description = "The number of bytes of RAM available on the system") public Long getPhysicalMemoryBytes() { return physicalMemoryBytes; } @@ -117,7 +117,7 @@ public void setPhysicalMemoryBytes(Long memoryBytes) { this.physicalMemoryBytes = memoryBytes; } - @ApiModelProperty("The number of bytes of RAM available on the system as a human-readable value") + @Schema(description = "The number of bytes of RAM available on the system as a human-readable value") public String getPhysicalMemory() { return physicalMemory; } @@ -126,7 +126,7 @@ public void setPhysicalMemory(String memory) { this.physicalMemory = memory; } - @ApiModelProperty("The number of files that are open by the NiFi process") + @Schema(description = "The number of files that are open by the NiFi process") public Long getOpenFileDescriptors() { return openFileDescriptors; } @@ -135,7 +135,7 @@ public void setOpenFileDescriptors(Long openFileDescriptors) { this.openFileDescriptors = openFileDescriptors; } - @ApiModelProperty("The maximum number of open file descriptors that are available to each process") + @Schema(description = "The maximum number of open file descriptors that are available to each process") public Long getMaxOpenFileDescriptors() { return maxOpenFileDescriptors; } @@ -144,7 +144,7 @@ public void setMaxOpenFileDescriptors(Long maxOpenFileDescriptors) { this.maxOpenFileDescriptors = maxOpenFileDescriptors; } - @ApiModelProperty("Diagnostic information about the JVM's garbage collections") + @Schema(description = "Diagnostic information about the JVM's garbage collections") public List getGarbageCollectionDiagnostics() { return garbageCollectionDiagnostics; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/LocalQueuePartitionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/LocalQueuePartitionDTO.java index 65a668a2992de..cac58572275d0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/LocalQueuePartitionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/LocalQueuePartitionDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.diagnostics; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -35,7 +35,7 @@ public class LocalQueuePartitionDTO { private Boolean allActiveQueueFlowFilesPenalized; private Boolean anyActiveQueueFlowFilesPenalized; - @ApiModelProperty("Total number of FlowFiles owned by the Connection") + @Schema(description = "Total number of FlowFiles owned by the Connection") public int getTotalFlowFileCount() { return totalFlowFileCount; } @@ -44,7 +44,7 @@ public void setTotalFlowFileCount(int totalFlowFileCount) { this.totalFlowFileCount = totalFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles owned by this Connection") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles owned by this Connection") public long getTotalByteCount() { return totalByteCount; } @@ -53,7 +53,7 @@ public void setTotalByteCount(long totalByteCount) { this.totalByteCount = totalByteCount; } - @ApiModelProperty("Total number of FlowFiles that exist in the Connection's Active Queue, immediately available to be offered up to a component") + @Schema(description = "Total number of FlowFiles that exist in the Connection's Active Queue, immediately available to be offered up to a component") public int getActiveQueueFlowFileCount() { return activeQueueFlowFileCount; } @@ -62,7 +62,7 @@ public void setActiveQueueFlowFileCount(int activeQueueFlowFileCount) { this.activeQueueFlowFileCount = activeQueueFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles that are present in the Connection's Active Queue") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles that are present in the Connection's Active Queue") public long getActiveQueueByteCount() { return activeQueueByteCount; } @@ -71,7 +71,7 @@ public void setActiveQueueByteCount(long activeQueueByteCount) { this.activeQueueByteCount = activeQueueByteCount; } - @ApiModelProperty("The total number of FlowFiles that are swapped out for this Connection") + @Schema(description = "The total number of FlowFiles that are swapped out for this Connection") public int getSwapFlowFileCount() { return swapFlowFileCount; } @@ -80,7 +80,7 @@ public void setSwapFlowFileCount(int swapFlowFileCount) { this.swapFlowFileCount = swapFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles that are swapped out to disk for the Connection") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles that are swapped out to disk for the Connection") public long getSwapByteCount() { return swapByteCount; } @@ -89,7 +89,7 @@ public void setSwapByteCount(long swapByteCount) { this.swapByteCount = swapByteCount; } - @ApiModelProperty("The number of Swap Files that exist for this Connection") + @Schema(description = "The number of Swap Files that exist for this Connection") public int getSwapFiles() { return swapFiles; } @@ -98,7 +98,7 @@ public void setSwapFiles(int swapFiles) { this.swapFiles = swapFiles; } - @ApiModelProperty("The number of In-Flight FlowFiles for this Connection. These are FlowFiles that belong to the connection but are currently being operated on by a Processor, Port, etc.") + @Schema(description = "The number of In-Flight FlowFiles for this Connection. These are FlowFiles that belong to the connection but are currently being operated on by a Processor, Port, etc.") public int getInFlightFlowFileCount() { return inFlightFlowFileCount; } @@ -107,7 +107,7 @@ public void setInFlightFlowFileCount(int inFlightFlowFileCount) { this.inFlightFlowFileCount = inFlightFlowFileCount; } - @ApiModelProperty("The number bytes that make up the content of the FlowFiles that are In-Flight") + @Schema(description = "The number bytes that make up the content of the FlowFiles that are In-Flight") public long getInFlightByteCount() { return inFlightByteCount; } @@ -116,7 +116,7 @@ public void setInFlightByteCount(long inFlightByteCount) { this.inFlightByteCount = inFlightByteCount; } - @ApiModelProperty("Whether or not all of the FlowFiles in the Active Queue are penalized") + @Schema(description = "Whether or not all of the FlowFiles in the Active Queue are penalized") public Boolean getAllActiveQueueFlowFilesPenalized() { return allActiveQueueFlowFilesPenalized; } @@ -125,7 +125,7 @@ public void setAllActiveQueueFlowFilesPenalized(Boolean allFlowFilesPenalized) { this.allActiveQueueFlowFilesPenalized = allFlowFilesPenalized; } - @ApiModelProperty("Whether or not any of the FlowFiles in the Active Queue are penalized") + @Schema(description = "Whether or not any of the FlowFiles in the Active Queue are penalized") public Boolean getAnyActiveQueueFlowFilesPenalized() { return anyActiveQueueFlowFilesPenalized; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeGCDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeGCDiagnosticsSnapshotDTO.java index cd0ac1b58f2e7..4700285808eb9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeGCDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeGCDiagnosticsSnapshotDTO.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "nodeGCDiagnosticsSnapshot") public class NodeGCDiagnosticsSnapshotDTO { @@ -29,7 +29,7 @@ public class NodeGCDiagnosticsSnapshotDTO { private GCDiagnosticsSnapshotDTO snapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The Garbage Collection Diagnostics Snapshot") + @Schema(description = "The Garbage Collection Diagnostics Snapshot") public GCDiagnosticsSnapshotDTO getSnapshot() { return snapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeJVMDiagnosticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeJVMDiagnosticsSnapshotDTO.java index 8aab6fb88bdc3..be7c7576344b0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeJVMDiagnosticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/NodeJVMDiagnosticsSnapshotDTO.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "nodeJVMDiagnosticsSnapshot") public class NodeJVMDiagnosticsSnapshotDTO { @@ -29,7 +29,7 @@ public class NodeJVMDiagnosticsSnapshotDTO { private JVMDiagnosticsSnapshotDTO snapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The JVM Diagnostics Snapshot") + @Schema(description = "The JVM Diagnostics Snapshot") public JVMDiagnosticsSnapshotDTO getSnapshot() { return snapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ProcessorDiagnosticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ProcessorDiagnosticsDTO.java index 5164926a87f37..4d589ad728f2a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ProcessorDiagnosticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ProcessorDiagnosticsDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.diagnostics; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ProcessorDTO; import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO; @@ -37,7 +37,7 @@ public class ProcessorDiagnosticsDTO { private ClassLoaderDiagnosticsDTO classLoaderDiagnostics; - @ApiModelProperty("Information about the Processor for which the Diagnostic Report is generated") + @Schema(description = "Information about the Processor for which the Diagnostic Report is generated") public ProcessorDTO getProcessor() { return processor; } @@ -46,7 +46,7 @@ public void setProcessor(ProcessorDTO processor) { this.processor = processor; } - @ApiModelProperty("The Status for the Processor for which the Diagnostic Report is generated") + @Schema(description = "The Status for the Processor for which the Diagnostic Report is generated") public ProcessorStatusDTO getProcessorStatus() { return processorStatus; } @@ -55,7 +55,7 @@ public void setProcessorStatus(ProcessorStatusDTO processorStatus) { this.processorStatus = processorStatus; } - @ApiModelProperty("Diagnostic Information about all Controller Services that the Processor is referencing") + @Schema(description = "Diagnostic Information about all Controller Services that the Processor is referencing") public Set getReferencedControllerServices() { return referencedControllerServices; } @@ -64,7 +64,7 @@ public void setReferencedControllerServices(Set this.referencedControllerServices = referencedControllerServices; } - @ApiModelProperty("Diagnostic Information about all incoming Connections") + @Schema(description = "Diagnostic Information about all incoming Connections") public Set getIncomingConnections() { return incomingConnections; } @@ -73,7 +73,7 @@ public void setIncomingConnections(Set incomingConnect this.incomingConnections = incomingConnections; } - @ApiModelProperty("Diagnostic Information about all outgoing Connections") + @Schema(description = "Diagnostic Information about all outgoing Connections") public Set getOutgoingConnections() { return outgoingConnections; } @@ -82,7 +82,7 @@ public void setOutgoingConnections(Set outgoingConnect this.outgoingConnections = outgoingConnections; } - @ApiModelProperty("Diagnostic Information about the JVM and system-level diagnostics") + @Schema(description = "Diagnostic Information about the JVM and system-level diagnostics") public JVMDiagnosticsDTO getJvmDiagnostics() { return jvmDiagnostics; } @@ -91,7 +91,7 @@ public void setJvmDiagnostics(JVMDiagnosticsDTO jvmDiagnostics) { this.jvmDiagnostics = jvmDiagnostics; } - @ApiModelProperty("Thread Dumps that were taken of the threads that are active in the Processor") + @Schema(description = "Thread Dumps that were taken of the threads that are active in the Processor") public List getThreadDumps() { return threadDumps; } @@ -100,7 +100,7 @@ public void setThreadDumps(List threadDumps) { this.threadDumps = threadDumps; } - @ApiModelProperty("Information about the Controller Service's Class Loader") + @Schema(description = "Information about the Controller Service's Class Loader") public ClassLoaderDiagnosticsDTO getClassLoaderDiagnostics() { return classLoaderDiagnostics; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RemoteQueuePartitionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RemoteQueuePartitionDTO.java index 157aed8ca06bd..1a15837ef8934 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RemoteQueuePartitionDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RemoteQueuePartitionDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.diagnostics; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,7 +34,7 @@ public class RemoteQueuePartitionDTO { private int inFlightFlowFileCount; private long inFlightByteCount; - @ApiModelProperty("The Node Identifier that this queue partition is sending to") + @Schema(description = "The Node Identifier that this queue partition is sending to") public String getNodeIdentifier() { return nodeId; } @@ -43,7 +43,7 @@ public void setNodeIdentifier(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("Total number of FlowFiles owned by the Connection") + @Schema(description = "Total number of FlowFiles owned by the Connection") public int getTotalFlowFileCount() { return totalFlowFileCount; } @@ -52,7 +52,7 @@ public void setTotalFlowFileCount(int totalFlowFileCount) { this.totalFlowFileCount = totalFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles owned by this Connection") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles owned by this Connection") public long getTotalByteCount() { return totalByteCount; } @@ -61,7 +61,7 @@ public void setTotalByteCount(long totalByteCount) { this.totalByteCount = totalByteCount; } - @ApiModelProperty("Total number of FlowFiles that exist in the Connection's Active Queue, immediately available to be offered up to a component") + @Schema(description = "Total number of FlowFiles that exist in the Connection's Active Queue, immediately available to be offered up to a component") public int getActiveQueueFlowFileCount() { return activeQueueFlowFileCount; } @@ -70,7 +70,7 @@ public void setActiveQueueFlowFileCount(int activeQueueFlowFileCount) { this.activeQueueFlowFileCount = activeQueueFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles that are present in the Connection's Active Queue") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles that are present in the Connection's Active Queue") public long getActiveQueueByteCount() { return activeQueueByteCount; } @@ -79,7 +79,7 @@ public void setActiveQueueByteCount(long activeQueueByteCount) { this.activeQueueByteCount = activeQueueByteCount; } - @ApiModelProperty("The total number of FlowFiles that are swapped out for this Connection") + @Schema(description = "The total number of FlowFiles that are swapped out for this Connection") public int getSwapFlowFileCount() { return swapFlowFileCount; } @@ -88,7 +88,7 @@ public void setSwapFlowFileCount(int swapFlowFileCount) { this.swapFlowFileCount = swapFlowFileCount; } - @ApiModelProperty("Total number of bytes that make up the content for the FlowFiles that are swapped out to disk for the Connection") + @Schema(description = "Total number of bytes that make up the content for the FlowFiles that are swapped out to disk for the Connection") public long getSwapByteCount() { return swapByteCount; } @@ -97,7 +97,7 @@ public void setSwapByteCount(long swapByteCount) { this.swapByteCount = swapByteCount; } - @ApiModelProperty("The number of Swap Files that exist for this Connection") + @Schema(description = "The number of Swap Files that exist for this Connection") public int getSwapFiles() { return swapFiles; } @@ -106,7 +106,7 @@ public void setSwapFiles(int swapFiles) { this.swapFiles = swapFiles; } - @ApiModelProperty("The number of In-Flight FlowFiles for this Connection. These are FlowFiles that belong to the connection but are currently being operated on by a Processor, Port, etc.") + @Schema(description = "The number of In-Flight FlowFiles for this Connection. These are FlowFiles that belong to the connection but are currently being operated on by a Processor, Port, etc.") public int getInFlightFlowFileCount() { return inFlightFlowFileCount; } @@ -115,7 +115,7 @@ public void setInFlightFlowFileCount(int inFlightFlowFileCount) { this.inFlightFlowFileCount = inFlightFlowFileCount; } - @ApiModelProperty("The number bytes that make up the content of the FlowFiles that are In-Flight") + @Schema(description = "The number bytes that make up the content of the FlowFiles that are In-Flight") public long getInFlightByteCount() { return inFlightByteCount; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RepositoryUsageDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RepositoryUsageDTO.java index 1e10baf66d173..6e137359c39ea 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RepositoryUsageDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/RepositoryUsageDTO.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "repositoryUsage") public class RepositoryUsageDTO implements Cloneable { @@ -33,7 +33,7 @@ public class RepositoryUsageDTO implements Cloneable { private String utilization; - @ApiModelProperty("The name of the repository") + @Schema(description = "The name of the repository") public String getName() { return name; } @@ -42,7 +42,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("A SHA-256 hash of the File Store name/path that is used to store the repository's data. This information is exposed as a hash in order to avoid " + @Schema(description = "A SHA-256 hash of the File Store name/path that is used to store the repository's data. This information is exposed as a hash in order to avoid " + "exposing potentially sensitive information that is not generally relevant. What is typically relevant is whether or not multiple repositories on the same node are " + "using the same File Store, as this indicates that the repositories are competing for the resources of the backing disk/storage mechanism.") public String getFileStoreHash() { @@ -53,7 +53,7 @@ public void setFileStoreHash(String fileStore) { this.fileStoreHash = fileStore; } - @ApiModelProperty("Amount of free space.") + @Schema(description = "Amount of free space.") public String getFreeSpace() { return freeSpace; } @@ -62,7 +62,7 @@ public void setFreeSpace(String freeSpace) { this.freeSpace = freeSpace; } - @ApiModelProperty("Amount of total space.") + @Schema(description = "Amount of total space.") public String getTotalSpace() { return totalSpace; } @@ -71,7 +71,7 @@ public void setTotalSpace(String totalSpace) { this.totalSpace = totalSpace; } - @ApiModelProperty("Utilization of this storage location.") + @Schema(description = "Utilization of this storage location.") public String getUtilization() { return utilization; } @@ -80,7 +80,7 @@ public void setUtilization(String utilization) { this.utilization = utilization; } - @ApiModelProperty("The number of bytes of free space.") + @Schema(description = "The number of bytes of free space.") public Long getFreeSpaceBytes() { return freeSpaceBytes; } @@ -89,7 +89,7 @@ public void setFreeSpaceBytes(Long freeSpaceBytes) { this.freeSpaceBytes = freeSpaceBytes; } - @ApiModelProperty("The number of bytes of total space.") + @Schema(description = "The number of bytes of total space.") public Long getTotalSpaceBytes() { return totalSpaceBytes; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ThreadDumpDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ThreadDumpDTO.java index dc1410e7cd4fe..38ae807bef3bf 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ThreadDumpDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/diagnostics/ThreadDumpDTO.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlType(name = "threadDump") public class ThreadDumpDTO { @@ -31,7 +31,7 @@ public class ThreadDumpDTO { private long threadActiveMillis; private boolean taskTerminated; - @ApiModelProperty("The ID of the node in the cluster") + @Schema(description = "The ID of the node in the cluster") public String getNodeId() { return nodeId; } @@ -40,7 +40,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The address of the node in the cluster") + @Schema(description = "The address of the node in the cluster") public String getNodeAddress() { return nodeAddress; } @@ -49,7 +49,7 @@ public void setNodeAddress(String nodeAddress) { this.nodeAddress = nodeAddress; } - @ApiModelProperty("The port the node is listening for API requests.") + @Schema(description = "The port the node is listening for API requests.") public Integer getApiPort() { return apiPort; } @@ -58,7 +58,7 @@ public void setApiPort(Integer port) { this.apiPort = port; } - @ApiModelProperty("The stack trace for the thread") + @Schema(description = "The stack trace for the thread") public String getStackTrace() { return stackTrace; } @@ -67,7 +67,7 @@ public void setStackTrace(String stackTrace) { this.stackTrace = stackTrace; } - @ApiModelProperty("The name of the thread") + @Schema(description = "The name of the thread") public String getThreadName() { return threadName; } @@ -76,7 +76,7 @@ public void setThreadName(String threadName) { this.threadName = threadName; } - @ApiModelProperty("The number of milliseconds that the thread has been executing in the Processor") + @Schema(description = "The number of milliseconds that the thread has been executing in the Processor") public long getThreadActiveMillis() { return threadActiveMillis; } @@ -89,7 +89,7 @@ public void setTaskTerminated(final boolean terminated) { this.taskTerminated = terminated; } - @ApiModelProperty("Indicates whether or not the user has requested that the task be terminated. If this is true, it may indicate that " + @Schema(description = "Indicates whether or not the user has requested that the task be terminated. If this is true, it may indicate that " + "the thread is in a state where it will continue running indefinitely without returning.") public boolean isTaskTerminated() { return taskTerminated; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java index d30163a728b2f..d4b7efda7702d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.VersionControlInformationDTO; import jakarta.xml.bind.annotation.XmlType; @@ -36,8 +36,7 @@ public class FlowBreadcrumbDTO { * * @return The id */ - @ApiModelProperty( - value = "The id of the group." + @Schema(description = "The id of the group." ) public String getId() { return this.id; @@ -52,8 +51,7 @@ public void setId(final String id) { * * @return The name */ - @ApiModelProperty( - value = "The id of the group." + @Schema(description = "The id of the group." ) public String getName() { return this.name; @@ -66,8 +64,7 @@ public void setName(final String name) { /** * @return the process group version control information or null if not version controlled */ - @ApiModelProperty( - value = "The process group version control information or null if not version controlled." + @Schema(description = "The process group version control information or null if not version controlled." ) public VersionControlInformationDTO getVersionControlInformation() { return versionControlInformation; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java index a73807bc66586..3b0dfce9f3351 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ConnectionEntity; import org.apache.nifi.web.api.entity.FunnelEntity; import org.apache.nifi.web.api.entity.LabelEntity; @@ -47,8 +47,7 @@ public class FlowDTO { /** * @return connections in this flow */ - @ApiModelProperty( - value = "The connections in this flow." + @Schema(description = "The connections in this flow." ) public Set getConnections() { return connections; @@ -61,8 +60,7 @@ public void setConnections(Set connections) { /** * @return input ports in this flow */ - @ApiModelProperty( - value = "The input ports in this flow." + @Schema(description = "The input ports in this flow." ) public Set getInputPorts() { return inputPorts; @@ -75,8 +73,7 @@ public void setInputPorts(Set inputPorts) { /** * @return labels in this flow */ - @ApiModelProperty( - value = "The labels in this flow." + @Schema(description = "The labels in this flow." ) public Set getLabels() { return labels; @@ -89,8 +86,7 @@ public void setLabels(Set labels) { /** * @return funnels in this flow */ - @ApiModelProperty( - value = "The funnels in this flow." + @Schema(description = "The funnels in this flow." ) public Set getFunnels() { return funnels; @@ -103,8 +99,7 @@ public void setFunnels(Set funnels) { /** * @return output ports in this flow */ - @ApiModelProperty( - value = "The output ports in this flow." + @Schema(description = "The output ports in this flow." ) public Set getOutputPorts() { return outputPorts; @@ -117,8 +112,7 @@ public void setOutputPorts(Set outputPorts) { /** * @return process groups in this flow */ - @ApiModelProperty( - value = "The process groups in this flow." + @Schema(description = "The process groups in this flow." ) public Set getProcessGroups() { return processGroups; @@ -131,8 +125,7 @@ public void setProcessGroups(Set processGroups) { /** * @return processors in this flow */ - @ApiModelProperty( - value = "The processors in this flow." + @Schema(description = "The processors in this flow." ) public Set getProcessors() { return processors; @@ -145,8 +138,7 @@ public void setProcessors(Set processors) { /** * @return remote process groups in this flow */ - @ApiModelProperty( - value = "The remote process groups in this flow." + @Schema(description = "The remote process groups in this flow." ) public Set getRemoteProcessGroups() { return remoteProcessGroups; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java index 0bcc8b50134cc..56ba4be694a8e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.flow; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import org.apache.nifi.web.api.entity.FlowBreadcrumbEntity; import org.apache.nifi.web.api.entity.ParameterContextReferenceEntity; @@ -42,8 +42,7 @@ public class ProcessGroupFlowDTO { /** * @return contents of this process group. This field will be populated if the request is marked verbose */ - @ApiModelProperty( - value = "The flow structure starting at this Process Group." + @Schema(description = "The flow structure starting at this Process Group." ) public FlowDTO getFlow() { return flow; @@ -58,8 +57,7 @@ public void setFlow(FlowDTO flow) { * * @return The id */ - @ApiModelProperty( - value = "The id of the component." + @Schema(description = "The id of the component." ) public String getId() { return this.id; @@ -74,8 +72,7 @@ public void setId(final String id) { * * @return The breadcrumb for this ProcessGroup flow */ - @ApiModelProperty( - value = "The breadcrumb of the process group." + @Schema(description = "The breadcrumb of the process group." ) public FlowBreadcrumbEntity getBreadcrumb() { return breadcrumb; @@ -88,8 +85,7 @@ public void setBreadcrumb(FlowBreadcrumbEntity breadcrumb) { /** * @return id for the parent group of this component if applicable, null otherwise */ - @ApiModelProperty( - value = "The id of parent process group of this component if applicable." + @Schema(description = "The id of parent process group of this component if applicable." ) public String getParentGroupId() { return parentGroupId; @@ -104,8 +100,7 @@ public void setParentGroupId(String parentGroupId) { * * @return The uri */ - @ApiModelProperty( - value = "The URI for futures requests to the component." + @Schema(description = "The URI for futures requests to the component." ) public String getUri() { return uri; @@ -116,9 +111,8 @@ public void setUri(String uri) { } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The time the flow for the process group was last refreshed.", - dataType = "string" + @Schema(description = "The time the flow for the process group was last refreshed.", + type = "string" ) public Date getLastRefreshed() { return lastRefreshed; @@ -128,7 +122,7 @@ public void setLastRefreshed(Date lastRefreshed) { this.lastRefreshed = lastRefreshed; } - @ApiModelProperty("The Parameter Context, or null if no Parameter Context has been bound to the Process Group") + @Schema(description = "The Parameter Context, or null if no Parameter Context has been bound to the Process Group") public ParameterContextReferenceEntity getParameterContext() { return parameterContext; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/AttributeDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/AttributeDTO.java index 1d83d33fd648a..75c2649ab88ef 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/AttributeDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/AttributeDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class AttributeDTO { /** * @return attribute name */ - @ApiModelProperty( - value = "The attribute name." + @Schema(description = "The attribute name." ) public String getName() { return name; @@ -47,8 +46,7 @@ public void setName(String name) { /** * @return attribute value */ - @ApiModelProperty( - value = "The attribute value." + @Schema(description = "The attribute value." ) public String getValue() { return value; @@ -61,8 +59,7 @@ public void setValue(String value) { /** * @return value of this attribute before the event took place */ - @ApiModelProperty( - value = "The value of the attribute before the event took place." + @Schema(description = "The value of the attribute before the event took place." ) public String getPreviousValue() { return previousValue; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceDTO.java index 7ef60cc8520b0..21de8846c15e5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -44,8 +44,7 @@ public class ProvenanceDTO { /** * @return id of this provenance query */ - @ApiModelProperty( - value = "The id of the provenance query." + @Schema(description = "The id of the provenance query." ) public String getId() { return id; @@ -58,8 +57,7 @@ public void setId(String id) { /** * @return URI for this query. Used for obtaining the requests at a later time */ - @ApiModelProperty( - value = "The URI for this query. Used for obtaining/deleting the request at a later time" + @Schema(description = "The URI for this query. Used for obtaining/deleting the request at a later time" ) public String getUri() { return uri; @@ -73,9 +71,8 @@ public void setUri(String uri) { * @return time the query was submitted */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp when the query was submitted.", - dataType = "string" + @Schema(description = "The timestamp when the query was submitted.", + type = "string" ) public Date getSubmissionTime() { return submissionTime; @@ -89,9 +86,8 @@ public void setSubmissionTime(Date submissionTime) { * @return expiration time of the query results */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp when the query will expire.", - dataType = "string" + @Schema(description = "The timestamp when the query will expire.", + type = "string" ) public Date getExpiration() { return expiration; @@ -104,8 +100,7 @@ public void setExpiration(Date expiration) { /** * @return percent completed */ - @ApiModelProperty( - value = "The current percent complete." + @Schema(description = "The current percent complete." ) public Integer getPercentCompleted() { return percentCompleted; @@ -118,8 +113,7 @@ public void setPercentCompleted(Integer percentCompleted) { /** * @return whether the query has finished */ - @ApiModelProperty( - value = "Whether the query has finished." + @Schema(description = "Whether the query has finished." ) public Boolean isFinished() { return finished; @@ -132,8 +126,7 @@ public void setFinished(Boolean finished) { /** * @return provenance request */ - @ApiModelProperty( - value = "The provenance request." + @Schema(description = "The provenance request." ) public ProvenanceRequestDTO getRequest() { return request; @@ -146,8 +139,7 @@ public void setRequest(ProvenanceRequestDTO request) { /** * @return results of this query */ - @ApiModelProperty( - value = "The provenance results." + @Schema(description = "The provenance results." ) public ProvenanceResultsDTO getResults() { return results; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceEventDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceEventDTO.java index 8afc9450da73a..46c4f5be6adea 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceEventDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceEventDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -85,8 +85,7 @@ public class ProvenanceEventDTO { /** * @return event uuid */ - @ApiModelProperty( - value = "The event uuid." + @Schema(description = "The event uuid." ) public String getId() { return id; @@ -99,8 +98,7 @@ public void setId(String id) { /** * @return event id */ - @ApiModelProperty( - value = "The event id. This is a one up number thats unique per node." + @Schema(description = "The event id. This is a one up number thats unique per node." ) public Long getEventId() { return eventId; @@ -114,9 +112,8 @@ public void setEventId(Long eventId) { * @return time the event occurred */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp of the event.", - dataType = "string" + @Schema(description = "The timestamp of the event.", + type = "string" ) public Date getEventTime() { return eventTime; @@ -129,8 +126,7 @@ public void setEventTime(Date eventTime) { /** * @return UUID of the FlowFile for this event */ - @ApiModelProperty( - value = "The uuid of the flowfile for the event." + @Schema(description = "The uuid of the flowfile for the event." ) public String getFlowFileUuid() { return flowFileUuid; @@ -143,8 +139,7 @@ public void setFlowFileUuid(String flowFileUuid) { /** * @return size of the FlowFile for this event */ - @ApiModelProperty( - value = "The size of the flowfile for the event." + @Schema(description = "The size of the flowfile for the event." ) public String getFileSize() { return fileSize; @@ -157,8 +152,7 @@ public void setFileSize(String fileSize) { /** * @return size of the FlowFile in bytes for this event */ - @ApiModelProperty( - value = "The size of the flowfile in bytes for the event." + @Schema(description = "The size of the flowfile in bytes for the event." ) public Long getFileSizeBytes() { return fileSizeBytes; @@ -171,8 +165,7 @@ public void setFileSizeBytes(Long fileSizeBytes) { /** * @return type of this event */ - @ApiModelProperty( - value = "The type of the event." + @Schema(description = "The type of the event." ) public String getEventType() { return eventType; @@ -185,8 +178,7 @@ public void setEventType(String eventType) { /** * @return attributes for the FlowFile for this event */ - @ApiModelProperty( - value = "The attributes of the flowfile for the event." + @Schema(description = "The attributes of the flowfile for the event." ) public Collection getAttributes() { return attributes; @@ -199,8 +191,7 @@ public void setAttributes(Collection attributes) { /** * @return id of the group that this component resides in. If the component is no longer in the flow, the group id will not be set */ - @ApiModelProperty( - value = "The id of the group that the component resides in. If the component is no longer in the flow, the group id will not be set." + @Schema(description = "The id of the group that the component resides in. If the component is no longer in the flow, the group id will not be set." ) public String getGroupId() { return groupId; @@ -213,8 +204,7 @@ public void setGroupId(String groupId) { /** * @return id of the component that generated this event */ - @ApiModelProperty( - value = "The id of the component that generated the event." + @Schema(description = "The id of the component that generated the event." ) public String getComponentId() { return componentId; @@ -227,8 +217,7 @@ public void setComponentId(String componentId) { /** * @return name of the component that generated this event */ - @ApiModelProperty( - value = "The name of the component that generated the event." + @Schema(description = "The name of the component that generated the event." ) public String getComponentName() { return componentName; @@ -241,8 +230,7 @@ public void setComponentName(String componentName) { /** * @return type of the component that generated this event */ - @ApiModelProperty( - value = "The type of the component that generated the event." + @Schema(description = "The type of the component that generated the event." ) public String getComponentType() { return componentType; @@ -255,8 +243,7 @@ public void setComponentType(String componentType) { /** * @return source/destination system URI if the event was a RECEIVE/SEND */ - @ApiModelProperty( - value = "The source/destination system uri if the event was a RECEIVE/SEND." + @Schema(description = "The source/destination system uri if the event was a RECEIVE/SEND." ) public String getTransitUri() { return transitUri; @@ -269,8 +256,7 @@ public void setTransitUri(String transitUri) { /** * @return alternate identifier URI for the FlowFile for this event */ - @ApiModelProperty( - value = "The alternate identifier uri for the fileflow for the event." + @Schema(description = "The alternate identifier uri for the fileflow for the event." ) public String getAlternateIdentifierUri() { return alternateIdentifierUri; @@ -283,8 +269,7 @@ public void setAlternateIdentifierUri(String alternateIdentifierUri) { /** * @return identifier of the node where this event originated */ - @ApiModelProperty( - value = "The identifier for the node where the event originated." + @Schema(description = "The identifier for the node where the event originated." ) public String getClusterNodeId() { return clusterNodeId; @@ -297,8 +282,7 @@ public void setClusterNodeId(String clusterNodeId) { /** * @return label to use to show which node this event originated from */ - @ApiModelProperty( - value = "The label for the node where the event originated." + @Schema(description = "The label for the node where the event originated." ) public String getClusterNodeAddress() { return clusterNodeAddress; @@ -311,8 +295,7 @@ public void setClusterNodeAddress(String clusterNodeAddress) { /** * @return parent uuids for this event */ - @ApiModelProperty( - value = "The parent uuids for the event." + @Schema(description = "The parent uuids for the event." ) public List getParentUuids() { return parentUuids; @@ -325,8 +308,7 @@ public void setParentUuids(List parentUuids) { /** * @return child uuids for this event */ - @ApiModelProperty( - value = "The child uuids for the event." + @Schema(description = "The child uuids for the event." ) public List getChildUuids() { return childUuids; @@ -339,8 +321,7 @@ public void setChildUuids(List childUuids) { /** * @return duration of the event, in milliseconds */ - @ApiModelProperty( - value = "The event duration in milliseconds." + @Schema(description = "The event duration in milliseconds." ) public Long getEventDuration() { return eventDuration; @@ -353,8 +334,7 @@ public void setEventDuration(Long eventDuration) { /** * @return duration since the lineage began, in milliseconds */ - @ApiModelProperty( - value = "The duration since the lineage began, in milliseconds." + @Schema(description = "The duration since the lineage began, in milliseconds." ) public Long getLineageDuration() { return lineageDuration; @@ -367,8 +347,7 @@ public void setLineageDuration(Long lineageDuration) { /** * @return source system FlowFile id */ - @ApiModelProperty( - value = "The source system flowfile id." + @Schema(description = "The source system flowfile id." ) public String getSourceSystemFlowFileId() { return sourceSystemFlowFileId; @@ -381,8 +360,7 @@ public void setSourceSystemFlowFileId(String sourceSystemFlowFileId) { /** * @return If this represents a route event, this is the relationship to which the flowfile was routed */ - @ApiModelProperty( - value = "The relationship to which the flowfile was routed if the event is of type ROUTE." + @Schema(description = "The relationship to which the flowfile was routed if the event is of type ROUTE." ) public String getRelationship() { return relationship; @@ -395,8 +373,7 @@ public void setRelationship(String relationship) { /** * @return event details */ - @ApiModelProperty( - value = "The event details." + @Schema(description = "The event details." ) public String getDetails() { return details; @@ -409,8 +386,7 @@ public void setDetails(String details) { /** * @return whether or not the input and output content claim is the same */ - @ApiModelProperty( - value = "Whether the input and output content claim is the same." + @Schema(description = "Whether the input and output content claim is the same." ) public Boolean getContentEqual() { return contentEqual; @@ -423,8 +399,7 @@ public void setContentEqual(Boolean contentEqual) { /** * @return whether or not the output content is still available */ - @ApiModelProperty( - value = "Whether the output content is still available." + @Schema(description = "Whether the output content is still available." ) public Boolean getOutputContentAvailable() { return outputContentAvailable; @@ -437,8 +412,7 @@ public void setOutputContentAvailable(Boolean outputContentAvailable) { /** * @return the Section in which the output Content Claim lives, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The section in which the output content claim lives." + @Schema(description = "The section in which the output content claim lives." ) public String getOutputContentClaimSection() { return outputContentClaimSection; @@ -451,8 +425,7 @@ public void setOutputContentClaimSection(String contentClaimSection) { /** * @return the Container in which the output Content Claim lives, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The container in which the output content claim lives." + @Schema(description = "The container in which the output content claim lives." ) public String getOutputContentClaimContainer() { return outputContentClaimContainer; @@ -465,8 +438,7 @@ public void setOutputContentClaimContainer(String outputContentClaimContainer) { /** * @return the Identifier of the output Content Claim, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The identifier of the output content claim." + @Schema(description = "The identifier of the output content claim." ) public String getOutputContentClaimIdentifier() { return outputContentClaimIdentifier; @@ -479,8 +451,7 @@ public void setOutputContentClaimIdentifier(String outputContentClaimIdentifier) /** * @return the offset into the the output Content Claim where the FlowFile's content begins, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The offset into the output content claim where the flowfiles content begins." + @Schema(description = "The offset into the output content claim where the flowfiles content begins." ) public Long getOutputContentClaimOffset() { return outputContentClaimOffset; @@ -493,8 +464,7 @@ public void setOutputContentClaimOffset(Long outputContentClaimOffset) { /** * @return the formatted file size of the input content claim */ - @ApiModelProperty( - value = "The file size of the output content claim formatted." + @Schema(description = "The file size of the output content claim formatted." ) public String getOutputContentClaimFileSize() { return outputContentClaimFileSize; @@ -507,8 +477,7 @@ public void setOutputContentClaimFileSize(String outputContentClaimFileSize) { /** * @return the number of bytes of the input content claim */ - @ApiModelProperty( - value = "The file size of the output content claim in bytes." + @Schema(description = "The file size of the output content claim in bytes." ) public Long getOutputContentClaimFileSizeBytes() { return outputContentClaimFileSizeBytes; @@ -521,8 +490,7 @@ public void setOutputContentClaimFileSizeBytes(Long outputContentClaimFileSizeBy /** * @return whether or not the input content is still available */ - @ApiModelProperty( - value = "Whether the input content is still available." + @Schema(description = "Whether the input content is still available." ) public Boolean getInputContentAvailable() { return inputContentAvailable; @@ -535,8 +503,7 @@ public void setInputContentAvailable(Boolean inputContentAvailable) { /** * @return the Section in which the input Content Claim lives, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The section in which the input content claim lives." + @Schema(description = "The section in which the input content claim lives." ) public String getInputContentClaimSection() { return inputContentClaimSection; @@ -549,8 +516,7 @@ public void setInputContentClaimSection(String inputContentClaimSection) { /** * @return the Container in which the input Content Claim lives, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The container in which the input content claim lives." + @Schema(description = "The container in which the input content claim lives." ) public String getInputContentClaimContainer() { return inputContentClaimContainer; @@ -563,8 +529,7 @@ public void setInputContentClaimContainer(String inputContentClaimContainer) { /** * @return the Identifier of the input Content Claim, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The identifier of the input content claim." + @Schema(description = "The identifier of the input content claim." ) public String getInputContentClaimIdentifier() { return inputContentClaimIdentifier; @@ -577,8 +542,7 @@ public void setInputContentClaimIdentifier(String inputContentClaimIdentifier) { /** * @return the offset into the the input Content Claim where the FlowFile's content begins, or null if no Content Claim exists */ - @ApiModelProperty( - value = "The offset into the input content claim where the flowfiles content begins." + @Schema(description = "The offset into the input content claim where the flowfiles content begins." ) public Long getInputContentClaimOffset() { return inputContentClaimOffset; @@ -591,8 +555,7 @@ public void setInputContentClaimOffset(Long inputContentClaimOffset) { /** * @return the formatted file size of the input content claim */ - @ApiModelProperty( - value = "The file size of the input content claim formatted." + @Schema(description = "The file size of the input content claim formatted." ) public String getInputContentClaimFileSize() { return inputContentClaimFileSize; @@ -605,8 +568,7 @@ public void setInputContentClaimFileSize(String inputContentClaimFileSize) { /** * @return the number of bytes of the input content claim */ - @ApiModelProperty( - value = "The file size of the intput content claim in bytes." + @Schema(description = "The file size of the intput content claim in bytes." ) public Long getInputContentClaimFileSizeBytes() { return inputContentClaimFileSizeBytes; @@ -619,8 +581,7 @@ public void setInputContentClaimFileSizeBytes(Long inputContentClaimFileSizeByte /** * @return whether or not replay is available */ - @ApiModelProperty( - value = "Whether or not replay is available." + @Schema(description = "Whether or not replay is available." ) public Boolean getReplayAvailable() { return replayAvailable; @@ -633,8 +594,7 @@ public void setReplayAvailable(Boolean replayAvailable) { /** * @return the explanation as to why replay is unavailable */ - @ApiModelProperty( - value = "Explanation as to why replay is unavailable." + @Schema(description = "Explanation as to why replay is unavailable." ) public String getReplayExplanation() { return replayExplanation; @@ -648,8 +608,7 @@ public void setReplayExplanation(String replayExplanation) { * @return identifier of the FlowFile Queue / Connection from which the FlowFile was pulled to generate this event, or null if either the queue is unknown or the FlowFile was created * by this event */ - @ApiModelProperty( - value = "The identifier of the queue/connection from which the flowfile was pulled to genereate this event. May be null if the queue/connection is unknown or the " + @Schema(description = "The identifier of the queue/connection from which the flowfile was pulled to genereate this event. May be null if the queue/connection is unknown or the " + "flowfile was generated from this event." ) public String getSourceConnectionIdentifier() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceOptionsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceOptionsDTO.java index 10d51df3be355..a22564f1bfd81 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceOptionsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceOptionsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -32,8 +32,7 @@ public class ProvenanceOptionsDTO { /** * @return available searchable fields for this NiFi instance */ - @ApiModelProperty( - value = "The available searchable field for the NiFi." + @Schema(description = "The available searchable field for the NiFi." ) public List getSearchableFields() { return searchableFields; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceRequestDTO.java index d51750a93a00b..c8a4e9053dba9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -44,8 +44,7 @@ public class ProvenanceRequestDTO { /** * @return the search terms to use for this search */ - @ApiModelProperty( - value = "The search terms used to perform the search." + @Schema(description = "The search terms used to perform the search." ) public Map getSearchTerms() { return searchTerms; @@ -59,9 +58,8 @@ public void setSearchTerms(final Map searchTer * @return earliest event time to include in the query */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The earliest event time to include in the query.", - dataType = "string" + @Schema(description = "The earliest event time to include in the query.", + type = "string" ) public Date getStartDate() { return startDate; @@ -75,9 +73,8 @@ public void setStartDate(Date startDate) { * @return latest event time to include in the query */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The latest event time to include in the query.", - dataType = "string" + @Schema(description = "The latest event time to include in the query.", + type = "string" ) public Date getEndDate() { return endDate; @@ -90,8 +87,7 @@ public void setEndDate(Date endDate) { /** * @return minimum file size to include in the query */ - @ApiModelProperty( - value = "The minimum file size to include in the query." + @Schema(description = "The minimum file size to include in the query." ) public String getMinimumFileSize() { return minimumFileSize; @@ -104,8 +100,7 @@ public void setMinimumFileSize(String minimumFileSize) { /** * @return maximum file size to include in the query */ - @ApiModelProperty( - value = "The maximum file size to include in the query." + @Schema(description = "The maximum file size to include in the query." ) public String getMaximumFileSize() { return maximumFileSize; @@ -118,8 +113,7 @@ public void setMaximumFileSize(String maximumFileSize) { /** * @return number of max results */ - @ApiModelProperty( - value = "The maximum number of results to include." + @Schema(description = "The maximum number of results to include." ) public Integer getMaxResults() { return maxResults; @@ -132,8 +126,7 @@ public void setMaxResults(Integer maxResults) { /** * @return id of the node in the cluster where this provenance originated */ - @ApiModelProperty( - value = "The id of the node in the cluster where this provenance originated." + @Schema(description = "The id of the node in the cluster where this provenance originated." ) public String getClusterNodeId() { return clusterNodeId; @@ -147,8 +140,7 @@ public void setClusterNodeId(String clusterNodeId) { * @return whether or not incremental results are returned. If false, provenance events * are only returned once the query completes. This property is true by default. */ - @ApiModelProperty( - value = "Whether or not incremental results are returned. If false, provenance events" + @Schema(description = "Whether or not incremental results are returned. If false, provenance events" + " are only returned once the query completes. This property is true by default." ) public Boolean getIncrementalResults() { @@ -162,8 +154,7 @@ public void setIncrementalResults(Boolean incrementalResults) { /** * @return whether or not to summarize provenance events returned. This property is false by default. */ - @ApiModelProperty( - value = "Whether or not to summarize provenance events returned. This property is false by default." + @Schema(description = "Whether or not to summarize provenance events returned. This property is false by default." ) public Boolean getSummarize() { return summarize; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceResultsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceResultsDTO.java index 7c036b3f55ed4..797745ef78d68 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceResultsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceResultsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; import org.apache.nifi.web.api.dto.util.TimeAdapter; @@ -44,8 +44,7 @@ public class ProvenanceResultsDTO { /** * @return error messages */ - @ApiModelProperty( - value = "Any errors that occurred while performing the provenance request." + @Schema(description = "Any errors that occurred while performing the provenance request." ) public Set getErrors() { return errors; @@ -58,8 +57,7 @@ public void setErrors(Set errors) { /** * @return provenance events that matched the search criteria */ - @ApiModelProperty( - value = "The provenance events that matched the search criteria." + @Schema(description = "The provenance events that matched the search criteria." ) public List getProvenanceEvents() { return provenanceEvents; @@ -72,8 +70,7 @@ public void setProvenanceEvents(List provenanceEvents) { /** * @return total number of results formatted */ - @ApiModelProperty( - value = "The total number of results formatted." + @Schema(description = "The total number of results formatted." ) public String getTotal() { return total; @@ -86,8 +83,7 @@ public void setTotal(String total) { /** * @return total number of results */ - @ApiModelProperty( - value = "The total number of results." + @Schema(description = "The total number of results." ) public Long getTotalCount() { return totalCount; @@ -101,9 +97,8 @@ public void setTotalCount(Long totalCount) { * @return when the search was performed */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "Then the search was performed.", - dataType = "string" + @Schema(description = "Then the search was performed.", + type = "string" ) public Date getGenerated() { return generated; @@ -117,9 +112,8 @@ public void setGenerated(Date generated) { * @return oldest event available in the provenance repository */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The oldest event available in the provenance repository.", - dataType = "string" + @Schema(description = "The oldest event available in the provenance repository.", + type = "string" ) public Date getOldestEvent() { return oldestEvent; @@ -132,8 +126,7 @@ public void setOldestEvent(Date oldestEvent) { /** * @return time offset on the server that's used for event time */ - @ApiModelProperty( - value = "The time offset of the server that's used for event time." + @Schema(description = "The time offset of the server that's used for event time." ) public Integer getTimeOffset() { return timeOffset; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchValueDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchValueDTO.java index 69585385eac61..5537c670a4c8a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchValueDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchValueDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,8 +32,7 @@ public class ProvenanceSearchValueDTO { /** * @return the search value */ - @ApiModelProperty( - value = "The search value." + @Schema(description = "The search value." ) public String getValue() { return value; @@ -46,8 +45,7 @@ public void setValue(String value) { /** * @return whether inverse of search value should be searched or not */ - @ApiModelProperty( - value = "Query for all except for search value." + @Schema(description = "Query for all except for search value." ) public Boolean getInverse() { return inverse; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchableFieldDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchableFieldDTO.java index b3095f63379ec..5a491380b210b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchableFieldDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/ProvenanceSearchableFieldDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -34,8 +34,7 @@ public class ProvenanceSearchableFieldDTO { /** * @return id of this searchable field */ - @ApiModelProperty( - value = "The id of the searchable field." + @Schema(description = "The id of the searchable field." ) public String getId() { return id; @@ -48,8 +47,7 @@ public void setId(String id) { /** * @return the field */ - @ApiModelProperty( - value = "The searchable field." + @Schema(description = "The searchable field." ) public String getField() { return field; @@ -62,8 +60,7 @@ public void setField(String field) { /** * @return label for this field */ - @ApiModelProperty( - value = "The label for the searchable field." + @Schema(description = "The label for the searchable field." ) public String getLabel() { return label; @@ -76,8 +73,7 @@ public void setLabel(String label) { /** * @return type of this field */ - @ApiModelProperty( - value = "The type of the searchable field." + @Schema(description = "The type of the searchable field." ) public String getType() { return type; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java index beeb6538c0131..b4d46b1492876 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance.lineage; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -43,8 +43,7 @@ public class LineageDTO { /** * @return id of this lineage */ - @ApiModelProperty( - value = "The id of this lineage query." + @Schema(description = "The id of this lineage query." ) public String getId() { return id; @@ -57,8 +56,7 @@ public void setId(String id) { /** * @return uri for this lineage */ - @ApiModelProperty( - value = "The URI for this lineage query for later retrieval and deletion." + @Schema(description = "The URI for this lineage query for later retrieval and deletion." ) public String getUri() { return uri; @@ -72,9 +70,8 @@ public void setUri(String uri) { * @return submission time for this lineage */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "When the lineage query was submitted.", - dataType = "string" + @Schema(description = "When the lineage query was submitted.", + type = "string" ) public Date getSubmissionTime() { return submissionTime; @@ -88,9 +85,8 @@ public void setSubmissionTime(Date submissionTime) { * @return expiration of this lineage */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "When the lineage query will expire.", - dataType = "string" + @Schema(description = "When the lineage query will expire.", + type = "string" ) public Date getExpiration() { return expiration; @@ -103,8 +99,7 @@ public void setExpiration(Date expiration) { /** * @return percent completed for this result */ - @ApiModelProperty( - value = "The percent complete for the lineage query." + @Schema(description = "The percent complete for the lineage query." ) public Integer getPercentCompleted() { return percentCompleted; @@ -117,8 +112,7 @@ public void setPercentCompleted(Integer percentCompleted) { /** * @return whether or not the request is finished running */ - @ApiModelProperty( - value = "Whether the lineage query has finished." + @Schema(description = "Whether the lineage query has finished." ) public Boolean getFinished() { return finished; @@ -131,8 +125,7 @@ public void setFinished(Boolean finished) { /** * @return the lineage request */ - @ApiModelProperty( - value = "The initial lineage result." + @Schema(description = "The initial lineage result." ) public LineageRequestDTO getRequest() { return request; @@ -145,8 +138,7 @@ public void setRequest(LineageRequestDTO request) { /** * @return the results of this lineage */ - @ApiModelProperty( - value = "The results of the lineage query." + @Schema(description = "The results of the lineage query." ) public LineageResultsDTO getResults() { return results; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java index 7939c02b70fb5..745e8ac017cfd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageRequestDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance.lineage; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlEnum; import jakarta.xml.bind.annotation.XmlType; @@ -47,9 +47,11 @@ public enum LineageRequestType { /** * @return event id that was used to generate this lineage */ - @ApiModelProperty( - value = "The event id that was used to generate this lineage, if applicable. The event id is allowed for any type of lineageRequestType. If the lineageRequestType is FLOWFILE and the " - + "flowfile uuid is also included in the request, the event id will be ignored." + @Schema(description = """ + The event id that was used to generate this lineage, if applicable. + The event id is allowed for any type of lineageRequestType. + If the lineageRequestType is FLOWFILE and the flowfile uuid is also included in the request, the event id will be ignored. + """ ) public Long getEventId() { return eventId; @@ -63,8 +65,7 @@ public void setEventId(Long eventId) { * @return type of lineage request. Either 'PARENTS', 'CHILDREN', or 'FLOWFILE'. PARENTS will return the lineage for the flowfiles that are parents of the specified event. CHILDREN will return the * lineage of for the flowfiles that are children of the specified event. FLOWFILE will return the lineage for the specified flowfile. */ - @ApiModelProperty( - value = "The type of lineage request. PARENTS will return the lineage for the flowfiles that are parents of the specified event. CHILDREN will return the lineage " + @Schema(description = "The type of lineage request. PARENTS will return the lineage for the flowfiles that are parents of the specified event. CHILDREN will return the lineage " + "for the flowfiles that are children of the specified event. FLOWFILE will return the lineage for the specified flowfile.", allowableValues = "PARENTS, CHILDREN, and FLOWFILE" ) @@ -79,7 +80,7 @@ public void setLineageRequestType(LineageRequestType lineageRequestType) { /** * @return id of the node in the cluster where this lineage originated */ - @ApiModelProperty(value = "The id of the node where this lineage originated if clustered.") + @Schema(description = "The id of the node where this lineage originated if clustered.") public String getClusterNodeId() { return clusterNodeId; } @@ -91,8 +92,7 @@ public void setClusterNodeId(String clusterNodeId) { /** * @return uuid that was used to generate this lineage */ - @ApiModelProperty( - value = "The flowfile uuid that was used to generate the lineage. The flowfile uuid is only allowed when the lineageRequestType is FLOWFILE and will take precedence over event id." + @Schema(description = "The flowfile uuid that was used to generate the lineage. The flowfile uuid is only allowed when the lineageRequestType is FLOWFILE and will take precedence over event id." ) public String getUuid() { return uuid; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageResultsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageResultsDTO.java index 5a658ee9954ff..2f9b43d734777 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageResultsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/LineageResultsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance.lineage; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -36,8 +36,7 @@ public class LineageResultsDTO { /** * @return any error messages */ - @ApiModelProperty( - value = "Any errors that occurred while generating the lineage." + @Schema(description = "Any errors that occurred while generating the lineage." ) public Set getErrors() { return errors; @@ -50,8 +49,7 @@ public void setErrors(Set errors) { /** * @return the nodes */ - @ApiModelProperty( - value = "The nodes in the lineage." + @Schema(description = "The nodes in the lineage." ) public List getNodes() { return nodes; @@ -64,8 +62,7 @@ public void setNodes(List nodes) { /** * @return the links */ - @ApiModelProperty( - value = "The links between the nodes in the lineage." + @Schema(description = "The links between the nodes in the lineage." ) public List getLinks() { return links; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceLinkDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceLinkDTO.java index 4a8f20a3e1b87..397dddbf38b93 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceLinkDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceLinkDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance.lineage; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -38,8 +38,7 @@ public class ProvenanceLinkDTO { /** * @return source node id */ - @ApiModelProperty( - value = "The source node id of the link." + @Schema(description = "The source node id of the link." ) public String getSourceId() { return sourceId; @@ -52,8 +51,7 @@ public void setSourceId(String sourceId) { /** * @return target node id */ - @ApiModelProperty( - value = "The target node id of the link." + @Schema(description = "The target node id of the link." ) public String getTargetId() { return targetId; @@ -66,8 +64,7 @@ public void setTargetId(String targetId) { /** * @return flowfile uuid that traversed this link */ - @ApiModelProperty( - value = "The flowfile uuid that traversed the link." + @Schema(description = "The flowfile uuid that traversed the link." ) public String getFlowFileUuid() { return flowFileUuid; @@ -81,9 +78,8 @@ public void setFlowFileUuid(String flowFileUuid) { * @return timestamp of this link (based on the destination) */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp of the link (based on the destination).", - dataType = "string" + @Schema(description = "The timestamp of the link (based on the destination).", + type = "string" ) public Date getTimestamp() { return timestamp; @@ -96,8 +92,7 @@ public void setTimestamp(Date timestamp) { /** * @return number of millis since epoch */ - @ApiModelProperty( - value = "The timestamp of this link in milliseconds." + @Schema(description = "The timestamp of this link in milliseconds." ) public Long getMillis() { return millis; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceNodeDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceNodeDTO.java index f294387b71a8e..1fedc0fb6d64d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceNodeDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/provenance/lineage/ProvenanceNodeDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.provenance.lineage; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimestampAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -43,8 +43,7 @@ public class ProvenanceNodeDTO { /** * @return id of the node */ - @ApiModelProperty( - value = "The id of the node." + @Schema(description = "The id of the node." ) public String getId() { return id; @@ -57,8 +56,7 @@ public void setId(String id) { /** * @return flowfile uuid for this provenance event */ - @ApiModelProperty( - value = "The uuid of the flowfile associated with the provenance event." + @Schema(description = "The uuid of the flowfile associated with the provenance event." ) public String getFlowFileUuid() { return flowFileUuid; @@ -71,8 +69,7 @@ public void setFlowFileUuid(String flowFileUuid) { /** * @return parent flowfile uuids for this provenance event */ - @ApiModelProperty( - value = "The uuid of the parent flowfiles of the provenance event." + @Schema(description = "The uuid of the parent flowfiles of the provenance event." ) public List getParentUuids() { return parentUuids; @@ -85,8 +82,7 @@ public void setParentUuids(List parentUuids) { /** * @return child flowfile uuids for this provenance event */ - @ApiModelProperty( - value = "The uuid of the childrent flowfiles of the provenance event." + @Schema(description = "The uuid of the childrent flowfiles of the provenance event." ) public List getChildUuids() { return childUuids; @@ -99,8 +95,7 @@ public void setChildUuids(List childUuids) { /** * @return node identifier that this event/flowfile originated from */ - @ApiModelProperty( - value = "The identifier of the node that this event/flowfile originated from." + @Schema(description = "The identifier of the node that this event/flowfile originated from." ) public String getClusterNodeIdentifier() { return clusterNodeIdentifier; @@ -113,8 +108,7 @@ public void setClusterNodeIdentifier(String clusterNodeIdentifier) { /** * @return type of node */ - @ApiModelProperty( - value = "The type of the node.", + @Schema(description = "The type of the node.", allowableValues = "FLOWFILE, EVENT" ) public String getType() { @@ -128,8 +122,7 @@ public void setType(String type) { /** * @return this is an event node, this is the type of event */ - @ApiModelProperty( - value = "If the type is EVENT, this is the type of event." + @Schema(description = "If the type is EVENT, this is the type of event." ) public String getEventType() { return eventType; @@ -143,9 +136,8 @@ public void setEventType(String eventType) { * @return timestamp of this node */ @XmlJavaTypeAdapter(TimestampAdapter.class) - @ApiModelProperty( - value = "The timestamp of the node formatted.", - dataType = "string" + @Schema(description = "The timestamp of the node formatted.", + type = "string" ) public Date getTimestamp() { return timestamp; @@ -158,8 +150,7 @@ public void setTimestamp(Date timestamp) { /** * @return number of millis since epoch */ - @ApiModelProperty( - value = "The timestamp of the node in milliseconds." + @Schema(description = "The timestamp of the node in milliseconds." ) public Long getMillis() { return millis; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/remote/PeerDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/remote/PeerDTO.java index b94c5090b3891..c8266dda11704 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/remote/PeerDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/remote/PeerDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.remote; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,8 +31,7 @@ public class PeerDTO { private boolean secure; private int flowFileCount; - @ApiModelProperty( - value = "The hostname of this peer." + @Schema(description = "The hostname of this peer." ) public String getHostname() { return hostname; @@ -42,8 +41,7 @@ public void setHostname(String hostname) { this.hostname = hostname; } - @ApiModelProperty( - value = "The port number of this peer." + @Schema(description = "The port number of this peer." ) public int getPort() { return port; @@ -53,8 +51,7 @@ public void setPort(int port) { this.port = port; } - @ApiModelProperty( - value = "Returns if this peer connection is secure." + @Schema(description = "Returns if this peer connection is secure." ) public boolean isSecure() { return secure; @@ -65,8 +62,7 @@ public void setSecure(boolean secure) { } - @ApiModelProperty( - value = "The number of flowFiles this peer holds." + @Schema(description = "The number of flowFiles this peer holds." ) public int getFlowFileCount() { return flowFileCount; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/ComponentSearchResultDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/ComponentSearchResultDTO.java index 138132bbad499..1597727fce89e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/ComponentSearchResultDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/ComponentSearchResultDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.search; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -37,8 +37,7 @@ public class ComponentSearchResultDTO { /** * @return id of the component that matched */ - @ApiModelProperty( - value = "The id of the component that matched the search." + @Schema(description = "The id of the component that matched the search." ) public String getId() { return id; @@ -51,8 +50,7 @@ public void setId(String id) { /** * @return group id of the component that matched */ - @ApiModelProperty( - value = "The group id of the component that matched the search." + @Schema(description = "The group id of the component that matched the search." ) public String getGroupId() { return groupId; @@ -65,8 +63,7 @@ public void setGroupId(String groupId) { /** * @return parent group of the component that matched */ - @ApiModelProperty( - value = "The parent group of the component that matched the search." + @Schema(description = "The parent group of the component that matched the search." ) public SearchResultGroupDTO getParentGroup() { return parentGroup; @@ -79,8 +76,7 @@ public void setParentGroup(final SearchResultGroupDTO parentGroup) { /** * @return the nearest versioned ancestor group of the component that matched */ - @ApiModelProperty( - value = "The nearest versioned ancestor group of the component that matched the search." + @Schema(description = "The nearest versioned ancestor group of the component that matched the search." ) public SearchResultGroupDTO getVersionedGroup() { return versionedGroup; @@ -93,8 +89,7 @@ public void setVersionedGroup(final SearchResultGroupDTO versionedGroup) { /** * @return name of the component that matched */ - @ApiModelProperty( - value = "The name of the component that matched the search." + @Schema(description = "The name of the component that matched the search." ) public String getName() { return name; @@ -107,8 +102,7 @@ public void setName(String name) { /** * @return What matched the search string for this component */ - @ApiModelProperty( - value = "What matched the search from the component." + @Schema(description = "What matched the search from the component." ) public List getMatches() { return matches; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/NodeSearchResultDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/NodeSearchResultDTO.java index 7f5a8860fd38f..bcc0d6eb60078 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/NodeSearchResultDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/NodeSearchResultDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.search; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,8 +32,7 @@ public class NodeSearchResultDTO { /** * @return id of the node that was matched */ - @ApiModelProperty( - value = "The id of the node that matched the search." + @Schema(description = "The id of the node that matched the search." ) public String getId() { return id; @@ -46,8 +45,7 @@ public void setId(String id) { /** * @return address of the node that was matched */ - @ApiModelProperty( - value = "The address of the node that matched the search." + @Schema(description = "The address of the node that matched the search." ) public String getAddress() { return address; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultGroupDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultGroupDTO.java index 02ce030102894..77de477a18a3d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultGroupDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultGroupDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.search; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,9 +31,8 @@ public class SearchResultGroupDTO { /** * @return id of this group */ - @ApiModelProperty( - value = "The id of the group.", - required = true + @Schema(description = "The id of the group.", + requiredMode = Schema.RequiredMode.REQUIRED ) public String getId() { return id; @@ -46,8 +45,7 @@ public void setId(final String id) { /** * @return name of this group */ - @ApiModelProperty( - value = "The name of the group." + @Schema(description = "The name of the group." ) public String getName() { return name; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultsDTO.java index 7e43fd902e879..3934f328e5d68 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/search/SearchResultsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.search; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.ArrayList; @@ -44,8 +44,7 @@ public class SearchResultsDTO { /** * @return The processors that matched the search */ - @ApiModelProperty( - value = "The processors that matched the search." + @Schema(description = "The processors that matched the search." ) public List getProcessorResults() { return processorResults; @@ -58,8 +57,7 @@ public void setProcessorResults(List processorResults) /** * @return connections that matched the search */ - @ApiModelProperty( - value = "The connections that matched the search." + @Schema(description = "The connections that matched the search." ) public List getConnectionResults() { return connectionResults; @@ -72,8 +70,7 @@ public void setConnectionResults(List connectionResult /** * @return process group that matched the search */ - @ApiModelProperty( - value = "The process groups that matched the search." + @Schema(description = "The process groups that matched the search." ) public List getProcessGroupResults() { return processGroupResults; @@ -86,8 +83,7 @@ public void setProcessGroupResults(List processGroupRe /** * @return input ports that matched the search */ - @ApiModelProperty( - value = "The input ports that matched the search." + @Schema(description = "The input ports that matched the search." ) public List getInputPortResults() { return inputPortResults; @@ -96,8 +92,7 @@ public List getInputPortResults() { /** * @return output ports that matched the search */ - @ApiModelProperty( - value = "The output ports that matched the search." + @Schema(description = "The output ports that matched the search." ) public List getOutputPortResults() { return outputPortResults; @@ -114,8 +109,7 @@ public void setOutputPortResults(List outputPortResult /** * @return remote process groups that matched the search */ - @ApiModelProperty( - value = "The remote process groups that matched the search." + @Schema(description = "The remote process groups that matched the search." ) public List getRemoteProcessGroupResults() { return remoteProcessGroupResults; @@ -128,8 +122,7 @@ public void setRemoteProcessGroupResults(List remotePr /** * @return funnels that matched the search */ - @ApiModelProperty( - value = "The funnels that matched the search." + @Schema(description = "The funnels that matched the search." ) public List getFunnelResults() { return funnelResults; @@ -142,8 +135,7 @@ public void setFunnelResults(List funnelResults) { /** * @return labels that matched the search */ - @ApiModelProperty( - value = "The labels that matched the search." + @Schema(description = "The labels that matched the search." ) public List getLabelResults() { return labelResults; @@ -156,8 +148,7 @@ public void setLabelResults(List labelResults) { /** * @return the controller service nodes that matched the search */ - @ApiModelProperty( - value = "The controller service nodes that matched the search" + @Schema(description = "The controller service nodes that matched the search" ) public List getControllerServiceNodeResults() { return controllerServiceNodeResults; @@ -170,8 +161,7 @@ public void setControllerServiceNodeResults(List contr /** * @return the parameter provider nodes that matched the search */ - @ApiModelProperty( - value = "The parameter provider nodes that matched the search" + @Schema(description = "The parameter provider nodes that matched the search" ) public List getParameterProviderNodeResults() { return parameterProviderNodeResults; @@ -184,8 +174,7 @@ public void setParameterProviderNodeResults(List param /** * @return parameter contexts that matched the search. */ - @ApiModelProperty( - value = "The parameter contexts that matched the search." + @Schema(description = "The parameter contexts that matched the search." ) public List getParameterContextResults() { return parameterContextResults; @@ -198,8 +187,7 @@ public void setParameterContextResults(List parameterC /** * @return parameters that matched the search. */ - @ApiModelProperty( - value = "The parameters that matched the search." + @Schema(description = "The parameters that matched the search." ) public List getParameterResults() { return parameterResults; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ClusterStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ClusterStatusDTO.java index 7792f7fed5ceb..143976e7b0b24 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ClusterStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ClusterStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Collection; @@ -32,8 +32,7 @@ public class ClusterStatusDTO { /** * @return collection of the node status DTOs */ - @ApiModelProperty( - value = "The status of each node." + @Schema(description = "The status of each node." ) public Collection getNodeStatus() { return nodeStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java index 175bc3e9256ef..64a082222482b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ComponentStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -39,11 +39,11 @@ public class ComponentStatusDTO{ private Integer activeThreadCount; /** - * Sub-classes should override this method to provide API documentation using ApiModelProperty annotation with allowable values. + * Sub-classes should override this method to provide API documentation using @Schema annotation with allowable values. * @return the run status of the component */ - @ApiModelProperty(value = "The run status of this component", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "The run status of this component", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = "ENABLED, ENABLING, DISABLED, DISABLING") public String getRunStatus() { return runStatus; @@ -53,9 +53,9 @@ public void setRunStatus(String runStatus) { this.runStatus = runStatus; } - @ApiModelProperty(value = "Indicates whether the component is valid, invalid, or still in the process of validating" + + @Schema(description = "Indicates whether the component is valid, invalid, or still in the process of validating" + " (i.e., it is unknown whether or not the component is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = VALID + ", " + INVALID + ", " + VALIDATING) public String getValidationStatus() { return validationStatus; @@ -68,8 +68,7 @@ public void setValidationStatus(String validationStatus) { /** * @return number of active threads for this component */ - @ApiModelProperty( - value = "The number of active threads for the component." + @Schema(description = "The number of active threads for the component." ) public Integer getActiveThreadCount() { return activeThreadCount; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsDTO.java index 05e6148b3b4e1..de98da796c0ff 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -35,7 +35,7 @@ public class ConnectionStatisticsDTO implements Cloneable { private List nodeSnapshots; - @ApiModelProperty("The ID of the connection") + @Schema(description = "The ID of the connection") public String getId() { return id; } @@ -44,7 +44,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The status snapshot that represents the aggregate stats of the cluster") + @Schema(description = "The status snapshot that represents the aggregate stats of the cluster") public ConnectionStatisticsSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; } @@ -53,7 +53,7 @@ public void setAggregateSnapshot(ConnectionStatisticsSnapshotDTO aggregateSnapsh this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A list of status snapshots for each node") + @Schema(description = "A list of status snapshots for each node") public List getNodeSnapshots() { return nodeSnapshots; } @@ -63,9 +63,8 @@ public void setNodeSnapshots(List nodeSnaps } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The timestamp of when the stats were last refreshed", - dataType = "string" + @Schema(description = "The timestamp of when the stats were last refreshed", + type = "string" ) public Date getStatsLastRefreshed() { return statsLastRefreshed; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsSnapshotDTO.java index 0ec7606f18a30..99d7b0d46a062 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatisticsSnapshotDTO.java @@ -18,7 +18,7 @@ import jakarta.xml.bind.annotation.XmlType; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; /** * DTO for serializing the statistics of a connection. @@ -40,7 +40,7 @@ public class ConnectionStatisticsSnapshotDTO implements Cloneable { /** * @return The connection id */ - @ApiModelProperty("The id of the connection.") + @Schema(description = "The id of the connection.") public String getId() { return id; } @@ -49,7 +49,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The predicted number of milliseconds before the connection will have backpressure applied, based on the queued count.") + @Schema(description = "The predicted number of milliseconds before the connection will have backpressure applied, based on the queued count.") public Long getPredictedMillisUntilCountBackpressure() { return predictedMillisUntilCountBackpressure; } @@ -58,7 +58,7 @@ public void setPredictedMillisUntilCountBackpressure(Long predictedMillisUntilCo this.predictedMillisUntilCountBackpressure = predictedMillisUntilCountBackpressure; } - @ApiModelProperty("The predicted number of milliseconds before the connection will have backpressure applied, based on the total number of bytes in the queue.") + @Schema(description = "The predicted number of milliseconds before the connection will have backpressure applied, based on the total number of bytes in the queue.") public Long getPredictedMillisUntilBytesBackpressure() { return predictedMillisUntilBytesBackpressure; } @@ -67,7 +67,7 @@ public void setPredictedMillisUntilBytesBackpressure(Long predictedMillisUntilBy this.predictedMillisUntilBytesBackpressure = predictedMillisUntilBytesBackpressure; } - @ApiModelProperty("The predicted number of queued objects at the next configured interval.") + @Schema(description = "The predicted number of queued objects at the next configured interval.") public Integer getPredictedCountAtNextInterval() { return predictedCountAtNextInterval; } @@ -76,7 +76,7 @@ public void setPredictedCountAtNextInterval(Integer predictedCountAtNextInterval this.predictedCountAtNextInterval = predictedCountAtNextInterval; } - @ApiModelProperty("The predicted total number of bytes in the queue at the next configured interval.") + @Schema(description = "The predicted total number of bytes in the queue at the next configured interval.") public Long getPredictedBytesAtNextInterval() { return predictedBytesAtNextInterval; } @@ -85,7 +85,7 @@ public void setPredictedBytesAtNextInterval(Long predictedBytesAtNextInterval) { this.predictedBytesAtNextInterval = predictedBytesAtNextInterval; } - @ApiModelProperty("The predicted percentage of queued objects at the next configured interval.") + @Schema(description = "The predicted percentage of queued objects at the next configured interval.") public Integer getPredictedPercentCount() { return predictedPercentCount; } @@ -94,7 +94,7 @@ public void setPredictedPercentCount(Integer predictedPercentCount) { this.predictedPercentCount = predictedPercentCount; } - @ApiModelProperty("The predicted percentage of bytes in the queue against current threshold at the next configured interval.") + @Schema(description = "The predicted percentage of bytes in the queue against current threshold at the next configured interval.") public Integer getPredictedPercentBytes() { return predictedPercentBytes; } @@ -103,7 +103,7 @@ public void setPredictedPercentBytes(Integer predictedPercentBytes) { this.predictedPercentBytes = predictedPercentBytes; } - @ApiModelProperty("The prediction interval in seconds") + @Schema(description = "The prediction interval in seconds") public Long getPredictionIntervalMillis() { return predictionIntervalMillis; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusDTO.java index 2b96b8c287dbc..6989977d3cef0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -42,7 +42,7 @@ public class ConnectionStatusDTO implements Cloneable { private List nodeSnapshots; - @ApiModelProperty("The ID of the connection") + @Schema(description = "The ID of the connection") public String getId() { return id; } @@ -51,7 +51,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The ID of the Process Group that the connection belongs to") + @Schema(description = "The ID of the Process Group that the connection belongs to") public String getGroupId() { return groupId; } @@ -60,7 +60,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty("The name of the connection") + @Schema(description = "The name of the connection") public String getName() { return name; } @@ -69,7 +69,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The ID of the source component") + @Schema(description = "The ID of the source component") public String getSourceId() { return sourceId; } @@ -78,7 +78,7 @@ public void setSourceId(String sourceId) { this.sourceId = sourceId; } - @ApiModelProperty("The name of the source component") + @Schema(description = "The name of the source component") public String getSourceName() { return sourceName; } @@ -87,7 +87,7 @@ public void setSourceName(String sourceName) { this.sourceName = sourceName; } - @ApiModelProperty("The ID of the destination component") + @Schema(description = "The ID of the destination component") public String getDestinationId() { return destinationId; } @@ -96,7 +96,7 @@ public void setDestinationId(String destinationId) { this.destinationId = destinationId; } - @ApiModelProperty("The name of the destination component") + @Schema(description = "The name of the destination component") public String getDestinationName() { return destinationName; } @@ -105,7 +105,7 @@ public void setDestinationName(String destinationName) { this.destinationName = destinationName; } - @ApiModelProperty("The status snapshot that represents the aggregate stats of the cluster") + @Schema(description = "The status snapshot that represents the aggregate stats of the cluster") public ConnectionStatusSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; } @@ -114,7 +114,7 @@ public void setAggregateSnapshot(ConnectionStatusSnapshotDTO aggregateSnapshot) this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A list of status snapshots for each node") + @Schema(description = "A list of status snapshots for each node") public List getNodeSnapshots() { return nodeSnapshots; } @@ -124,9 +124,8 @@ public void setNodeSnapshots(List nodeSnapshots } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The timestamp of when the stats were last refreshed", - dataType = "string" + @Schema(description = "The timestamp of when the stats were last refreshed", + type = "string" ) public Date getStatsLastRefreshed() { return statsLastRefreshed; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusPredictionsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusPredictionsSnapshotDTO.java index aa3e9fbdd53a5..70fc4f115d77c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusPredictionsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusPredictionsSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -33,7 +33,7 @@ public class ConnectionStatusPredictionsSnapshotDTO implements Cloneable { private Integer predictedPercentCount; private Integer predictedPercentBytes; - @ApiModelProperty("The predicted number of milliseconds before the connection will have backpressure applied, based on the queued count.") + @Schema(description = "The predicted number of milliseconds before the connection will have backpressure applied, based on the queued count.") public Long getPredictedMillisUntilCountBackpressure() { return predictedMillisUntilCountBackpressure; } @@ -42,7 +42,7 @@ public void setPredictedMillisUntilCountBackpressure(Long predictedMillisUntilCo this.predictedMillisUntilCountBackpressure = predictedMillisUntilCountBackpressure; } - @ApiModelProperty("The predicted number of milliseconds before the connection will have backpressure applied, based on the total number of bytes in the queue.") + @Schema(description = "The predicted number of milliseconds before the connection will have backpressure applied, based on the total number of bytes in the queue.") public Long getPredictedMillisUntilBytesBackpressure() { return predictedMillisUntilBytesBackpressure; } @@ -51,7 +51,7 @@ public void setPredictedMillisUntilBytesBackpressure(Long predictedMillisUntilBy this.predictedMillisUntilBytesBackpressure = predictedMillisUntilBytesBackpressure; } - @ApiModelProperty("The predicted number of queued objects at the next configured interval.") + @Schema(description = "The predicted number of queued objects at the next configured interval.") public Integer getPredictedCountAtNextInterval() { return predictedCountAtNextInterval; } @@ -60,7 +60,7 @@ public void setPredictedCountAtNextInterval(Integer predictedCountAtNextInterval this.predictedCountAtNextInterval = predictedCountAtNextInterval; } - @ApiModelProperty("The configured interval (in seconds) for predicting connection queue count and size (and percent usage).") + @Schema(description = "The configured interval (in seconds) for predicting connection queue count and size (and percent usage).") public Integer getPredictionIntervalSeconds() { return predictionIntervalSeconds; } @@ -69,7 +69,7 @@ public void setPredictionIntervalSeconds(Integer predictionIntervalSeconds) { this.predictionIntervalSeconds = predictionIntervalSeconds; } - @ApiModelProperty("The predicted total number of bytes in the queue at the next configured interval.") + @Schema(description = "The predicted total number of bytes in the queue at the next configured interval.") public Long getPredictedBytesAtNextInterval() { return predictedBytesAtNextInterval; } @@ -78,7 +78,7 @@ public void setPredictedBytesAtNextInterval(Long predictedBytesAtNextInterval) { this.predictedBytesAtNextInterval = predictedBytesAtNextInterval; } - @ApiModelProperty("Predicted connection percent use regarding queued flow files count and backpressure threshold if configured.") + @Schema(description = "Predicted connection percent use regarding queued flow files count and backpressure threshold if configured.") public Integer getPredictedPercentCount() { return predictedPercentCount; } @@ -87,7 +87,7 @@ public void setPredictedPercentCount(Integer predictedPercentCount) { this.predictedPercentCount = predictedPercentCount; } - @ApiModelProperty("Predicted connection percent use regarding queued flow files size and backpressure threshold if configured.") + @Schema(description = "Predicted connection percent use regarding queued flow files size and backpressure threshold if configured.") public Integer getPredictedPercentBytes() { return predictedPercentBytes; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusSnapshotDTO.java index f117584c14002..e876974ceecaf 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ConnectionStatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -54,7 +54,7 @@ public class ConnectionStatusSnapshotDTO implements Cloneable { /** * @return The connection id */ - @ApiModelProperty("The id of the connection.") + @Schema(description = "The id of the connection.") public String getId() { return id; } @@ -66,7 +66,7 @@ public void setId(String id) { /** * @return the ID of the Process Group to which this connection belongs. */ - @ApiModelProperty("The id of the process group the connection belongs to.") + @Schema(description = "The id of the process group the connection belongs to.") public String getGroupId() { return groupId; } @@ -78,7 +78,7 @@ public void setGroupId(final String groupId) { /** * @return name of this connection */ - @ApiModelProperty("The name of the connection.") + @Schema(description = "The name of the connection.") public String getName() { return name; } @@ -90,7 +90,7 @@ public void setName(String name) { /** * @return total count of flow files that are queued */ - @ApiModelProperty("The number of flowfiles that are queued, pretty printed.") + @Schema(description = "The number of flowfiles that are queued, pretty printed.") public String getQueuedCount() { return queuedCount; } @@ -103,7 +103,7 @@ public void setQueuedCount(String queuedCount) { /** * @return total size of flow files that are queued */ - @ApiModelProperty("The total size of flowfiles that are queued formatted.") + @Schema(description = "The total size of flowfiles that are queued formatted.") public String getQueuedSize() { return queuedSize; } @@ -128,7 +128,7 @@ public void setQueuedSize(String queuedSize) { /** * @return The total count and size of queued flow files */ - @ApiModelProperty("The total count and size of queued flowfiles formatted.") + @Schema(description = "The total count and size of queued flowfiles formatted.") public String getQueued() { return queued; } @@ -137,7 +137,7 @@ public String getQueued() { /** * @return id of the source of this connection */ - @ApiModelProperty("The id of the source of the connection.") + @Schema(description = "The id of the source of the connection.") public String getSourceId() { return sourceId; } @@ -149,7 +149,7 @@ public void setSourceId(String sourceId) { /** * @return name of the source of this connection */ - @ApiModelProperty("The name of the source of the connection.") + @Schema(description = "The name of the source of the connection.") public String getSourceName() { return sourceName; } @@ -161,7 +161,7 @@ public void setSourceName(String sourceName) { /** * @return id of the destination of this connection */ - @ApiModelProperty("The id of the destination of the connection.") + @Schema(description = "The id of the destination of the connection.") public String getDestinationId() { return destinationId; } @@ -173,7 +173,7 @@ public void setDestinationId(String destinationId) { /** * @return name of the destination of this connection */ - @ApiModelProperty("The name of the destination of the connection.") + @Schema(description = "The name of the destination of the connection.") public String getDestinationName() { return destinationName; } @@ -185,7 +185,7 @@ public void setDestinationName(String destinationName) { /** * @return predictions for this connection */ - @ApiModelProperty("Predictions, if available, for this connection (null if not available)") + @Schema(description = "Predictions, if available, for this connection (null if not available)") public ConnectionStatusPredictionsSnapshotDTO getPredictions() { return predictions; } @@ -197,7 +197,7 @@ public void setPredictions(ConnectionStatusPredictionsSnapshotDTO predictions) { /** * @return input for this connection */ - @ApiModelProperty("The input count/size for the connection in the last 5 minutes, pretty printed.") + @Schema(description = "The input count/size for the connection in the last 5 minutes, pretty printed.") public String getInput() { return input; } @@ -206,13 +206,13 @@ public String getInput() { /** * @return output for this connection */ - @ApiModelProperty("The output count/sie for the connection in the last 5 minutes, pretty printed.") + @Schema(description = "The output count/sie for the connection in the last 5 minutes, pretty printed.") public String getOutput() { return output; } - @ApiModelProperty("The number of FlowFiles that have come into the connection in the last 5 minutes.") + @Schema(description = "The number of FlowFiles that have come into the connection in the last 5 minutes.") public Integer getFlowFilesIn() { return flowFilesIn; } @@ -221,7 +221,7 @@ public void setFlowFilesIn(Integer flowFilesIn) { this.flowFilesIn = flowFilesIn; } - @ApiModelProperty("The size of the FlowFiles that have come into the connection in the last 5 minutes.") + @Schema(description = "The size of the FlowFiles that have come into the connection in the last 5 minutes.") public Long getBytesIn() { return bytesIn; } @@ -230,7 +230,7 @@ public void setBytesIn(Long bytesIn) { this.bytesIn = bytesIn; } - @ApiModelProperty("The number of FlowFiles that have left the connection in the last 5 minutes.") + @Schema(description = "The number of FlowFiles that have left the connection in the last 5 minutes.") public Integer getFlowFilesOut() { return flowFilesOut; } @@ -239,7 +239,7 @@ public void setFlowFilesOut(Integer flowFilesOut) { this.flowFilesOut = flowFilesOut; } - @ApiModelProperty("The number of bytes that have left the connection in the last 5 minutes.") + @Schema(description = "The number of bytes that have left the connection in the last 5 minutes.") public Long getBytesOut() { return bytesOut; } @@ -248,7 +248,7 @@ public void setBytesOut(Long bytesOut) { this.bytesOut = bytesOut; } - @ApiModelProperty("The number of FlowFiles that are currently queued in the connection.") + @Schema(description = "The number of FlowFiles that are currently queued in the connection.") public Integer getFlowFilesQueued() { return flowFilesQueued; } @@ -257,7 +257,7 @@ public void setFlowFilesQueued(Integer flowFilesQueued) { this.flowFilesQueued = flowFilesQueued; } - @ApiModelProperty("The size of the FlowFiles that are currently queued in the connection.") + @Schema(description = "The size of the FlowFiles that are currently queued in the connection.") public Long getBytesQueued() { return bytesQueued; } @@ -266,7 +266,7 @@ public void setBytesQueued(Long bytesQueued) { this.bytesQueued = bytesQueued; } - @ApiModelProperty("Connection percent use regarding queued flow files count and backpressure threshold if configured.") + @Schema(description = "Connection percent use regarding queued flow files count and backpressure threshold if configured.") public Integer getPercentUseCount() { return percentUseCount; } @@ -275,7 +275,7 @@ public void setPercentUseCount(Integer percentUseCount) { this.percentUseCount = percentUseCount; } - @ApiModelProperty("Connection percent use regarding queued flow files size and backpressure threshold if configured.") + @Schema(description = "Connection percent use regarding queued flow files size and backpressure threshold if configured.") public Integer getPercentUseBytes() { return percentUseBytes; } @@ -284,7 +284,7 @@ public void setPercentUseBytes(Integer percentUseBytes) { this.percentUseBytes = percentUseBytes; } - @ApiModelProperty("The availability of FlowFiles in this connection") + @Schema(description = "The availability of FlowFiles in this connection") public String getFlowFileAvailability() { return flowFileAvailability; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java index 6f67682e76fa4..f6e97ac2340d1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerServiceStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -27,8 +27,8 @@ @XmlType(name = "controllerServiceStatus") public class ControllerServiceStatusDTO extends ComponentStatusDTO { - @ApiModelProperty(value = "The run status of this ControllerService", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "The run status of this ControllerService", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = "ENABLED, ENABLING, DISABLED, DISABLING") @Override public String getRunStatus() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerStatusDTO.java index bfea16cb97184..42a79a68cb741 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ControllerStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -50,7 +50,7 @@ public class ControllerStatusDTO implements Cloneable { * * @return The active thread count */ - @ApiModelProperty("The number of active threads in the NiFi.") + @Schema(description = "The number of active threads in the NiFi.") public Integer getActiveThreadCount() { return activeThreadCount; } @@ -64,7 +64,7 @@ public void setActiveThreadCount(Integer activeThreadCount) { * * @return The terminated thread count */ - @ApiModelProperty("The number of terminated threads in the NiFi.") + @Schema(description = "The number of terminated threads in the NiFi.") public Integer getTerminatedThreadCount() { return terminatedThreadCount; } @@ -76,7 +76,7 @@ public void setTerminatedThreadCount(Integer terminatedThreadCount) { /** * @return queue for the controller */ - @ApiModelProperty("The number of flowfiles queued in the NiFi.") + @Schema(description = "The number of flowfiles queued in the NiFi.") public String getQueued() { return queued; } @@ -88,7 +88,7 @@ public void setQueued(String queued) { /** * @return number of running components in this controller */ - @ApiModelProperty("The number of running components in the NiFi.") + @Schema(description = "The number of running components in the NiFi.") public Integer getRunningCount() { return runningCount; } @@ -100,7 +100,7 @@ public void setRunningCount(Integer runningCount) { /** * @return number of stopped components in this controller */ - @ApiModelProperty("The number of stopped components in the NiFi.") + @Schema(description = "The number of stopped components in the NiFi.") public Integer getStoppedCount() { return stoppedCount; } @@ -112,7 +112,7 @@ public void setStoppedCount(Integer stoppedCount) { /** * @return number of invalid components in this controller */ - @ApiModelProperty("The number of invalid components in the NiFi.") + @Schema(description = "The number of invalid components in the NiFi.") public Integer getInvalidCount() { return invalidCount; } @@ -124,7 +124,7 @@ public void setInvalidCount(Integer invalidCount) { /** * @return number of disabled components in this controller */ - @ApiModelProperty("The number of disabled components in the NiFi.") + @Schema(description = "The number of disabled components in the NiFi.") public Integer getDisabledCount() { return disabledCount; } @@ -136,7 +136,7 @@ public void setDisabledCount(Integer disabledCount) { /** * @return number of active remote ports in this controller */ - @ApiModelProperty("The number of active remote ports in the NiFi.") + @Schema(description = "The number of active remote ports in the NiFi.") public Integer getActiveRemotePortCount() { return activeRemotePortCount; } @@ -148,7 +148,7 @@ public void setActiveRemotePortCount(Integer activeRemotePortCount) { /** * @return number of inactive remote ports in this controller */ - @ApiModelProperty("The number of inactive remote ports in the NiFi.") + @Schema(description = "The number of inactive remote ports in the NiFi.") public Integer getInactiveRemotePortCount() { return inactiveRemotePortCount; } @@ -157,7 +157,7 @@ public void setInactiveRemotePortCount(Integer inactiveRemotePortCount) { this.inactiveRemotePortCount = inactiveRemotePortCount; } - @ApiModelProperty("The number of FlowFiles queued across the entire flow") + @Schema(description = "The number of FlowFiles queued across the entire flow") public Integer getFlowFilesQueued() { return flowFilesQueued; } @@ -166,7 +166,7 @@ public void setFlowFilesQueued(Integer flowFilesQueued) { this.flowFilesQueued = flowFilesQueued; } - @ApiModelProperty("The size of the FlowFiles queued across the entire flow") + @Schema(description = "The size of the FlowFiles queued across the entire flow") public Long getBytesQueued() { return bytesQueued; } @@ -175,7 +175,7 @@ public void setBytesQueued(Long bytesQueued) { this.bytesQueued = bytesQueued; } - @ApiModelProperty("The number of up to date versioned process groups in the NiFi.") + @Schema(description = "The number of up to date versioned process groups in the NiFi.") public Integer getUpToDateCount() { return upToDateCount; } @@ -184,7 +184,7 @@ public void setUpToDateCount(Integer upToDateCount) { this.upToDateCount = upToDateCount; } - @ApiModelProperty("The number of locally modified versioned process groups in the NiFi.") + @Schema(description = "The number of locally modified versioned process groups in the NiFi.") public Integer getLocallyModifiedCount() { return locallyModifiedCount; } @@ -193,7 +193,7 @@ public void setLocallyModifiedCount(Integer locallyModifiedCount) { this.locallyModifiedCount = locallyModifiedCount; } - @ApiModelProperty("The number of stale versioned process groups in the NiFi.") + @Schema(description = "The number of stale versioned process groups in the NiFi.") public Integer getStaleCount() { return staleCount; } @@ -202,7 +202,7 @@ public void setStaleCount(Integer staleCount) { this.staleCount = staleCount; } - @ApiModelProperty("The number of locally modified and stale versioned process groups in the NiFi.") + @Schema(description = "The number of locally modified and stale versioned process groups in the NiFi.") public Integer getLocallyModifiedAndStaleCount() { return locallyModifiedAndStaleCount; } @@ -211,7 +211,7 @@ public void setLocallyModifiedAndStaleCount(Integer locallyModifiedAndStaleCount this.locallyModifiedAndStaleCount = locallyModifiedAndStaleCount; } - @ApiModelProperty("The number of versioned process groups in the NiFi that are unable to sync to a registry.") + @Schema(description = "The number of versioned process groups in the NiFi that are unable to sync to a registry.") public Integer getSyncFailureCount() { return syncFailureCount; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/FlowAnalysisRuleStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/FlowAnalysisRuleStatusDTO.java index 1b19fab2e369c..a4897f6d542b4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/FlowAnalysisRuleStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/FlowAnalysisRuleStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -27,8 +27,8 @@ @XmlType(name = "flowAnalysisRuleStatus") public class FlowAnalysisRuleStatusDTO extends ComponentStatusDTO { - @ApiModelProperty(value = "The run status of this FlowAnalysisRule", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "The run status of this FlowAnalysisRule", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = "ENABLED, DISABLED") @Override public String getRunStatus() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatisticsSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatisticsSnapshotDTO.java index 0d79476fc8dd7..319da96501e21 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatisticsSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatisticsSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public class NodeConnectionStatisticsSnapshotDTO implements Cloneable { private ConnectionStatisticsSnapshotDTO statisticsSnapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The connection status snapshot from the node.") + @Schema(description = "The connection status snapshot from the node.") public ConnectionStatisticsSnapshotDTO getStatisticsSnapshot() { return statisticsSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatusSnapshotDTO.java index 081e06ad0c072..d426bc7d48f02 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeConnectionStatusSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public class NodeConnectionStatusSnapshotDTO implements Cloneable { private ConnectionStatusSnapshotDTO statusSnapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The connection status snapshot from the node.") + @Schema(description = "The connection status snapshot from the node.") public ConnectionStatusSnapshotDTO getStatusSnapshot() { return statusSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusDTO.java index 597e5cc3fee88..8ad3f9e25dee0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.NodeDTO; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class NodePortStatusDTO { /** * @return the node */ - @ApiModelProperty( - value = "The node." + @Schema(description = "The node." ) public NodeDTO getNode() { return node; @@ -47,8 +46,7 @@ public void setNode(NodeDTO node) { /** * @return port status */ - @ApiModelProperty( - value = "The port status from the node." + @Schema(description = "The port status from the node." ) public PortStatusDTO getPortStatus() { return portStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusSnapshotDTO.java index 9abb795876fd5..ed6d0b1a7e5f0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodePortStatusSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public class NodePortStatusSnapshotDTO implements Cloneable { private PortStatusSnapshotDTO statusSnapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The port status snapshot from the node.") + @Schema(description = "The port status snapshot from the node.") public PortStatusSnapshotDTO getStatusSnapshot() { return statusSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessGroupStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessGroupStatusSnapshotDTO.java index 8f6131a306c01..6462dc95ac945 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessGroupStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessGroupStatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; public class NodeProcessGroupStatusSnapshotDTO implements Cloneable { @@ -26,7 +26,7 @@ public class NodeProcessGroupStatusSnapshotDTO implements Cloneable { private ProcessGroupStatusSnapshotDTO statusSnapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -35,7 +35,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -44,7 +44,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -53,7 +53,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The process group status snapshot from the node.") + @Schema(description = "The process group status snapshot from the node.") public ProcessGroupStatusSnapshotDTO getStatusSnapshot() { return statusSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessorStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessorStatusSnapshotDTO.java index f95e08a00af32..c08230a7294f1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessorStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeProcessorStatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -32,7 +32,7 @@ public class NodeProcessorStatusSnapshotDTO implements Cloneable { private ProcessorStatusSnapshotDTO statusSnapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -41,7 +41,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -50,7 +50,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -59,7 +59,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The processor status snapshot from the node.") + @Schema(description = "The processor status snapshot from the node.") public ProcessorStatusSnapshotDTO getStatusSnapshot() { return statusSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeRemoteProcessGroupStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeRemoteProcessGroupStatusSnapshotDTO.java index 47985dd1ee14c..8b1b839b8bbcb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeRemoteProcessGroupStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeRemoteProcessGroupStatusSnapshotDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -29,7 +29,7 @@ public class NodeRemoteProcessGroupStatusSnapshotDTO implements Cloneable { private RemoteProcessGroupStatusSnapshotDTO statusSnapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -38,7 +38,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -47,7 +47,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -56,7 +56,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The remote process group status snapshot from the node.") + @Schema(description = "The remote process group status snapshot from the node.") public RemoteProcessGroupStatusSnapshotDTO getStatusSnapshot() { return statusSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusDTO.java index 4c2d12ceb07b0..6fcf1152e70c0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.NodeDTO; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class NodeStatusDTO { /** * @return the node */ - @ApiModelProperty( - value = "The node." + @Schema(description = "The node." ) public NodeDTO getNode() { return node; @@ -47,8 +46,7 @@ public void setNode(NodeDTO node) { /** * @return the controller status */ - @ApiModelProperty( - value = "The controller status for each node." + @Schema(description = "The controller status for each node." ) public ProcessGroupStatusDTO getControllerStatus() { return controllerStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusSnapshotsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusSnapshotsDTO.java index d8a4c6456c890..c5db00ae6222a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusSnapshotsDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/NodeStatusSnapshotsDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.List; @@ -35,8 +35,7 @@ public class NodeStatusSnapshotsDTO { /** * @return node's host/IP address */ - @ApiModelProperty( - value = "The node's host/ip address." + @Schema(description = "The node's host/ip address." ) public String getAddress() { return address; @@ -49,8 +48,7 @@ public void setAddress(String address) { /** * @return node ID */ - @ApiModelProperty( - value = "The id of the node." + @Schema(description = "The id of the node." ) public String getNodeId() { return nodeId; @@ -63,8 +61,7 @@ public void setNodeId(String nodeId) { /** * @return port the node is listening for API requests */ - @ApiModelProperty( - value = "The port the node is listening for API requests." + @Schema(description = "The port the node is listening for API requests." ) public Integer getApiPort() { return apiPort; @@ -74,7 +71,7 @@ public void setApiPort(Integer port) { this.apiPort = port; } - @ApiModelProperty("A list of StatusSnapshotDTO objects that provide the actual metric values for the component for this node.") + @Schema(description = "A list of StatusSnapshotDTO objects that provide the actual metric values for the component for this node.") public List getStatusSnapshots() { return statusSnapshots; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusDTO.java index 248279d527baa..431e14f6d334c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -36,7 +36,7 @@ public class PortStatusDTO { private PortStatusSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty("Whether the port has incoming or outgoing connections to a remote NiFi.") + @Schema(description = "Whether the port has incoming or outgoing connections to a remote NiFi.") public Boolean isTransmitting() { return transmitting; } @@ -46,7 +46,7 @@ public void setTransmitting(Boolean transmitting) { } - @ApiModelProperty("The id of the port.") + @Schema(description = "The id of the port.") public String getId() { return id; } @@ -56,7 +56,7 @@ public void setId(String id) { } - @ApiModelProperty("The id of the parent process group of the port.") + @Schema(description = "The id of the parent process group of the port.") public String getGroupId() { return groupId; } @@ -66,7 +66,7 @@ public void setGroupId(String groupId) { } - @ApiModelProperty("The name of the port.") + @Schema(description = "The name of the port.") public String getName() { return name; } @@ -76,8 +76,7 @@ public void setName(String name) { } - @ApiModelProperty( - value="The run status of the port.", + @Schema(description = "The run status of the port.", allowableValues = "Running, Stopped, Validating, Disabled, Invalid") public String getRunStatus() { return runStatus; @@ -87,7 +86,7 @@ public void setRunStatus(String runStatus) { this.runStatus = runStatus; } - @ApiModelProperty("A status snapshot that represents the aggregate stats of all nodes in the cluster. If the NiFi instance is " + @Schema(description = "A status snapshot that represents the aggregate stats of all nodes in the cluster. If the NiFi instance is " + "a standalone instance, rather than a cluster, this represents the stats of the single instance.") public PortStatusSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; @@ -97,7 +96,7 @@ public void setAggregateSnapshot(PortStatusSnapshotDTO aggregateSnapshot) { this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A status snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + @Schema(description = "A status snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + "a cluster, this may be null.") public List getNodeSnapshots() { return nodeSnapshots; @@ -113,9 +112,8 @@ public void setNodeSnapshots(List nodeSnapshots) { * @return The the status was calculated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The time the status for the process group was last refreshed.", - dataType = "string" + @Schema(description = "The time the status for the process group was last refreshed.", + type = "string" ) public Date getStatsLastRefreshed() { return statsLastRefreshed; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusSnapshotDTO.java index 63bb142227173..dad3c74c93177 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/PortStatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -44,7 +44,7 @@ public class PortStatusSnapshotDTO implements Cloneable { /** * @return whether this port has incoming or outgoing connections to a remote NiFi */ - @ApiModelProperty("Whether the port has incoming or outgoing connections to a remote NiFi.") + @Schema(description = "Whether the port has incoming or outgoing connections to a remote NiFi.") public Boolean isTransmitting() { return transmitting; } @@ -56,7 +56,7 @@ public void setTransmitting(Boolean transmitting) { /** * @return the active thread count for this port */ - @ApiModelProperty("The active thread count for the port.") + @Schema(description = "The active thread count for the port.") public Integer getActiveThreadCount() { return activeThreadCount; } @@ -68,7 +68,7 @@ public void setActiveThreadCount(Integer activeThreadCount) { /** * @return id of this port */ - @ApiModelProperty("The id of the port.") + @Schema(description = "The id of the port.") public String getId() { return id; } @@ -80,7 +80,7 @@ public void setId(String id) { /** * @return id of the group this port resides in */ - @ApiModelProperty("The id of the parent process group of the port.") + @Schema(description = "The id of the parent process group of the port.") public String getGroupId() { return groupId; } @@ -92,7 +92,7 @@ public void setGroupId(String groupId) { /** * @return name of this port */ - @ApiModelProperty("The name of the port.") + @Schema(description = "The name of the port.") public String getName() { return name; } @@ -104,9 +104,10 @@ public void setName(String name) { /** * @return run status of this port */ - @ApiModelProperty( - value="The run status of the port.", - allowableValues = "Running, Stopped, Validating, Disabled, Invalid") + @Schema( + description = "The run status of the port.", + allowableValues = "Running, Stopped, Validating, Disabled, Invalid" + ) public String getRunStatus() { return runStatus; } @@ -118,7 +119,7 @@ public void setRunStatus(String runStatus) { /** * @return The total count and size of flow files that have been accepted in the last five minutes */ - @ApiModelProperty("The count/size of flowfiles that have been accepted in the last 5 minutes.") + @Schema(description = "The count/size of flowfiles that have been accepted in the last 5 minutes.") public String getInput() { return input; } @@ -130,7 +131,7 @@ public void setInput(String input) { /** * @return The total count and size of flow files that have been processed in the last five minutes */ - @ApiModelProperty("The count/size of flowfiles that have been processed in the last 5 minutes.") + @Schema(description = "The count/size of flowfiles that have been processed in the last 5 minutes.") public String getOutput() { return output; } @@ -139,7 +140,7 @@ public void setOutput(String output) { this.output = output; } - @ApiModelProperty("The number of FlowFiles that have been accepted in the last 5 minutes.") + @Schema(description = "The number of FlowFiles that have been accepted in the last 5 minutes.") public Integer getFlowFilesIn() { return flowFilesIn; } @@ -148,7 +149,7 @@ public void setFlowFilesIn(Integer flowFilesIn) { this.flowFilesIn = flowFilesIn; } - @ApiModelProperty("The size of hte FlowFiles that have been accepted in the last 5 minutes.") + @Schema(description = "The size of hte FlowFiles that have been accepted in the last 5 minutes.") public Long getBytesIn() { return bytesIn; } @@ -157,7 +158,7 @@ public void setBytesIn(Long bytesIn) { this.bytesIn = bytesIn; } - @ApiModelProperty("The number of FlowFiles that have been processed in the last 5 minutes.") + @Schema(description = "The number of FlowFiles that have been processed in the last 5 minutes.") public Integer getFlowFilesOut() { return flowFilesOut; } @@ -166,7 +167,7 @@ public void setFlowFilesOut(Integer flowFilesOut) { this.flowFilesOut = flowFilesOut; } - @ApiModelProperty("The number of bytes that have been processed in the last 5 minutes.") + @Schema(description = "The number of bytes that have been processed in the last 5 minutes.") public Long getBytesOut() { return bytesOut; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusDTO.java index 936ba3c53997a..7efb712f8aa8b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -34,7 +34,7 @@ public class ProcessGroupStatusDTO implements Cloneable { private ProcessGroupStatusSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty("The ID of the Process Group") + @Schema(description = "The ID of the Process Group") public String getId() { return id; } @@ -43,7 +43,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The name of the Process Group") + @Schema(description = "The name of the Process Group") public String getName() { return name; } @@ -52,7 +52,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The aggregate status of all nodes in the cluster") + @Schema(description = "The aggregate status of all nodes in the cluster") public ProcessGroupStatusSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; } @@ -61,7 +61,7 @@ public void setAggregateSnapshot(ProcessGroupStatusSnapshotDTO aggregateSnapshot this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("The status reported by each node in the cluster. If the NiFi instance is a standalone instance, rather than " + @Schema(description = "The status reported by each node in the cluster. If the NiFi instance is a standalone instance, rather than " + "a clustered instance, this value may be null.") public List getNodeSnapshots() { return nodeSnapshots; @@ -77,9 +77,8 @@ public void setNodeSnapshots(List nodeSnapsho * @return The the status was calculated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The time the status for the process group was last refreshed.", - dataType = "string" + @Schema(description = "The time the status for the process group was last refreshed.", + type = "string" ) public Date getStatsLastRefreshed() { return statsLastRefreshed; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusSnapshotDTO.java index 06b34b0821ed2..5c179896496da 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessGroupStatusSnapshotDTO.java @@ -16,8 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; -import io.swagger.annotations.ApiModelProperty.AccessMode; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.entity.ConnectionStatusSnapshotEntity; import org.apache.nifi.web.api.entity.PortStatusSnapshotEntity; import org.apache.nifi.web.api.entity.ProcessGroupStatusSnapshotEntity; @@ -87,7 +86,7 @@ public class ProcessGroupStatusSnapshotDTO implements Cloneable { * * @return The id for the process group */ - @ApiModelProperty("The id of the process group.") + @Schema(description = "The id of the process group.") public String getId() { return id; } @@ -99,7 +98,7 @@ public void setId(String id) { /** * @return name of this process group */ - @ApiModelProperty("The name of this process group.") + @Schema(description = "The name of this process group.") public String getName() { return name; } @@ -108,8 +107,8 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY, - value = "The current state of the Process Group, as it relates to the Versioned Flow", + @Schema(description = "The current state of the Process Group, as it relates to the Versioned Flow", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = "LOCALLY_MODIFIED, STALE, LOCALLY_MODIFIED_AND_STALE, UP_TO_DATE, SYNC_FAILURE") public String getVersionedFlowState() { return versionedFlowState; @@ -119,8 +118,10 @@ public void setVersionedFlowState(String versionedFlowState) { this.versionedFlowState = versionedFlowState; } - @ApiModelProperty(accessMode = AccessMode.READ_ONLY, - value = "The current number of active threads for the Process Group, when running in Stateless mode.") + @Schema( + description = "The current number of active threads for the Process Group, when running in Stateless mode.", + accessMode = Schema.AccessMode.READ_ONLY + ) public int getStatelessActiveThreadCount() { return statelessActiveThreadCount; } @@ -132,7 +133,7 @@ public void setStatelessActiveThreadCount(int statelessActiveThreadCount) { /** * @return active thread count for this process group */ - @ApiModelProperty("The active thread count for this process group.") + @Schema(description = "The active thread count for this process group.") public Integer getActiveThreadCount() { return activeThreadCount; } @@ -144,7 +145,7 @@ public void setActiveThreadCount(Integer activeThreadCount) { /** * @return number of threads currently terminated for this process group */ - @ApiModelProperty("The number of threads currently terminated for the process group.") + @Schema(description = "The number of threads currently terminated for the process group.") public Integer getTerminatedThreadCount() { return terminatedThreadCount; } @@ -158,7 +159,7 @@ public void setTerminatedThreadCount(Integer terminatedThreadCount) { * * @return The status of all connections */ - @ApiModelProperty("The status of all connections in the process group.") + @Schema(description = "The status of all connections in the process group.") public Collection getConnectionStatusSnapshots() { return connectionStatusSnapshots; } @@ -172,7 +173,7 @@ public void setConnectionStatusSnapshots(Collection getProcessGroupStatusSnapshots() { return processGroupStatusSnapshots; } @@ -186,7 +187,7 @@ public void setProcessGroupStatusSnapshots(Collection getRemoteProcessGroupStatusSnapshots() { return remoteProcessGroupStatusSnapshots; } @@ -200,7 +201,7 @@ public void setRemoteProcessGroupStatusSnapshots(final Collection getProcessorStatusSnapshots() { return processorStatusSnapshots; } @@ -214,7 +215,7 @@ public void setProcessorStatusSnapshots(Collection getInputPortStatusSnapshots() { return inputPortStatusSnapshots; } @@ -228,7 +229,7 @@ public void setInputPortStatusSnapshots(Collection inp * * @return The status of all output ports */ - @ApiModelProperty("The status of all output ports in the process group.") + @Schema(description = "The status of all output ports in the process group.") public Collection getOutputPortStatusSnapshots() { return outputPortStatusSnapshots; } @@ -242,7 +243,7 @@ public void setOutputPortStatusSnapshots(Collection ou * * @return The output stats */ - @ApiModelProperty("The output count/size for the process group in the last 5 minutes.") + @Schema(description = "The output count/size for the process group in the last 5 minutes.") public String getOutput() { return output; } @@ -252,7 +253,7 @@ public String getOutput() { * * @return The transferred status for this process group */ - @ApiModelProperty("The count/size transferred to/from queues in the process group in the last 5 minutes.") + @Schema(description = "The count/size transferred to/from queues in the process group in the last 5 minutes.") public String getTransferred() { return transferred; } @@ -262,7 +263,7 @@ public String getTransferred() { * * @return The received stats for this process group */ - @ApiModelProperty("The count/size sent to the process group in the last 5 minutes.") + @Schema(description = "The count/size sent to the process group in the last 5 minutes.") public String getReceived() { return received; } @@ -273,7 +274,7 @@ public String getReceived() { * * @return The sent stats for this process group */ - @ApiModelProperty("The count/size sent from this process group in the last 5 minutes.") + @Schema(description = "The count/size sent from this process group in the last 5 minutes.") public String getSent() { return sent; } @@ -284,7 +285,7 @@ public String getSent() { * * @return The queued count for this process group */ - @ApiModelProperty("The count that is queued for the process group.") + @Schema(description = "The count that is queued for the process group.") public String getQueuedCount() { return queuedCount; } @@ -295,7 +296,7 @@ public String getQueuedCount() { * * @return The queued size for this process group */ - @ApiModelProperty("The size that is queued for the process group.") + @Schema(description = "The size that is queued for the process group.") public String getQueuedSize() { return queuedSize; } @@ -306,7 +307,7 @@ public String getQueuedSize() { * * @return The queued stats */ - @ApiModelProperty("The count/size that is queued in the the process group.") + @Schema(description = "The count/size that is queued in the the process group.") public String getQueued() { return queued; } @@ -317,7 +318,7 @@ public String getQueued() { * * @return The read stats */ - @ApiModelProperty("The number of bytes read in the last 5 minutes.") + @Schema(description = "The number of bytes read in the last 5 minutes.") public String getRead() { return read; } @@ -328,7 +329,7 @@ public String getRead() { * * @return The written stats */ - @ApiModelProperty("The number of bytes written in the last 5 minutes.") + @Schema(description = "The number of bytes written in the last 5 minutes.") public String getWritten() { return written; } @@ -339,13 +340,13 @@ public String getWritten() { * * @return The input stats */ - @ApiModelProperty("The input count/size for the process group in the last 5 minutes (pretty printed).") + @Schema(description = "The input count/size for the process group in the last 5 minutes (pretty printed).") public String getInput() { return input; } - @ApiModelProperty("The number of FlowFiles that have come into this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of FlowFiles that have come into this ProcessGroup in the last 5 minutes") public Integer getFlowFilesIn() { return flowFilesIn; } @@ -354,7 +355,7 @@ public void setFlowFilesIn(Integer flowFilesIn) { this.flowFilesIn = flowFilesIn; } - @ApiModelProperty("The number of bytes that have come into this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes that have come into this ProcessGroup in the last 5 minutes") public Long getBytesIn() { return bytesIn; } @@ -363,7 +364,7 @@ public void setBytesIn(Long bytesIn) { this.bytesIn = bytesIn; } - @ApiModelProperty("The number of FlowFiles that are queued up in this ProcessGroup right now") + @Schema(description = "The number of FlowFiles that are queued up in this ProcessGroup right now") public Integer getFlowFilesQueued() { return flowFilesQueued; } @@ -372,7 +373,7 @@ public void setFlowFilesQueued(Integer flowFilesQueued) { this.flowFilesQueued = flowFilesQueued; } - @ApiModelProperty("The number of bytes that are queued up in this ProcessGroup right now") + @Schema(description = "The number of bytes that are queued up in this ProcessGroup right now") public Long getBytesQueued() { return bytesQueued; } @@ -381,7 +382,7 @@ public void setBytesQueued(Long bytesQueued) { this.bytesQueued = bytesQueued; } - @ApiModelProperty("The number of bytes read by components in this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes read by components in this ProcessGroup in the last 5 minutes") public Long getBytesRead() { return bytesRead; } @@ -390,7 +391,7 @@ public void setBytesRead(Long bytesRead) { this.bytesRead = bytesRead; } - @ApiModelProperty("The number of bytes written by components in this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes written by components in this ProcessGroup in the last 5 minutes") public Long getBytesWritten() { return bytesWritten; } @@ -399,7 +400,7 @@ public void setBytesWritten(Long bytesWritten) { this.bytesWritten = bytesWritten; } - @ApiModelProperty("The number of FlowFiles transferred out of this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of FlowFiles transferred out of this ProcessGroup in the last 5 minutes") public Integer getFlowFilesOut() { return flowFilesOut; } @@ -408,7 +409,7 @@ public void setFlowFilesOut(Integer flowFilesOut) { this.flowFilesOut = flowFilesOut; } - @ApiModelProperty("The number of bytes transferred out of this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes transferred out of this ProcessGroup in the last 5 minutes") public Long getBytesOut() { return bytesOut; } @@ -417,7 +418,7 @@ public void setBytesOut(Long bytesOut) { this.bytesOut = bytesOut; } - @ApiModelProperty("The number of FlowFiles transferred in this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of FlowFiles transferred in this ProcessGroup in the last 5 minutes") public Integer getFlowFilesTransferred() { return flowFilesTransferred; } @@ -426,7 +427,7 @@ public void setFlowFilesTransferred(Integer flowFilesTransferred) { this.flowFilesTransferred = flowFilesTransferred; } - @ApiModelProperty("The number of bytes transferred in this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes transferred in this ProcessGroup in the last 5 minutes") public Long getBytesTransferred() { return bytesTransferred; } @@ -435,7 +436,7 @@ public void setBytesTransferred(Long bytesTransferred) { this.bytesTransferred = bytesTransferred; } - @ApiModelProperty("The number of bytes received from external sources by components within this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes received from external sources by components within this ProcessGroup in the last 5 minutes") public Long getBytesReceived() { return bytesReceived; } @@ -444,7 +445,7 @@ public void setBytesReceived(Long bytesReceived) { this.bytesReceived = bytesReceived; } - @ApiModelProperty("The number of bytes sent to an external sink by components within this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of bytes sent to an external sink by components within this ProcessGroup in the last 5 minutes") public Long getBytesSent() { return bytesSent; } @@ -453,7 +454,7 @@ public void setBytesSent(Long bytesSent) { this.bytesSent = bytesSent; } - @ApiModelProperty("The number of FlowFiles sent to an external sink by components within this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of FlowFiles sent to an external sink by components within this ProcessGroup in the last 5 minutes") public Integer getFlowFilesSent() { return flowFilesSent; } @@ -462,7 +463,7 @@ public void setFlowFilesSent(Integer flowFilesSent) { this.flowFilesSent = flowFilesSent; } - @ApiModelProperty("The number of FlowFiles received from external sources by components within this ProcessGroup in the last 5 minutes") + @Schema(description = "The number of FlowFiles received from external sources by components within this ProcessGroup in the last 5 minutes") public Integer getFlowFilesReceived() { return flowFilesReceived; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusDTO.java index d391fcdd07309..36c3f27e43de0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -41,7 +41,7 @@ public class ProcessorStatusDTO implements Cloneable { private ProcessorStatusSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty("The unique ID of the process group that the Processor belongs to") + @Schema(description = "The unique ID of the process group that the Processor belongs to") public String getGroupId() { return groupId; } @@ -50,7 +50,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty("The unique ID of the Processor") + @Schema(description = "The unique ID of the Processor") public String getId() { return id; } @@ -59,7 +59,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The name of the Processor") + @Schema(description = "The name of the Processor") public String getName() { return name; } @@ -68,7 +68,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The type of the Processor") + @Schema(description = "The type of the Processor") public String getType() { return type; } @@ -77,7 +77,7 @@ public void setType(String type) { this.type = type; } - @ApiModelProperty(value="The run status of the Processor", + @Schema(description = "The run status of the Processor", allowableValues = "Running, Stopped, Validating, Disabled, Invalid") public String getRunStatus() { return runStatus; @@ -88,10 +88,7 @@ public void setRunStatus(String runStatus) { } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value="The timestamp of when the stats were last refreshed", - dataType = "string" - ) + @Schema(description = "The timestamp of when the stats were last refreshed", type = "string") public Date getStatsLastRefreshed() { return statsLastRefreshed; } @@ -100,7 +97,7 @@ public void setStatsLastRefreshed(Date statsLastRefreshed) { this.statsLastRefreshed = statsLastRefreshed; } - @ApiModelProperty("A status snapshot that represents the aggregate stats of all nodes in the cluster. If the NiFi instance is " + @Schema(description = "A status snapshot that represents the aggregate stats of all nodes in the cluster. If the NiFi instance is " + "a standalone instance, rather than a cluster, this represents the stats of the single instance.") public ProcessorStatusSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; @@ -110,7 +107,7 @@ public void setAggregateSnapshot(ProcessorStatusSnapshotDTO aggregateSnapshot) { this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A status snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + @Schema(description = "A status snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + "a cluster, this may be null.") public List getNodeSnapshots() { return nodeSnapshots; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusSnapshotDTO.java index 4c3d978595e25..2e9d1ac245c79 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ProcessorStatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -57,7 +57,7 @@ public class ProcessorStatusSnapshotDTO implements Cloneable { /** * @return The processor id */ - @ApiModelProperty("The id of the processor.") + @Schema(description = "The id of the processor.") public String getId() { return id; } @@ -69,7 +69,7 @@ public void setId(String id) { /** * @return The processor name */ - @ApiModelProperty("The name of the prcessor.") + @Schema(description = "The name of the prcessor.") public String getName() { return name; } @@ -81,7 +81,7 @@ public void setName(String name) { /** * @return The processor type */ - @ApiModelProperty("The type of the processor.") + @Schema(description = "The type of the processor.") public String getType() { return type; } @@ -93,8 +93,7 @@ public void setType(String type) { /** * @return run status of this processor */ - @ApiModelProperty( - value = "The state of the processor.", + @Schema(description = "The state of the processor.", allowableValues = "Running, Stopped, Validating, Disabled, Invalid" ) public String getRunStatus() { @@ -105,8 +104,7 @@ public void setRunStatus(String runStatus) { this.runStatus = runStatus; } - @ApiModelProperty( - value = "Indicates the node where the process will execute.", + @Schema(description = "Indicates the node where the process will execute.", allowableValues = "ALL, PRIMARY" ) public String getExecutionNode() { @@ -120,7 +118,7 @@ public void setExecutionNode(String executionNode) { /** * @return The total count and size of flow files that have been accepted in the last five minutes */ - @ApiModelProperty("The count/size of flowfiles that have been accepted in the last 5 minutes.") + @Schema(description = "The count/size of flowfiles that have been accepted in the last 5 minutes.") public String getInput() { return input; } @@ -132,7 +130,7 @@ public void setInput(String input) { /** * @return number of bytes read */ - @ApiModelProperty("The number of bytes read in the last 5 minutes.") + @Schema(description = "The number of bytes read in the last 5 minutes.") public String getRead() { return read; } @@ -144,7 +142,7 @@ public void setRead(String read) { /** * @return number of bytes written */ - @ApiModelProperty("The number of bytes written in the last 5 minutes.") + @Schema(description = "The number of bytes written in the last 5 minutes.") public String getWritten() { return written; } @@ -156,7 +154,7 @@ public void setWritten(String written) { /** * @return the ID of the Process Group to which this processor belongs. */ - @ApiModelProperty("The id of the parent process group to which the processor belongs.") + @Schema(description = "The id of the parent process group to which the processor belongs.") public String getGroupId() { return groupId; } @@ -168,7 +166,7 @@ public void setGroupId(final String groupId) { /** * @return The total count and size of flow files that have been processed in the last five minutes */ - @ApiModelProperty("The count/size of flowfiles that have been processed in the last 5 minutes.") + @Schema(description = "The count/size of flowfiles that have been processed in the last 5 minutes.") public String getOutput() { return output; } @@ -180,7 +178,7 @@ public void setOutput(String output) { /** * @return number of threads currently running for this Processor */ - @ApiModelProperty("The number of threads currently executing in the processor.") + @Schema(description = "The number of threads currently executing in the processor.") public Integer getActiveThreadCount() { return activeThreadCount; } @@ -192,7 +190,7 @@ public void setActiveThreadCount(Integer threadCount) { /** * @return number of threads currently terminated for this Processor */ - @ApiModelProperty("The number of threads currently terminated for the processor.") + @Schema(description = "The number of threads currently terminated for the processor.") public Integer getTerminatedThreadCount() { return terminatedThreadCount; } @@ -204,7 +202,7 @@ public void setTerminatedThreadCount(Integer terminatedThreadCount) { /** * @return number of task this connectable has had over the last 5 minutes */ - @ApiModelProperty("The total number of task this connectable has completed over the last 5 minutes.") + @Schema(description = "The total number of task this connectable has completed over the last 5 minutes.") public String getTasks() { return tasks; } @@ -216,7 +214,7 @@ public void setTasks(String tasks) { /** * @return total duration of all tasks for this connectable over the last 5 minutes */ - @ApiModelProperty("The total duration of all tasks for this connectable over the last 5 minutes.") + @Schema(description = "The total duration of all tasks for this connectable over the last 5 minutes.") public String getTasksDuration() { return tasksDuration; } @@ -225,7 +223,7 @@ public void setTasksDuration(String tasksDuration) { this.tasksDuration = tasksDuration; } - @ApiModelProperty("The number of bytes read by this Processor in the last 5 mintues") + @Schema(description = "The number of bytes read by this Processor in the last 5 mintues") public Long getBytesRead() { return bytesRead; } @@ -234,7 +232,7 @@ public void setBytesRead(Long bytesRead) { this.bytesRead = bytesRead; } - @ApiModelProperty("The number of bytes written by this Processor in the last 5 minutes") + @Schema(description = "The number of bytes written by this Processor in the last 5 minutes") public Long getBytesWritten() { return bytesWritten; } @@ -243,7 +241,7 @@ public void setBytesWritten(Long bytesWritten) { this.bytesWritten = bytesWritten; } - @ApiModelProperty("The number of FlowFiles that have been accepted in the last 5 minutes") + @Schema(description = "The number of FlowFiles that have been accepted in the last 5 minutes") public Integer getFlowFilesIn() { return flowFilesIn; } @@ -252,7 +250,7 @@ public void setFlowFilesIn(Integer flowFilesIn) { this.flowFilesIn = flowFilesIn; } - @ApiModelProperty("The size of the FlowFiles that have been accepted in the last 5 minutes") + @Schema(description = "The size of the FlowFiles that have been accepted in the last 5 minutes") public Long getBytesIn() { return bytesIn; } @@ -261,7 +259,7 @@ public void setBytesIn(Long bytesIn) { this.bytesIn = bytesIn; } - @ApiModelProperty("The number of FlowFiles transferred to a Connection in the last 5 minutes") + @Schema(description = "The number of FlowFiles transferred to a Connection in the last 5 minutes") public Integer getFlowFilesOut() { return flowFilesOut; } @@ -270,7 +268,7 @@ public void setFlowFilesOut(Integer flowFilesOut) { this.flowFilesOut = flowFilesOut; } - @ApiModelProperty("The size of the FlowFiles transferred to a Connection in the last 5 minutes") + @Schema(description = "The size of the FlowFiles transferred to a Connection in the last 5 minutes") public Long getBytesOut() { return bytesOut; } @@ -279,7 +277,7 @@ public void setBytesOut(Long bytesOut) { this.bytesOut = bytesOut; } - @ApiModelProperty("The number of times this Processor has run in the last 5 minutes") + @Schema(description = "The number of times this Processor has run in the last 5 minutes") public Integer getTaskCount() { return taskCount; } @@ -288,7 +286,7 @@ public void setTaskCount(Integer taskCount) { this.taskCount = taskCount; } - @ApiModelProperty("The number of nanoseconds that this Processor has spent running in the last 5 minutes") + @Schema(description = "The number of nanoseconds that this Processor has spent running in the last 5 minutes") public Long getTasksDurationNanos() { return tasksDurationNanos; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java index d7f640239f7d5..0ebb33c74257f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -38,7 +38,7 @@ public class RemoteProcessGroupStatusDTO { private RemoteProcessGroupStatusSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty("The unique ID of the process group that the Processor belongs to") + @Schema(description = "The unique ID of the process group that the Processor belongs to") public String getGroupId() { return groupId; } @@ -47,7 +47,7 @@ public void setGroupId(String groupId) { this.groupId = groupId; } - @ApiModelProperty("The unique ID of the Processor") + @Schema(description = "The unique ID of the Processor") public String getId() { return id; } @@ -56,7 +56,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty("The name of the remote process group.") + @Schema(description = "The name of the remote process group.") public String getName() { return name; } @@ -65,7 +65,7 @@ public void setName(String name) { this.name = name; } - @ApiModelProperty("The transmission status of the remote process group.") + @Schema(description = "The transmission status of the remote process group.") public String getTransmissionStatus() { return transmissionStatus; } @@ -74,7 +74,7 @@ public void setTransmissionStatus(String transmissionStatus) { this.transmissionStatus = transmissionStatus; } - @ApiModelProperty("The URI of the target system.") + @Schema(description = "The URI of the target system.") public String getTargetUri() { return targetUri; } @@ -83,7 +83,7 @@ public void setTargetUri(String targetUri) { this.targetUri = targetUri; } - @ApiModelProperty("A status snapshot that represents the aggregate stats of all nodes in the cluster. If the NiFi instance is " + @Schema(description = "A status snapshot that represents the aggregate stats of all nodes in the cluster. If the NiFi instance is " + "a standalone instance, rather than a cluster, this represents the stats of the single instance.") public RemoteProcessGroupStatusSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; @@ -93,7 +93,7 @@ public void setAggregateSnapshot(RemoteProcessGroupStatusSnapshotDTO aggregateSn this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("A status snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + @Schema(description = "A status snapshot for each node in the cluster. If the NiFi instance is a standalone instance, rather than " + "a cluster, this may be null.") public List getNodeSnapshots() { return nodeSnapshots; @@ -109,9 +109,8 @@ public void setNodeSnapshots(List nodeS * @return The the status was calculated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The time the status for the process group was last refreshed.", - dataType = "string" + @Schema(description = "The time the status for the process group was last refreshed.", + type = "string" ) public Date getStatsLastRefreshed() { return statsLastRefreshed; @@ -121,9 +120,9 @@ public void setStatsLastRefreshed(Date statsLastRefreshed) { this.statsLastRefreshed = statsLastRefreshed; } - @ApiModelProperty(value = "Indicates whether the component is valid, invalid, or still in the process of validating" + + @Schema(description = "Indicates whether the component is valid, invalid, or still in the process of validating" + " (i.e., it is unknown whether or not the component is valid)", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = "VALID, INVALID, VALIDATING") public String getValidationStatus() { return validationStatus; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusSnapshotDTO.java index 2c01dd4423e91..911552f3da409 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/RemoteProcessGroupStatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -44,7 +44,7 @@ public class RemoteProcessGroupStatusSnapshotDTO implements Cloneable { /** * @return The id for the remote process group */ - @ApiModelProperty("The id of the remote process group.") + @Schema(description = "The id of the remote process group.") public String getId() { return id; } @@ -56,7 +56,7 @@ public void setId(String id) { /** * @return id of the group this remote process group is in */ - @ApiModelProperty("The id of the parent process group the remote process group resides in.") + @Schema(description = "The id of the parent process group the remote process group resides in.") public String getGroupId() { return groupId; } @@ -68,7 +68,7 @@ public void setGroupId(String groupId) { /** * @return URI of the target system */ - @ApiModelProperty("The URI of the target system.") + @Schema(description = "The URI of the target system.") public String getTargetUri() { return targetUri; } @@ -80,7 +80,7 @@ public void setTargetUri(String targetUri) { /** * @return name of this remote process group */ - @ApiModelProperty("The name of the remote process group.") + @Schema(description = "The name of the remote process group.") public String getName() { return name; } @@ -92,7 +92,7 @@ public void setName(String name) { /** * @return transmission status of this remote process group */ - @ApiModelProperty("The transmission status of the remote process group.") + @Schema(description = "The transmission status of the remote process group.") public String getTransmissionStatus() { return transmissionStatus; } @@ -104,7 +104,7 @@ public void setTransmissionStatus(String transmissionStatus) { /** * @return number of active threads */ - @ApiModelProperty("The number of active threads for the remote process group.") + @Schema(description = "The number of active threads for the remote process group.") public Integer getActiveThreadCount() { return activeThreadCount; } @@ -116,7 +116,7 @@ public void setActiveThreadCount(Integer activeThreadCount) { /** * @return Formatted description of the amount of data sent to this remote process group */ - @ApiModelProperty("The count/size of the flowfiles sent to the remote process group in the last 5 minutes.") + @Schema(description = "The count/size of the flowfiles sent to the remote process group in the last 5 minutes.") public String getSent() { return sent; } @@ -129,7 +129,7 @@ public void setSent(String sent) { /** * @return Formatted description of the amount of data received from this remote process group */ - @ApiModelProperty("The count/size of the flowfiles received from the remote process group in the last 5 minutes.") + @Schema(description = "The count/size of the flowfiles received from the remote process group in the last 5 minutes.") public String getReceived() { return received; } @@ -138,7 +138,7 @@ public void setReceived(String received) { this.received = received; } - @ApiModelProperty("The number of FlowFiles sent to the remote process group in the last 5 minutes.") + @Schema(description = "The number of FlowFiles sent to the remote process group in the last 5 minutes.") public Integer getFlowFilesSent() { return flowFilesSent; } @@ -147,7 +147,7 @@ public void setFlowFilesSent(Integer flowFilesSent) { this.flowFilesSent = flowFilesSent; } - @ApiModelProperty("The size of the FlowFiles sent to the remote process group in the last 5 minutes.") + @Schema(description = "The size of the FlowFiles sent to the remote process group in the last 5 minutes.") public Long getBytesSent() { return bytesSent; } @@ -156,7 +156,7 @@ public void setBytesSent(Long bytesSent) { this.bytesSent = bytesSent; } - @ApiModelProperty("The number of FlowFiles received from the remote process group in the last 5 minutes.") + @Schema(description = "The number of FlowFiles received from the remote process group in the last 5 minutes.") public Integer getFlowFilesReceived() { return flowFilesReceived; } @@ -165,7 +165,7 @@ public void setFlowFilesReceived(Integer flowFilesReceived) { this.flowFilesReceived = flowFilesReceived; } - @ApiModelProperty("The size of the FlowFiles received from the remote process group in the last 5 minutes.") + @Schema(description = "The size of the FlowFiles received from the remote process group in the last 5 minutes.") public Long getBytesReceived() { return bytesReceived; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java index e9ee0e7a9e08e..f7c3859fb3b59 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/ReportingTaskStatusDTO.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -31,8 +31,8 @@ public class ReportingTaskStatusDTO extends ComponentStatusDTO { public static final String STOPPED = "STOPPED"; public static final String DISABLED = "DISABLED"; - @ApiModelProperty(value = "The run status of this ReportingTask", - accessMode = ApiModelProperty.AccessMode.READ_ONLY, + @Schema(description = "The run status of this ReportingTask", + accessMode = Schema.AccessMode.READ_ONLY, allowableValues = "RUNNING, STOPPED, DISABLED") @Override public String getRunStatus() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusDescriptorDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusDescriptorDTO.java index f76c89c0ed470..b6e3e4feb4163 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusDescriptorDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusDescriptorDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Objects; @@ -51,8 +51,7 @@ public StatusDescriptorDTO(final String field, final String label, final String /** * @return name of this status field */ - @ApiModelProperty( - value = "The name of the status field." + @Schema(description = "The name of the status field." ) public String getField() { return field; @@ -65,8 +64,7 @@ public void setField(String field) { /** * @return label of this status field */ - @ApiModelProperty( - value = "The label for the status field." + @Schema(description = "The label for the status field." ) public String getLabel() { return label; @@ -79,8 +77,7 @@ public void setLabel(String label) { /** * @return description of this status field */ - @ApiModelProperty( - value = "The description of the status field." + @Schema(description = "The description of the status field." ) public String getDescription() { return description; @@ -93,8 +90,7 @@ public void setDescription(String description) { /** * @return formatter for this descriptor */ - @ApiModelProperty( - value = "The formatter for the status descriptor." + @Schema(description = "The formatter for the status descriptor." ) public String getFormatter() { return formatter; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusHistoryDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusHistoryDTO.java index 87b626220b194..1763ac832a482 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusHistoryDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusHistoryDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlType; @@ -42,9 +42,8 @@ public class StatusHistoryDTO { * @return when this status history was generated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "When the status history was generated.", - dataType = "string" + @Schema(description = "When the status history was generated.", + type = "string" ) public Date getGenerated() { return generated; @@ -57,7 +56,7 @@ public void setGenerated(Date generated) { /** * @return key/value pairs that describe the component that the status history belongs to */ - @ApiModelProperty("A Map of key/value pairs that describe the component that the status history belongs to") + @Schema(description = "A Map of key/value pairs that describe the component that the status history belongs to") public LinkedHashMap getComponentDetails() { return componentDetails; } @@ -66,7 +65,7 @@ public void setComponentDetails(LinkedHashMap componentDetails) this.componentDetails = componentDetails; } - @ApiModelProperty("The Descriptors that provide information on each of the metrics provided in the status history") + @Schema(description = "The Descriptors that provide information on each of the metrics provided in the status history") public List getFieldDescriptors() { return fieldDescriptors; } @@ -75,7 +74,7 @@ public void setFieldDescriptors(List fieldDescriptors) { this.fieldDescriptors = fieldDescriptors; } - @ApiModelProperty("A list of StatusSnapshotDTO objects that provide the actual metric values for the component. If the NiFi instance " + @Schema(description = "A list of StatusSnapshotDTO objects that provide the actual metric values for the component. If the NiFi instance " + "is clustered, this will represent the aggregate status across all nodes. If the NiFi instance is not clustered, this will represent " + "the status of the entire NiFi instance.") public List getAggregateSnapshots() { @@ -86,7 +85,7 @@ public void setAggregateSnapshots(List aggregateSnapshots) { this.aggregateSnapshots = aggregateSnapshots; } - @ApiModelProperty("The NodeStatusSnapshotsDTO objects that provide the actual metric values for the component, for each node. " + @Schema(description = "The NodeStatusSnapshotsDTO objects that provide the actual metric values for the component, for each node. " + "If the NiFi instance is not clustered, this value will be null.") public List getNodeSnapshots() { return nodeSnapshots; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusSnapshotDTO.java index b10675169cb0d..003b8de20a7b8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/status/StatusSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.dto.status; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; import java.util.Date; @@ -34,8 +34,7 @@ public class StatusSnapshotDTO { /** * @return timestamp of this snapshot */ - @ApiModelProperty( - value = "The timestamp of the snapshot." + @Schema(description = "The timestamp of the snapshot." ) public Date getTimestamp() { return timestamp; @@ -48,8 +47,7 @@ public void setTimestamp(Date timestamp) { /** * @return status metrics */ - @ApiModelProperty( - value = "The status metrics." + @Schema(description = "The status metrics." ) public Map getStatusMetrics() { return statusMetrics; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/DateTimeAdapter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/DateTimeAdapter.java index 2f99f6e5ae388..07a54a95d7c85 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/DateTimeAdapter.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/DateTimeAdapter.java @@ -16,10 +16,10 @@ */ package org.apache.nifi.web.api.dto.util; -import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; import jakarta.xml.bind.annotation.adapters.XmlAdapter; @@ -28,20 +28,19 @@ */ public class DateTimeAdapter extends XmlAdapter { - public static final String DEFAULT_DATE_TIME_FORMAT = "MM/dd/yyyy HH:mm:ss z"; + private static final String DEFAULT_DATE_TIME_FORMAT = "MM/dd/yyyy HH:mm:ss z"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT); @Override public String marshal(Date date) throws Exception { - final SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.US); - formatter.setTimeZone(TimeZone.getDefault()); - return formatter.format(date); + final ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault()); + return DATE_TIME_FORMATTER.format(zonedDateTime); } @Override public Date unmarshal(String date) throws Exception { - final SimpleDateFormat parser = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.US); - parser.setTimeZone(TimeZone.getDefault()); - return parser.parse(date); + final ZonedDateTime zonedDateTime = ZonedDateTime.parse(date, DATE_TIME_FORMATTER); + return Date.from(zonedDateTime.toInstant()); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/TimestampAdapter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/TimestampAdapter.java index 78e1ba1e86fdd..a39606f24898a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/TimestampAdapter.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/util/TimestampAdapter.java @@ -16,10 +16,11 @@ */ package org.apache.nifi.web.api.dto.util; -import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; import jakarta.xml.bind.annotation.adapters.XmlAdapter; @@ -28,20 +29,18 @@ */ public class TimestampAdapter extends XmlAdapter { - public static final String DEFAULT_DATE_TIME_FORMAT = "MM/dd/yyyy HH:mm:ss.SSS z"; + private static final String DEFAULT_DATE_TIME_FORMAT = "MM/dd/yyyy HH:mm:ss.SSS z"; + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT).withZone(ZoneId.systemDefault()); @Override public String marshal(Date date) throws Exception { - final SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.US); - formatter.setTimeZone(TimeZone.getDefault()); - return formatter.format(date); + return DATE_TIME_FORMATTER.format(date.toInstant()); } @Override public Date unmarshal(String date) throws Exception { - final SimpleDateFormat parser = new SimpleDateFormat(DEFAULT_DATE_TIME_FORMAT, Locale.US); - parser.setTimeZone(TimeZone.getDefault()); - return parser.parse(date); + final ZonedDateTime dateTime = LocalDateTime.parse(date, DATE_TIME_FORMATTER).atZone(ZoneId.systemDefault()); + return Date.from(dateTime.toInstant()); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AccessPolicyEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AccessPolicyEntity.java index 0d01781d7f7a5..2558b4e5fb48b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AccessPolicyEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AccessPolicyEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.AccessPolicyDTO; import org.apache.nifi.web.api.dto.util.TimeAdapter; @@ -50,9 +50,8 @@ public void setComponent(AccessPolicyDTO component) { * @return When this content was generated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "When this content was generated.", - dataType = "string" + @Schema(description = "When this content was generated.", + type = "string" ) public Date getGenerated() { return generated; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActionEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActionEntity.java index d8863e0dd46eb..165a27d24dff9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActionEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActionEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.action.ActionDTO; import org.apache.nifi.web.api.dto.util.DateTimeAdapter; @@ -66,9 +66,8 @@ public void setId(Integer id) { * @return The timestamp of the action. */ @XmlJavaTypeAdapter(DateTimeAdapter.class) - @ApiModelProperty( - value = "The timestamp of the action.", - dataType = "string" + @Schema(description = "The timestamp of the action.", + type = "string" ) public Date getTimestamp() { return timestamp; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActivateControllerServicesEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActivateControllerServicesEntity.java index 94d94525333e9..2a9f28966b917 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActivateControllerServicesEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ActivateControllerServicesEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -32,7 +32,7 @@ public class ActivateControllerServicesEntity extends Entity { private Map components; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The id of the ProcessGroup") + @Schema(description = "The id of the ProcessGroup") public String getId() { return id; } @@ -44,7 +44,7 @@ public void setId(String id) { /** * @return The desired state of the descendant components. Possible states are 'RUNNING' and 'STOPPED' */ - @ApiModelProperty(value = "The desired state of the descendant components", + @Schema(description = "The desired state of the descendant components", allowableValues = STATE_ENABLED + ", " + STATE_DISABLED) public String getState() { return state; @@ -54,7 +54,7 @@ public void setState(String state) { this.state = state; } - @ApiModelProperty("Optional services to schedule. If not specified, all authorized descendant controller services will be used.") + @Schema(description = "Optional services to schedule. If not specified, all authorized descendant controller services will be used.") public Map getComponents() { return components; } @@ -63,8 +63,7 @@ public void setComponents(Map components) { this.components = components; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AffectedComponentEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AffectedComponentEntity.java index a2f80ee98d5e0..e4a8f145a68ce 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AffectedComponentEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/AffectedComponentEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.AffectedComponentDTO; import org.apache.nifi.web.api.dto.ProcessGroupNameDTO; @@ -47,7 +47,7 @@ public void setComponent(AffectedComponentDTO component) { this.component = component; } - @ApiModelProperty("The Process Group that the component belongs to") + @Schema(description = "The Process Group that the component belongs to") public ProcessGroupNameDTO getProcessGroup() { return processGroup; } @@ -56,7 +56,7 @@ public void setProcessGroup(ProcessGroupNameDTO processGroup) { this.processGroup = processGroup; } - @ApiModelProperty(value="The type of component referenced", + @Schema(description = "The type of component referenced", allowableValues = AffectedComponentDTO.COMPONENT_TYPE_PROCESSOR + "," + AffectedComponentDTO.COMPONENT_TYPE_CONTROLLER_SERVICE + ", " + AffectedComponentDTO.COMPONENT_TYPE_INPUT_PORT + ", " + AffectedComponentDTO.COMPONENT_TYPE_OUTPUT_PORT + ", " + AffectedComponentDTO.COMPONENT_TYPE_REMOTE_INPUT_PORT + ", " + AffectedComponentDTO.COMPONENT_TYPE_REMOTE_OUTPUT_PORT) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/BulletinEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/BulletinEntity.java index e35f24f5a73c5..435b5daefb8c5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/BulletinEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/BulletinEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.BulletinDTO; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.util.TimeAdapter; @@ -90,9 +90,8 @@ public void setSourceId(String sourceId) { * @return When this bulletin was generated. */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "When this bulletin was generated.", - dataType = "string" + @Schema(description = "When this bulletin was generated.", + type = "string" ) public Date getTimestamp() { return timestamp; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java index 35679a45352f0..f03fa9d5f2f5e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.PositionDTO; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -42,8 +42,7 @@ public class ComponentEntity extends Entity { /** * @return revision for this request/response */ - @ApiModelProperty( - value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." + @Schema(description = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." ) public RevisionDTO getRevision() { return revision; @@ -58,8 +57,7 @@ public void setRevision(RevisionDTO revision) { * * @return The id */ - @ApiModelProperty( - value = "The id of the component." + @Schema(description = "The id of the component." ) public String getId() { return this.id; @@ -74,8 +72,7 @@ public void setId(final String id) { * * @return The uri */ - @ApiModelProperty( - value = "The URI for futures requests to the component." + @Schema(description = "The URI for futures requests to the component." ) public String getUri() { return uri; @@ -90,8 +87,7 @@ public void setUri(String uri) { * * @return The position */ - @ApiModelProperty( - value = "The position of this component in the UI if applicable." + @Schema(description = "The position of this component in the UI if applicable." ) public PositionDTO getPosition() { return position; @@ -106,8 +102,7 @@ public void setPosition(PositionDTO position) { * * @return The permissions */ - @ApiModelProperty( - value = "The permissions for this component." + @Schema(description = "The permissions for this component." ) public PermissionsDTO getPermissions() { return permissions; @@ -122,8 +117,7 @@ public void setPermissions(PermissionsDTO permissions) { * * @return The bulletins */ - @ApiModelProperty( - value = "The bulletins for this component." + @Schema(description = "The bulletins for this component." ) public List getBulletins() { return bulletins; @@ -133,8 +127,7 @@ public void setBulletins(List bulletins) { this.bulletins = bulletins; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentReferenceEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentReferenceEntity.java index e3a589c7ec68e..cc0d1317a2210 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentReferenceEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentReferenceEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ComponentReferenceDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -34,8 +34,7 @@ public class ComponentReferenceEntity extends ComponentEntity { /** * @return id for the parent group of this component if applicable, null otherwise */ - @ApiModelProperty( - value = "The id of parent process group of this component if applicable." + @Schema(description = "The id of parent process group of this component if applicable." ) public String getParentGroupId() { return parentGroupId; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java index bf4145dbbd3ba..e0849654c908c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentRunStatusEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import jakarta.xml.bind.annotation.XmlType; @@ -35,8 +35,7 @@ public abstract class ComponentRunStatusEntity extends Entity { /** * @return revision for this request/response */ - @ApiModelProperty( - value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." + @Schema(description = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." ) public RevisionDTO getRevision() { return revision; @@ -49,8 +48,7 @@ public void setRevision(RevisionDTO revision) { * Run status for this component. * @return The run status */ - @ApiModelProperty( - value = "The run status of the component." + @Schema(description = "The run status of the component." ) public String getState() { return this.state; @@ -60,8 +58,7 @@ public void setState(String state) { this.state = state; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentStateEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentStateEntity.java index 0d856f58c26c2..b58d1b81bf466 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentStateEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentStateEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ComponentStateDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -34,8 +34,7 @@ public class ComponentStateEntity extends Entity { * * @return The ComponentStateDTO object */ - @ApiModelProperty( - value = "The component state." + @Schema(description = "The component state." ) public ComponentStateDTO getComponentState() { return componentState; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentValidationResultsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentValidationResultsEntity.java index c2fea0f935294..9792997ea6f91 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentValidationResultsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentValidationResultsEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; import java.util.List; @@ -25,7 +25,7 @@ public class ComponentValidationResultsEntity extends Entity { private List componentValidationResults; - @ApiModelProperty("A List of ComponentValidationResultEntity, one for each component that is validated") + @Schema(description = "A List of ComponentValidationResultEntity, one for each component that is validated") public List getValidationResults() { return componentValidationResults; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConfigurationAnalysisEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConfigurationAnalysisEntity.java index 7b395a3d31d45..8defbafd93248 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConfigurationAnalysisEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConfigurationAnalysisEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ConfigurationAnalysisDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class ConfigurationAnalysisEntity extends Entity { private ConfigurationAnalysisDTO configurationAnalysis; - @ApiModelProperty("The configuration analysis") + @Schema(description = "The configuration analysis") public ConfigurationAnalysisDTO getConfigurationAnalysis() { return configurationAnalysis; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java index 7ff12f66e22ee..bfc222847be03 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ConnectionDTO; import org.apache.nifi.web.api.dto.PositionDTO; import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO; @@ -56,8 +56,7 @@ public void setComponent(ConnectionDTO component) { /** * @return the connection status */ - @ApiModelProperty( - value = "The status of the connection." + @Schema(description = "The status of the connection." ) public ConnectionStatusDTO getStatus() { return status; @@ -70,8 +69,7 @@ public void setStatus(ConnectionStatusDTO status) { /** * @return position of the bend points on this connection */ - @ApiModelProperty( - value = "The bend points on the connection." + @Schema(description = "The bend points on the connection." ) public List getBends() { return bends; @@ -84,8 +82,7 @@ public void setBends(List bends) { /** * @return The index of control point that the connection label should be placed over */ - @ApiModelProperty( - value = "The index of the bend point where to place the connection label." + @Schema(description = "The index of the bend point where to place the connection label." ) public Integer getLabelIndex() { return labelIndex; @@ -98,8 +95,7 @@ public void setLabelIndex(Integer labelIndex) { /** * @return z index for this connection */ - @ApiModelProperty( - value = "The z index of the connection." + @Schema(description = "The z index of the connection." ) public Long getzIndex() { return zIndex; @@ -112,8 +108,7 @@ public void setzIndex(Long zIndex) { /** * @return The identifier of the source of this connection */ - @ApiModelProperty( - value = "The identifier of the source of this connection." + @Schema(description = "The identifier of the source of this connection." ) public String getSourceId() { return sourceId; @@ -126,8 +121,7 @@ public void setSourceId(String sourceId) { /** * @return The identifier of the destination of this connection */ - @ApiModelProperty( - value = "The identifier of the destination of this connection." + @Schema(description = "The identifier of the destination of this connection." ) public String getDestinationId() { return destinationId; @@ -140,8 +134,7 @@ public void setDestinationId(String destinationId) { /** * @return The identifier of the group of the source of this connection */ - @ApiModelProperty( - value = "The identifier of the group of the source of this connection." + @Schema(description = "The identifier of the group of the source of this connection." ) public String getSourceGroupId() { return sourceGroupId; @@ -154,9 +147,8 @@ public void setSourceGroupId(String sourceGroupId) { /** * @return type of this source connectable component */ - @ApiModelProperty( - value = "The type of component the source connectable is.", - required = true, + @Schema(description = "The type of component the source connectable is.", + requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = "PROCESSOR, REMOTE_INPUT_PORT, REMOTE_OUTPUT_PORT, INPUT_PORT, OUTPUT_PORT, FUNNEL" ) public String getSourceType() { @@ -170,8 +162,7 @@ public void setSourceType(String sourceType) { /** * @return The identifier of the group of the destination of this connection */ - @ApiModelProperty( - value = "The identifier of the group of the destination of this connection." + @Schema(description = "The identifier of the group of the destination of this connection." ) public String getDestinationGroupId() { return destinationGroupId; @@ -184,9 +175,8 @@ public void setDestinationGroupId(String destinationGroupId) { /** * @return type of this destination connectable component */ - @ApiModelProperty( - value = "The type of component the destination connectable is.", - required = true, + @Schema(description = "The type of component the destination connectable is.", + requiredMode = Schema.RequiredMode.REQUIRED, allowableValues = "PROCESSOR, REMOTE_INPUT_PORT, REMOTE_OUTPUT_PORT, INPUT_PORT, OUTPUT_PORT, FUNNEL" ) public String getDestinationType() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatisticsSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatisticsSnapshotEntity.java index 6f4eee50c585d..5c94067665cb2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatisticsSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatisticsSnapshotEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.status.ConnectionStatisticsSnapshotDTO; @@ -32,7 +32,7 @@ public class ConnectionStatisticsSnapshotEntity extends Entity implements Readab /** * @return The connection id */ - @ApiModelProperty("The id of the connection.") + @Schema(description = "The id of the connection.") public String getId() { return id; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatusSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatusSnapshotEntity.java index 2f6a671edef7e..5b86e855676e0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatusSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionStatusSnapshotEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.status.ConnectionStatusSnapshotDTO; @@ -31,7 +31,7 @@ public class ConnectionStatusSnapshotEntity extends Entity implements ReadablePe /** * @return The connection id */ - @ApiModelProperty("The id of the connection.") + @Schema(description = "The id of the connection.") public String getId() { return id; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerBulletinsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerBulletinsEntity.java index 5adc503440f94..4f23b9af4e461 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerBulletinsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerBulletinsEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; import java.util.ArrayList; @@ -38,7 +38,7 @@ public class ControllerBulletinsEntity extends Entity { /** * @return System bulletins to be reported to the user */ - @ApiModelProperty("System level bulletins to be reported to the user.") + @Schema(description = "System level bulletins to be reported to the user.") public List getBulletins() { return bulletins; } @@ -50,7 +50,7 @@ public void setBulletins(List bulletins) { /** * @return Controller service bulletins to be reported to the user */ - @ApiModelProperty("Controller service bulletins to be reported to the user.") + @Schema(description = "Controller service bulletins to be reported to the user.") public List getControllerServiceBulletins() { return controllerServiceBulletins; } @@ -62,7 +62,7 @@ public void setControllerServiceBulletins(List controllerService /** * @return Reporting task bulletins to be reported to the user */ - @ApiModelProperty("Reporting task bulletins to be reported to the user.") + @Schema(description = "Reporting task bulletins to be reported to the user.") public List getReportingTaskBulletins() { return reportingTaskBulletins; } @@ -74,7 +74,7 @@ public void setReportingTaskBulletins(List reportingTaskBulletin /** * @return Flow Analysis Rule bulletins to be reported to the user */ - @ApiModelProperty("Flow Analysis Rule bulletins to be reported to the user.") + @Schema(description = "Flow Analysis Rule bulletins to be reported to the user.") public List getFlowAnalysisRuleBulletins() { return flowAnalysisRuleBulletins; } @@ -86,7 +86,7 @@ public void setFlowAnalysisRuleBulletins(List flowAnalysisRuleBu /** * @return Parameter provider bulletins to be reported to the user */ - @ApiModelProperty("Parameter provider bulletins to be reported to the user.") + @Schema(description = "Parameter provider bulletins to be reported to the user.") public List getParameterProviderBulletins() { return parameterProviderBulletins; } @@ -98,7 +98,7 @@ public void setParameterProviderBulletins(List parameterProvider /** * @return Flow registry client bulletins to be reported to the user */ - @ApiModelProperty("Flow registry client bulletins to be reported to the user.") + @Schema(description = "Flow registry client bulletins to be reported to the user.") public List getFlowRegistryClientBulletins() { return flowRegistryClientBulletins; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java index 5dcb403a48816..0221d9d2ab196 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerConfigurationEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ControllerConfigurationDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -37,8 +37,7 @@ public class ControllerConfigurationEntity extends Entity implements Permissible /** * @return revision for this request/response */ - @ApiModelProperty( - value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." + @Schema(description = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." ) public RevisionDTO getRevision() { if (revision == null) { @@ -57,8 +56,7 @@ public void setRevision(RevisionDTO revision) { * * @return The ControllerConfigurationDTO object */ - @ApiModelProperty( - value = "The controller configuration." + @Schema(description = "The controller configuration." ) public ControllerConfigurationDTO getComponent() { return controllerConfiguration; @@ -73,8 +71,7 @@ public void setComponent(ControllerConfigurationDTO controllerConfiguration) { * * @return The permissions */ - @ApiModelProperty( - value = "The permissions for this component." + @Schema(description = "The permissions for this component." ) public PermissionsDTO getPermissions() { return permissions; @@ -84,8 +81,7 @@ public void setPermissions(PermissionsDTO permissions) { this.permissions = permissions; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java index 77be2ac36f2ef..3910671f8b1a6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java @@ -18,7 +18,7 @@ import jakarta.xml.bind.annotation.XmlRootElement; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ControllerServiceDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.status.ControllerServiceStatusDTO; @@ -37,8 +37,7 @@ public class ControllerServiceEntity extends ComponentEntity implements Permissi /** * @return The id for the parent group of this ControllerService */ - @ApiModelProperty( - value = "The id of parent process group of this ControllerService." + @Schema(description = "The id of parent process group of this ControllerService." ) public String getParentGroupId() { return parentGroupId; @@ -62,8 +61,7 @@ public void setComponent(ControllerServiceDTO component) { /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { @@ -78,9 +76,8 @@ public void setOperatePermissions(PermissionsDTO permissions) { /** * @return The status for this ControllerService */ - @ApiModelProperty( - value = "The status for this ControllerService.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The status for this ControllerService.", + accessMode = Schema.AccessMode.READ_ONLY ) public ControllerServiceStatusDTO getStatus() { return status; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java index d120f19692d51..647e57ee35d8a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceReferencingComponentEntity.java @@ -19,7 +19,7 @@ import jakarta.xml.bind.annotation.XmlRootElement; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; @@ -47,8 +47,7 @@ public void setComponent(ControllerServiceReferencingComponentDTO component) { /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java index f090af4d0dc81..6110055bf1d93 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceRunStatusEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -38,17 +38,18 @@ protected String[] getSupportedState() { * Run status for this ControllerService. * @return The run status */ - @ApiModelProperty( - value = "The run status of the ControllerService.", + @Schema(description = "The run status of the ControllerService.", allowableValues = "ENABLED, DISABLED" ) public String getState() { return super.getState(); } - @ApiModelProperty( - value = "Indicates whether or not responses should only include fields necessary for rendering the NiFi User Interface. As such, when this value is set to true, some fields may be " + - "returned as null values, and the selected fields may change at any time without notice. As a result, this value should not be set to true by any client other than the UI." + @Schema(description = """ + Indicates whether or not responses should only include fields necessary for rendering the NiFi User Interface. + As such, when this value is set to true, some fields may be returned as null values, and the selected fields may change at any time without notice. + As a result, this value should not be set to true by any client other than the UI. + """ ) public Boolean getUiOnly() { return uiOnly; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java index 0c4904a597866..139f2e00bc051 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServicesEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlRootElement; @@ -48,9 +48,8 @@ public void setControllerServices(Set controllerService * @return current time on the server */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The current time on the system.", - dataType = "string" + @Schema(description = "The current time on the system.", + type = "string" ) public Date getCurrentTime() { return currentTime; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CopySnippetRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CopySnippetRequestEntity.java index 53dddf50e5449..3c228d1158944 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CopySnippetRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CopySnippetRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; @@ -31,8 +31,7 @@ public class CopySnippetRequestEntity extends Entity { private Double originY; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty( - value = "The identifier of the snippet." + @Schema(description = "The identifier of the snippet." ) public String getSnippetId() { return snippetId; @@ -42,8 +41,7 @@ public void setSnippetId(String snippetId) { this.snippetId = snippetId; } - @ApiModelProperty( - value = "The x coordinate of the origin of the bounding box where the new components will be placed." + @Schema(description = "The x coordinate of the origin of the bounding box where the new components will be placed." ) public Double getOriginX() { return originX; @@ -53,8 +51,7 @@ public void setOriginX(Double originX) { this.originX = originX; } - @ApiModelProperty( - value = "The y coordinate of the origin of the bounding box where the new components will be placed." + @Schema(description = "The y coordinate of the origin of the bounding box where the new components will be placed." ) public Double getOriginY() { return originY; @@ -64,8 +61,7 @@ public void setOriginY(Double originY) { this.originY = originY; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CreateActiveRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CreateActiveRequestEntity.java index 4e0c3144bf49c..78837d6e58bd3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CreateActiveRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CreateActiveRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class CreateActiveRequestEntity extends Entity { private String processGroupId; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The Process Group ID that this active request will update") + @Schema(description = "The Process Group ID that this active request will update") public String getProcessGroupId() { return processGroupId; } @@ -35,8 +35,7 @@ public void setProcessGroupId(String processGroupId) { this.processGroupId = processGroupId; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CurrentUserEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CurrentUserEntity.java index 5a54639840b47..739575d1f5bbd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CurrentUserEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/CurrentUserEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ComponentRestrictionPermissionDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; @@ -47,7 +47,7 @@ public class CurrentUserEntity extends Entity { /** * @return the user identity being serialized */ - @ApiModelProperty("The user identity being serialized.") + @Schema(description = "The user identity being serialized.") public String getIdentity() { return identity; } @@ -59,7 +59,7 @@ public void setIdentity(String identity) { /** * @return if the user is anonymous */ - @ApiModelProperty("Whether the current user is anonymous.") + @Schema(description = "Whether the current user is anonymous.") public boolean isAnonymous() { return anonymous; } @@ -71,7 +71,7 @@ public void setAnonymous(boolean anonymous) { /** * @return if the use can query provenance */ - @ApiModelProperty("Permissions for querying provenance.") + @Schema(description = "Permissions for querying provenance.") public PermissionsDTO getProvenancePermissions() { return provenancePermissions; } @@ -83,7 +83,7 @@ public void setProvenancePermissions(PermissionsDTO provenancePermissions) { /** * @return permissions for accessing counters */ - @ApiModelProperty("Permissions for accessing counters.") + @Schema(description = "Permissions for accessing counters.") public PermissionsDTO getCountersPermissions() { return countersPermissions; } @@ -95,7 +95,7 @@ public void setCountersPermissions(PermissionsDTO countersPermissions) { /** * @return permissions for accessing users */ - @ApiModelProperty("Permissions for accessing tenants.") + @Schema(description = "Permissions for accessing tenants.") public PermissionsDTO getTenantsPermissions() { return tenantsPermissions; } @@ -107,7 +107,7 @@ public void setTenantsPermissions(PermissionsDTO tenantsPermissions) { /** * @return permissions for accessing the controller */ - @ApiModelProperty("Permissions for accessing the controller.") + @Schema(description = "Permissions for accessing the controller.") public PermissionsDTO getControllerPermissions() { return controllerPermissions; } @@ -119,7 +119,7 @@ public void setControllerPermissions(PermissionsDTO controllerPermissions) { /** * @return permissions for accessing the all policies */ - @ApiModelProperty("Permissions for accessing the policies.") + @Schema(description = "Permissions for accessing the policies.") public PermissionsDTO getPoliciesPermissions() { return policiesPermissions; } @@ -131,7 +131,7 @@ public void setPoliciesPermissions(PermissionsDTO policiesPermissions) { /** * @return permissions for accessing the system */ - @ApiModelProperty("Permissions for accessing system.") + @Schema(description = "Permissions for accessing system.") public PermissionsDTO getSystemPermissions() { return systemPermissions; } @@ -143,7 +143,7 @@ public void setSystemPermissions(PermissionsDTO systemPermissions) { /** * @return permissions for accessing parameter contexts */ - @ApiModelProperty("Permissions for accessing parameter contexts.") + @Schema(description = "Permissions for accessing parameter contexts.") public PermissionsDTO getParameterContextPermissions() { return parameterContextPermissions; } @@ -155,7 +155,7 @@ public void setParameterContextPermissions(PermissionsDTO parameterContextPermis /** * @return permissions for accessing the restricted components */ - @ApiModelProperty("Permissions for accessing restricted components. Note: the read permission are not used and will always be false.") + @Schema(description = "Permissions for accessing restricted components. Note: the read permission are not used and will always be false.") public PermissionsDTO getRestrictedComponentsPermissions() { return restrictedComponentsPermissions; } @@ -167,7 +167,7 @@ public void setRestrictedComponentsPermissions(PermissionsDTO restrictedComponen /** * @return permissions for specific component restrictions */ - @ApiModelProperty("Permissions for specific component restrictions.") + @Schema(description = "Permissions for specific component restrictions.") public Set getComponentRestrictionPermissions() { return componentRestrictionPermissions; } @@ -179,7 +179,7 @@ public void setComponentRestrictionPermissions(Set flowAnalysisRules; /** @@ -38,4 +44,20 @@ public void setFlowAnalysisRules(Set flowAnalysisRules) this.flowAnalysisRules = flowAnalysisRules; } + /** + * @return current time on the server + */ + @XmlJavaTypeAdapter(TimeAdapter.class) + @Schema( + description = "The current time on the system.", + type = "string" + ) + public Date getCurrentTime() { + return currentTime; + } + + public void setCurrentTime(Date currentTime) { + this.currentTime = currentTime; + } + } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowBreadcrumbEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowBreadcrumbEntity.java index fa9a6992c6c30..d31b796b615ca 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowBreadcrumbEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowBreadcrumbEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.flow.FlowBreadcrumbDTO; @@ -39,8 +39,7 @@ public class FlowBreadcrumbEntity extends Entity { * * @return The id */ - @ApiModelProperty( - value = "The id of this ancestor ProcessGroup." + @Schema(description = "The id of this ancestor ProcessGroup." ) public String getId() { return id; @@ -55,8 +54,7 @@ public void setId(String id) { * * @return The permissions */ - @ApiModelProperty( - value = "The permissions for this ancestor ProcessGroup." + @Schema(description = "The permissions for this ancestor ProcessGroup." ) public PermissionsDTO getPermissions() { return permissions; @@ -71,8 +69,7 @@ public void setPermissions(PermissionsDTO permissions) { * * @return The FlowBreadcrumbDTO object */ - @ApiModelProperty( - value = "This breadcrumb." + @Schema(description = "This breadcrumb." ) public FlowBreadcrumbDTO getBreadcrumb() { return breadcrumb; @@ -87,8 +84,7 @@ public void setBreadcrumb(FlowBreadcrumbDTO breadcrumb) { * * @return The parent breadcrumb for this breadcrumb */ - @ApiModelProperty( - value = "The parent breadcrumb for this breadcrumb." + @Schema(description = "The parent breadcrumb for this breadcrumb." ) public FlowBreadcrumbEntity getParentBreadcrumb() { return parentBreadcrumb; @@ -98,9 +94,11 @@ public void setParentBreadcrumb(FlowBreadcrumbEntity parentBreadcrumb) { this.parentBreadcrumb = parentBreadcrumb; } - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY, - value = "The current state of the Process Group, as it relates to the Versioned Flow", - allowableValues = "LOCALLY_MODIFIED, STALE, LOCALLY_MODIFIED_AND_STALE, UP_TO_DATE, SYNC_FAILURE") + @Schema( + description = "The current state of the Process Group, as it relates to the Versioned Flow", + allowableValues = "LOCALLY_MODIFIED, STALE, LOCALLY_MODIFIED_AND_STALE, UP_TO_DATE, SYNC_FAILURE", + accessMode = Schema.AccessMode.READ_ONLY + ) public String getVersionedFlowState() { return versionedFlowState; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowComparisonEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowComparisonEntity.java index 1c9539b1bfedd..5fe4b7e851c62 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowComparisonEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowComparisonEntity.java @@ -23,13 +23,13 @@ import org.apache.nifi.web.api.dto.ComponentDifferenceDTO; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlRootElement(name = "flowComparisonEntity") public class FlowComparisonEntity extends Entity { private Set componentDifferences; - @ApiModelProperty("The list of differences for each component in the flow that is not the same between the two flows") + @Schema(description = "The list of differences for each component in the flow that is not the same between the two flows") public Set getComponentDifferences() { return componentDifferences; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java index b87af2f5008ff..802471df67a1a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowConfigurationEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.FlowConfigurationDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -34,8 +34,7 @@ public class FlowConfigurationEntity extends Entity { * * @return The FlowConfigurationDTO object */ - @ApiModelProperty( - value = "The controller configuration." + @Schema(description = "The controller configuration." ) public FlowConfigurationDTO getFlowConfiguration() { return flowConfiguration; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowRegistryClientsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowRegistryClientsEntity.java index 2031fd2559525..49ba0ff1731e5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowRegistryClientsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowRegistryClientsEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlRootElement; @@ -48,9 +48,8 @@ public void setRegistries(Set registries) { * @return current time on the server */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The current time on the system.", - dataType = "string" + @Schema(description = "The current time on the system.", + type = "string" ) public Date getCurrentTime() { return currentTime; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowUpdateRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowUpdateRequestEntity.java index cb2df23789357..719d6803c8b03 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowUpdateRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowUpdateRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.FlowUpdateRequestDTO; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -25,7 +25,7 @@ public abstract class FlowUpdateRequestEntity ex protected RevisionDTO processGroupRevision; protected T request; - @ApiModelProperty("The revision for the Process Group being updated.") + @Schema(description = "The revision for the Process Group being updated.") public RevisionDTO getProcessGroupRevision() { return processGroupRevision; } @@ -34,7 +34,7 @@ public void setProcessGroupRevision(RevisionDTO revision) { this.processGroupRevision = revision; } - @ApiModelProperty("The Process Group Update Request") + @Schema(description = "The Process Group Update Request") public abstract T getRequest(); public abstract void setRequest(T request); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java index d694b5f53ac8f..b94165e4f69f7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.DimensionsDTO; import org.apache.nifi.web.api.dto.LabelDTO; @@ -61,8 +61,7 @@ public void setDimensions(DimensionsDTO dimensions) { /** * @return z index for this label */ - @ApiModelProperty( - value = "The z index of the label." + @Schema(description = "The z index of the label." ) public Long getzIndex() { return zIndex; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/NodeReplayLastEventSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/NodeReplayLastEventSnapshotDTO.java index c4bbda710eeed..859a79eb8bde9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/NodeReplayLastEventSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/NodeReplayLastEventSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; @@ -27,7 +27,7 @@ public class NodeReplayLastEventSnapshotDTO { private Integer apiPort; private ReplayLastEventSnapshotDTO snapshot; - @ApiModelProperty("The unique ID that identifies the node") + @Schema(description = "The unique ID that identifies the node") public String getNodeId() { return nodeId; } @@ -36,7 +36,7 @@ public void setNodeId(String nodeId) { this.nodeId = nodeId; } - @ApiModelProperty("The API address of the node") + @Schema(description = "The API address of the node") public String getAddress() { return address; } @@ -45,7 +45,7 @@ public void setAddress(String address) { this.address = address; } - @ApiModelProperty("The API port used to communicate with the node") + @Schema(description = "The API port used to communicate with the node") public Integer getApiPort() { return apiPort; } @@ -54,7 +54,7 @@ public void setApiPort(Integer apiPort) { this.apiPort = apiPort; } - @ApiModelProperty("The snapshot from the node") + @Schema(description = "The snapshot from the node") public ReplayLastEventSnapshotDTO getSnapshot() { return snapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextEntity.java index 34c736a1ea7e2..ce60bcd253b97 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterContextDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -25,7 +25,7 @@ public class ParameterContextEntity extends ComponentEntity { private ParameterContextDTO parameterContextDTO; - @ApiModelProperty("The Parameter Context") + @Schema(description = "The Parameter Context") public ParameterContextDTO getComponent() { return parameterContextDTO; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextReferenceEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextReferenceEntity.java index ed1ef33193bec..d0f84108602ef 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextReferenceEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextReferenceEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterContextReferenceDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; @@ -37,8 +37,7 @@ public class ParameterContextReferenceEntity implements Permissible referencingComponents; - @ApiModelProperty("The Revision of the Parameter Context") + @Schema(description = "The Revision of the Parameter Context") public RevisionDTO getParameterContextRevision() { return parameterContextRevision; } @@ -38,8 +38,8 @@ public void setParameterContextRevision(final RevisionDTO parameterContextRevisi this.parameterContextRevision = parameterContextRevision; } - @ApiModelProperty(value = "The Parameter Context that is being operated on. This may not be populated until the request has successfully completed.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The Parameter Context that is being operated on. This may not be populated until the request has successfully completed.", + accessMode = Schema.AccessMode.READ_ONLY) public ParameterContextDTO getParameterContext() { return parameterContext; } @@ -48,7 +48,7 @@ public void setParameterContext(final ParameterContextDTO parameterContext) { this.parameterContext = parameterContext; } - @ApiModelProperty(value = "The components that are referenced by the update.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "The components that are referenced by the update.", accessMode = Schema.AccessMode.READ_ONLY) public Set getReferencingComponents() { return referencingComponents; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextUpdateRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextUpdateRequestEntity.java index c3bcbf0d73a5b..52c09a79185fe 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextUpdateRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextUpdateRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterContextUpdateRequestDTO; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -27,7 +27,7 @@ public class ParameterContextUpdateRequestEntity extends Entity { private RevisionDTO parameterContextRevision; private ParameterContextUpdateRequestDTO request; - @ApiModelProperty("The Revision of the Parameter Context") + @Schema(description = "The Revision of the Parameter Context") public RevisionDTO getParameterContextRevision() { return parameterContextRevision; } @@ -36,7 +36,7 @@ public void setParameterContextRevision(final RevisionDTO parameterContextRevisi this.parameterContextRevision = parameterContextRevision; } - @ApiModelProperty("The Update Request") + @Schema(description = "The Update Request") public ParameterContextUpdateRequestDTO getRequest() { return request; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextValidationRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextValidationRequestEntity.java index eedee79006096..4a2fcc9326915 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextValidationRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextValidationRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterContextValidationRequestDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class ParameterContextValidationRequestEntity extends Entity { private ParameterContextValidationRequestDTO request; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The Update Request") + @Schema(description = "The Update Request") public ParameterContextValidationRequestDTO getRequest() { return request; } @@ -35,7 +35,7 @@ public void setRequest(final ParameterContextValidationRequestDTO request) { this.request = request; } - @ApiModelProperty("Acknowledges that this node is disconnected to allow for mutable requests to proceed.") + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed.") public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextsEntity.java index 0c66dd2b99eb3..08ee5b3f2da9a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterContextsEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlRootElement; @@ -29,7 +29,7 @@ public class ParameterContextsEntity extends Entity { private Set parameterContexts; private Date currentTime; - @ApiModelProperty("The Parameter Contexts") + @Schema(description = "The Parameter Contexts") public Set getParameterContexts() { return parameterContexts; } @@ -39,10 +39,9 @@ public void setParameterContexts(final Set parameterCont } @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The current time on the system.", - dataType = "string", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The current time on the system.", + type = "string", + accessMode = Schema.AccessMode.READ_ONLY ) public Date getCurrentTime() { return currentTime; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterEntity.java index e877c77b82990..5181f4da7553b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterDTO; import org.apache.nifi.web.api.dto.WritablePermission; @@ -27,7 +27,7 @@ public class ParameterEntity extends Entity implements WritablePermission { private Boolean canWrite; private ParameterDTO parameter; - @ApiModelProperty("The parameter information") + @Schema(description = "The parameter information") public ParameterDTO getParameter() { return parameter; } @@ -37,7 +37,7 @@ public void setParameter(final ParameterDTO parameter) { } @Override - @ApiModelProperty(value = "Indicates whether the user can write a given resource.", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Indicates whether the user can write a given resource.", accessMode = Schema.AccessMode.READ_ONLY) public Boolean getCanWrite() { return canWrite; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterGroupConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterGroupConfigurationEntity.java index 7bfe04ff1b904..1a546f83bd764 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterGroupConfigurationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterGroupConfigurationEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.parameter.ParameterSensitivity; import jakarta.xml.bind.annotation.XmlType; @@ -33,8 +33,7 @@ public class ParameterGroupConfigurationEntity extends Entity implements Compara private Boolean isSynchronized; private Map parameterSensitivities; - @ApiModelProperty( - value = "The name of the external parameter group to which the provided parameter names apply." + @Schema(description = "The name of the external parameter group to which the provided parameter names apply." ) public String getGroupName() { return groupName; @@ -44,8 +43,7 @@ public void setGroupName(final String groupName) { this.groupName = groupName; } - @ApiModelProperty( - value = "The name of the ParameterContext that receives the parameters in this group" + @Schema(description = "The name of the ParameterContext that receives the parameters in this group" ) public String getParameterContextName() { return parameterContextName; @@ -58,8 +56,7 @@ public void setParameterContextName(final String parameterContextName) { /** * @return All fetched parameter names that should be applied. */ - @ApiModelProperty( - value = "All fetched parameter names that should be applied." + @Schema(description = "All fetched parameter names that should be applied." ) public Map getParameterSensitivities() { return parameterSensitivities; @@ -69,8 +66,7 @@ public void setParameterSensitivities(Map paramete this.parameterSensitivities = parameterSensitivities; } - @ApiModelProperty( - value = "True if this group should be synchronized to a ParameterContext, including creating one if it does not exist." + @Schema(description = "True if this group should be synchronized to a ParameterContext, including creating one if it does not exist." ) public Boolean isSynchronized() { return isSynchronized; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderApplyParametersRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderApplyParametersRequestEntity.java index a73448925daf2..db2c225ca6e00 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderApplyParametersRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderApplyParametersRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterProviderApplyParametersRequestDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -25,7 +25,7 @@ public class ParameterProviderApplyParametersRequestEntity extends Entity { private ParameterProviderApplyParametersRequestDTO request; - @ApiModelProperty("The Apply Parameters Request") + @Schema(description = "The Apply Parameters Request") public ParameterProviderApplyParametersRequestDTO getRequest() { return request; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderConfigurationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderConfigurationEntity.java index 9796da1b7b332..e36a14ecd0005 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderConfigurationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderConfigurationEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterProviderConfigurationDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; @@ -38,8 +38,7 @@ public class ParameterProviderConfigurationEntity implements Permissible parameterGroupConfigurations; - @ApiModelProperty( - value = "The id of the parameter provider." + @Schema(description = "The id of the parameter provider." ) public String getId() { return id; @@ -47,8 +46,7 @@ public void setId(final String id) { /** * @return revision for this request/response */ - @ApiModelProperty( - value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." + @Schema(description = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." ) public RevisionDTO getRevision() { return revision; @@ -58,8 +56,7 @@ public void setRevision(final RevisionDTO revision) { this.revision = revision; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; @@ -72,8 +69,7 @@ public void setDisconnectedNodeAcknowledged(final Boolean disconnectedNodeAcknow /** * @return Specifies per group which parameter names should be applied to the Parameter Contexts. */ - @ApiModelProperty( - value = "Configuration for the fetched Parameter Groups" + @Schema(description = "Configuration for the fetched Parameter Groups" ) public Collection getParameterGroupConfigurations() { return parameterGroupConfigurations; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderParameterFetchEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderParameterFetchEntity.java index e034ad49c4ca1..f1eaf9802f61a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderParameterFetchEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderParameterFetchEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import jakarta.xml.bind.annotation.XmlType; @@ -31,8 +31,7 @@ public class ParameterProviderParameterFetchEntity extends Entity { private RevisionDTO revision; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty( - value = "The id of the parameter provider." + @Schema(description = "The id of the parameter provider." ) public String getId() { return id; @@ -45,8 +44,7 @@ public void setId(final String id) { /** * @return revision for this request/response */ - @ApiModelProperty( - value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." + @Schema(description = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses." ) public RevisionDTO getRevision() { return revision; @@ -56,8 +54,7 @@ public void setRevision(final RevisionDTO revision) { this.revision = revision; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderReferencingComponentEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderReferencingComponentEntity.java index 4bf122a1511ff..aed4e7fe1ea03 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderReferencingComponentEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ParameterProviderReferencingComponentEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ParameterProviderReferencingComponentDTO; import org.apache.nifi.web.api.dto.PermissionsDTO; @@ -47,8 +47,7 @@ public void setComponent(ParameterProviderReferencingComponentDTO component) { /** * @return The permissions for this component */ - @ApiModelProperty( - value = "The permissions for this component." + @Schema(description = "The permissions for this component." ) @Override public PermissionsDTO getPermissions() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java index 6e05655326e5d..dd31dc591749f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.PortDTO; import org.apache.nifi.web.api.dto.status.PortStatusDTO; @@ -51,8 +51,7 @@ public void setComponent(PortDTO component) { /** * @return the port status */ - @ApiModelProperty( - value = "The status of the port." + @Schema(description = "The status of the port." ) public PortStatusDTO getStatus() { return status; @@ -73,8 +72,7 @@ public void setPortType(String portType) { /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { @@ -89,8 +87,7 @@ public void setOperatePermissions(PermissionsDTO permissions) { /** * @return whether this port can be accessed remotely via Site-to-Site protocol. */ - @ApiModelProperty( - value = "Whether this port can be accessed remotely via Site-to-Site protocol." + @Schema(description = "Whether this port can be accessed remotely via Site-to-Site protocol." ) public Boolean isAllowRemoteAccess() { return allowRemoteAccess; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java index c1a451cb103aa..106727dfa303a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortRunStatusEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -37,8 +37,7 @@ protected String[] getSupportedState() { * Run status for this Port. * @return The run status */ - @ApiModelProperty( - value = "The run status of the Port.", + @Schema(description = "The run status of the Port.", allowableValues = "RUNNING, STOPPED, DISABLED" ) public String getState() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortStatusSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortStatusSnapshotEntity.java index 2628e3be8a75b..7d4676c9e091e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortStatusSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortStatusSnapshotEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.status.PortStatusSnapshotDTO; @@ -32,7 +32,7 @@ public class PortStatusSnapshotEntity extends Entity implements ReadablePermissi /** * @return The port id */ - @ApiModelProperty("The id of the port.") + @Schema(description = "The id of the port.") public String getId() { return id; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupDescriptorEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupDescriptorEntity.java index b7116e31d4a09..c0e34b4c462a2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupDescriptorEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupDescriptorEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; /** @@ -28,7 +28,7 @@ public abstract class ProcessGroupDescriptorEntity extends Entity { private RevisionDTO processGroupRevision; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The Revision for the Process Group") + @Schema(description = "The Revision for the Process Group") public RevisionDTO getProcessGroupRevision() { return processGroupRevision; } @@ -37,8 +37,7 @@ public void setProcessGroupRevision(RevisionDTO revision) { this.processGroupRevision = revision; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java index 172b9c97fb7e0..cd5f452d400f4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.registry.flow.RegisteredFlowSnapshot; import org.apache.nifi.web.api.dto.ProcessGroupDTO; import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO; @@ -76,8 +76,7 @@ public void setComponent(ProcessGroupDTO component) { /** * @return the process group status */ - @ApiModelProperty( - value = "The status of the process group." + @Schema(description = "The status of the process group." ) public ProcessGroupStatusDTO getStatus() { return status; @@ -90,9 +89,8 @@ public void setStatus(ProcessGroupStatusDTO status) { /** * @return number of input ports contained in this process group */ - @ApiModelProperty( - value = "The number of input ports in the process group.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The number of input ports in the process group.", + accessMode = Schema.AccessMode.READ_ONLY ) public Integer getInputPortCount() { return NumberUtil.sumNullableIntegers(localInputPortCount, publicInputPortCount); @@ -105,8 +103,7 @@ public void setInputPortCount(Integer inputPortCount) { /** * @return number of local input ports contained in this process group */ - @ApiModelProperty( - value = "The number of local input ports in the process group." + @Schema(description = "The number of local input ports in the process group." ) public Integer getLocalInputPortCount() { return localInputPortCount; @@ -119,8 +116,7 @@ public void setLocalInputPortCount(Integer localInputPortCount) { /** * @return number of public input ports contained in this process group */ - @ApiModelProperty( - value = "The number of public input ports in the process group." + @Schema(description = "The number of public input ports in the process group." ) public Integer getPublicInputPortCount() { return publicInputPortCount; @@ -133,8 +129,7 @@ public void setPublicInputPortCount(Integer publicInputPortCount) { /** * @return number of invalid components in this process group */ - @ApiModelProperty( - value = "The number of invalid components in the process group." + @Schema(description = "The number of invalid components in the process group." ) public Integer getInvalidCount() { return invalidCount; @@ -147,9 +142,8 @@ public void setInvalidCount(Integer invalidCount) { /** * @return number of output ports in this process group */ - @ApiModelProperty( - value = "The number of output ports in the process group.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The number of output ports in the process group.", + accessMode = Schema.AccessMode.READ_ONLY ) public Integer getOutputPortCount() { return NumberUtil.sumNullableIntegers(localOutputPortCount, publicOutputPortCount); @@ -162,8 +156,7 @@ public void setOutputPortCount(Integer outputPortCount) { /** * @return number of local output ports in this process group */ - @ApiModelProperty( - value = "The number of local output ports in the process group." + @Schema(description = "The number of local output ports in the process group." ) public Integer getLocalOutputPortCount() { return localOutputPortCount; @@ -176,8 +169,7 @@ public void setLocalOutputPortCount(Integer localOutputPortCount) { /** * @return number of public output ports in this process group */ - @ApiModelProperty( - value = "The number of public output ports in the process group." + @Schema(description = "The number of public output ports in the process group." ) public Integer getPublicOutputPortCount() { return publicOutputPortCount; @@ -190,8 +182,7 @@ public void setPublicOutputPortCount(Integer publicOutputPortCount) { /** * @return number of running component in this process group */ - @ApiModelProperty( - value = "The number of running components in this process group." + @Schema(description = "The number of running components in this process group." ) public Integer getRunningCount() { return runningCount; @@ -204,8 +195,7 @@ public void setRunningCount(Integer runningCount) { /** * @return number of stopped components in this process group */ - @ApiModelProperty( - value = "The number of stopped components in the process group." + @Schema(description = "The number of stopped components in the process group." ) public Integer getStoppedCount() { return stoppedCount; @@ -218,8 +208,7 @@ public void setStoppedCount(Integer stoppedCount) { /** * @return number of disabled components in this process group */ - @ApiModelProperty( - value = "The number of disabled components in the process group." + @Schema(description = "The number of disabled components in the process group." ) public Integer getDisabledCount() { return disabledCount; @@ -232,8 +221,7 @@ public void setDisabledCount(Integer disabledCount) { /** * @return number of active remote ports in this process group */ - @ApiModelProperty( - value = "The number of active remote ports in the process group." + @Schema(description = "The number of active remote ports in the process group." ) public Integer getActiveRemotePortCount() { return activeRemotePortCount; @@ -246,8 +234,7 @@ public void setActiveRemotePortCount(Integer activeRemotePortCount) { /** * @return number of inactive remote ports in this process group */ - @ApiModelProperty( - value = "The number of inactive remote ports in the process group." + @Schema(description = "The number of inactive remote ports in the process group." ) public Integer getInactiveRemotePortCount() { return inactiveRemotePortCount; @@ -257,7 +244,7 @@ public void setInactiveRemotePortCount(Integer inactiveRemotePortCount) { this.inactiveRemotePortCount = inactiveRemotePortCount; } - @ApiModelProperty(value = "Returns the Versioned Flow that describes the contents of the Versioned Flow to be imported", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Returns the Versioned Flow that describes the contents of the Versioned Flow to be imported", accessMode = Schema.AccessMode.READ_ONLY) public RegisteredFlowSnapshot getVersionedFlowSnapshot() { return versionedFlowSnapshot; } @@ -266,9 +253,11 @@ public void setVersionedFlowSnapshot(RegisteredFlowSnapshot versionedFlowSnapsho this.versionedFlowSnapshot = versionedFlowSnapshot; } - @ApiModelProperty(accessMode = ApiModelProperty.AccessMode.READ_ONLY, - value = "The current state of the Process Group, as it relates to the Versioned Flow", - allowableValues = "LOCALLY_MODIFIED, STALE, LOCALLY_MODIFIED_AND_STALE, UP_TO_DATE, SYNC_FAILURE") + @Schema( + description = "The current state of the Process Group, as it relates to the Versioned Flow", + allowableValues = "LOCALLY_MODIFIED, STALE, LOCALLY_MODIFIED_AND_STALE, UP_TO_DATE, SYNC_FAILURE", + accessMode = Schema.AccessMode.READ_ONLY + ) public String getVersionedFlowState() { return versionedFlowState; } @@ -277,7 +266,7 @@ public void setVersionedFlowState(String versionedFlowState) { this.versionedFlowState = versionedFlowState; } - @ApiModelProperty("The number of up to date versioned process groups in the process group.") + @Schema(description = "The number of up to date versioned process groups in the process group.") public Integer getUpToDateCount() { return upToDateCount; } @@ -286,7 +275,7 @@ public void setUpToDateCount(Integer upToDateCount) { this.upToDateCount = upToDateCount; } - @ApiModelProperty("The number of locally modified versioned process groups in the process group.") + @Schema(description = "The number of locally modified versioned process groups in the process group.") public Integer getLocallyModifiedCount() { return locallyModifiedCount; } @@ -295,7 +284,7 @@ public void setLocallyModifiedCount(Integer locallyModifiedCount) { this.locallyModifiedCount = locallyModifiedCount; } - @ApiModelProperty("The number of stale versioned process groups in the process group.") + @Schema(description = "The number of stale versioned process groups in the process group.") public Integer getStaleCount() { return staleCount; } @@ -304,7 +293,7 @@ public void setStaleCount(Integer staleCount) { this.staleCount = staleCount; } - @ApiModelProperty("The number of locally modified and stale versioned process groups in the process group.") + @Schema(description = "The number of locally modified and stale versioned process groups in the process group.") public Integer getLocallyModifiedAndStaleCount() { return locallyModifiedAndStaleCount; } @@ -313,7 +302,7 @@ public void setLocallyModifiedAndStaleCount(Integer locallyModifiedAndStaleCount this.locallyModifiedAndStaleCount = locallyModifiedAndStaleCount; } - @ApiModelProperty("The number of versioned process groups in the process group that are unable to sync to a registry.") + @Schema(description = "The number of versioned process groups in the process group that are unable to sync to a registry.") public Integer getSyncFailureCount() { return syncFailureCount; } @@ -322,7 +311,7 @@ public void setSyncFailureCount(Integer syncFailureCount) { this.syncFailureCount = syncFailureCount; } - @ApiModelProperty("The Parameter Context, or null if no Parameter Context has been bound to the Process Group") + @Schema(description = "The Parameter Context, or null if no Parameter Context has been bound to the Process Group") public ParameterContextReferenceEntity getParameterContext() { return parameterContext; } @@ -331,8 +320,7 @@ public void setParameterContext(ParameterContextReferenceEntity parameterContext this.parameterContext = parameterContext; } - @ApiModelProperty( - value = "Determines the process group update strategy", + @Schema(description = "Determines the process group update strategy", allowableValues = "CURRENT_GROUP, CURRENT_GROUP_WITH_CHILDREN" ) public String getProcessGroupUpdateStrategy() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java index 02638cb9dc9cd..c98ba4b362efc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO; @@ -36,8 +36,7 @@ public class ProcessGroupFlowEntity extends Entity { * * @return The permissions */ - @ApiModelProperty( - value = "The access policy for this process group." + @Schema(description = "The access policy for this process group." ) public PermissionsDTO getPermissions() { return permissions; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupImportEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupImportEntity.java index 85afde07db0c4..224e6d5832797 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupImportEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupImportEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.registry.flow.RegisteredFlowSnapshot; import jakarta.xml.bind.annotation.XmlRootElement; @@ -29,7 +29,7 @@ public class ProcessGroupImportEntity extends ProcessGroupDescriptorEntity { private RegisteredFlowSnapshot versionedFlowSnapshot; - @ApiModelProperty("The Versioned Flow Snapshot to import") + @Schema(description = "The Versioned Flow Snapshot to import") public RegisteredFlowSnapshot getVersionedFlowSnapshot() { return versionedFlowSnapshot; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupReplaceRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupReplaceRequestEntity.java index 26ace61b767dc..109f873b40ae3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupReplaceRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupReplaceRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.registry.flow.RegisteredFlowSnapshot; import org.apache.nifi.web.api.dto.ProcessGroupReplaceRequestDTO; @@ -30,7 +30,7 @@ public class ProcessGroupReplaceRequestEntity extends FlowUpdateRequestEntity { private RegisteredFlowSnapshot versionedFlowSnapshot; - @ApiModelProperty(value = "Returns the Versioned Flow to replace with", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @Schema(description = "Returns the Versioned Flow to replace with", accessMode = Schema.AccessMode.READ_ONLY) public RegisteredFlowSnapshot getVersionedFlowSnapshot() { return versionedFlowSnapshot; } @@ -39,7 +39,7 @@ public void setVersionedFlowSnapshot(RegisteredFlowSnapshot versionedFlowSnapsho this.versionedFlowSnapshot = versionedFlowSnapshot; } - @ApiModelProperty("The Process Group Change Request") + @Schema(description = "The Process Group Change Request") @Override public ProcessGroupReplaceRequestDTO getRequest() { if (request == null) { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupStatusSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupStatusSnapshotEntity.java index 9522a3dd41232..adc657cc43f8f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupStatusSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupStatusSnapshotEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.status.ProcessGroupStatusSnapshotDTO; @@ -31,7 +31,7 @@ public class ProcessGroupStatusSnapshotEntity extends Entity implements Readable /** * @return The process group id */ - @ApiModelProperty("The id of the process group.") + @Schema(description = "The id of the process group.") public String getId() { return id; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorDiagnosticsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorDiagnosticsEntity.java index 5d26f9aa8c24f..b4304ffdee353 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorDiagnosticsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorDiagnosticsEntity.java @@ -21,14 +21,14 @@ import org.apache.nifi.web.api.dto.diagnostics.ProcessorDiagnosticsDTO; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; @XmlRootElement(name = "processorDiagnosticsEntity") public class ProcessorDiagnosticsEntity extends ComponentEntity implements Permissible { private ProcessorDiagnosticsDTO processorDiagnostics; @Override - @ApiModelProperty("The Processor Diagnostics") + @Schema(description = "The Processor Diagnostics") public ProcessorDiagnosticsDTO getComponent() { return processorDiagnostics; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java index ba6a9870dadeb..3012d9859957d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.ProcessorDTO; import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO; @@ -63,8 +63,7 @@ public void setStatus(ProcessorStatusDTO status) { /** * @return the input requirement of this processor */ - @ApiModelProperty( - value = "The input requirement for this processor." + @Schema(description = "The input requirement for this processor." ) public String getInputRequirement() { return inputRequirement; @@ -77,8 +76,7 @@ public void setInputRequirement(String inputRequirement) { /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusDetailsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusDetailsEntity.java index 830c773f56a8d..c8c474d6ad6af 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusDetailsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusDetailsEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.ProcessorRunStatusDetailsDTO; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -30,7 +30,7 @@ public class ProcessorRunStatusDetailsEntity extends Entity { private PermissionsDTO permissions; private ProcessorRunStatusDetailsDTO runStatusDetails; - @ApiModelProperty("The revision for the Processor.") + @Schema(description = "The revision for the Processor.") public RevisionDTO getRevision() { return revision; } @@ -39,7 +39,7 @@ public void setRevision(final RevisionDTO revision) { this.revision = revision; } - @ApiModelProperty("The permissions for the Processor.") + @Schema(description = "The permissions for the Processor.") public PermissionsDTO getPermissions() { return permissions; } @@ -48,7 +48,7 @@ public void setPermissions(final PermissionsDTO permissions) { this.permissions = permissions; } - @ApiModelProperty("The details of a Processor's run status") + @Schema(description = "The details of a Processor's run status") public ProcessorRunStatusDetailsDTO getRunStatusDetails() { return runStatusDetails; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java index 22637fbb4cb62..47d5a333db538 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorRunStatusEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -26,8 +26,9 @@ @XmlType(name = "processorRunStatus") public class ProcessorRunStatusEntity extends ComponentRunStatusEntity { - // Must match the @ApiModelProperty.allowableValues above getState() - private static String[] SUPPORTED_STATE = {"RUNNING", "RUN_ONCE", "STOPPED", "DISABLED"}; + private static final String ALLOWABLE_VALUES = "RUNNING, STOPPED, DISABLED, RUN_ONCE"; + + private static String[] SUPPORTED_STATE = ALLOWABLE_VALUES.split(", "); @Override protected String[] getSupportedState() { @@ -38,10 +39,7 @@ protected String[] getSupportedState() { * Run status for this Processor. * @return The run status */ - @ApiModelProperty( - value = "The run status of the Processor.", - allowableValues = "RUNNING, STOPPED, DISABLED, RUN_ONCE" - ) + @Schema(description = "The run status of the Processor.", allowableValues = ALLOWABLE_VALUES) public String getState() { return super.getState(); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorStatusSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorStatusSnapshotEntity.java index e59b34c75c4a7..7ba765d4d38ff 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorStatusSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorStatusSnapshotEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.status.ProcessorStatusSnapshotDTO; @@ -31,7 +31,7 @@ public class ProcessorStatusSnapshotEntity extends Entity implements ReadablePer /** * @return The processor id */ - @ApiModelProperty("The id of the processor.") + @Schema(description = "The id of the processor.") public String getId() { return id; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java index 8d406fd44ddd9..abe972bf91034 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemotePortRunStatusEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -37,8 +37,7 @@ protected String[] getSupportedState() { * Run status for this RemotePort. * @return The run status */ - @ApiModelProperty( - value = "The run status of the RemotePort.", + @Schema(description = "The run status of the RemotePort.", allowableValues = "TRANSMITTING, STOPPED" ) public String getState() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java index 41cf308f2cdc9..04d1aaf6f65df 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO; @@ -53,8 +53,7 @@ public void setComponent(RemoteProcessGroupDTO component) { /** * @return the remote process group status */ - @ApiModelProperty( - value = "The status of the remote process group." + @Schema(description = "The status of the remote process group." ) public RemoteProcessGroupStatusDTO getStatus() { return status; @@ -67,8 +66,7 @@ public void setStatus(RemoteProcessGroupStatusDTO status) { /** * @return number of Remote Input Ports currently available in the remote NiFi instance */ - @ApiModelProperty( - value = "The number of remote input ports currently available on the target." + @Schema(description = "The number of remote input ports currently available on the target." ) public Integer getInputPortCount() { return inputPortCount; @@ -81,8 +79,7 @@ public void setInputPortCount(Integer inputPortCount) { /** * @return number of Remote Output Ports currently available in the remote NiFi instance */ - @ApiModelProperty( - value = "The number of remote output ports currently available on the target." + @Schema(description = "The number of remote output ports currently available on the target." ) public Integer getOutputPortCount() { return outputPortCount; @@ -95,8 +92,7 @@ public void setOutputPortCount(Integer outputPortCount) { /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java index 92c8f91b29922..5ad8da267083a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupPortEntity.java @@ -18,7 +18,7 @@ import jakarta.xml.bind.annotation.XmlRootElement; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO; @@ -47,8 +47,7 @@ public void setRemoteProcessGroupPort(RemoteProcessGroupPortDTO remoteProcessGro /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupStatusSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupStatusSnapshotEntity.java index 6dcfe7d27f564..a0dec9157b96f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupStatusSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupStatusSnapshotEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.ReadablePermission; import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusSnapshotDTO; @@ -32,7 +32,7 @@ public class RemoteProcessGroupStatusSnapshotEntity extends Entity implements Re /** * @return The remote process group id */ - @ApiModelProperty("The id of the remote process group.") + @Schema(description = "The id of the remote process group.") public String getId() { return id; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventRequestEntity.java index 8beeeb29d004a..d2bc325b2ddbc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class ReplayLastEventRequestEntity extends Entity { private String componentId; private String nodes; - @ApiModelProperty("The UUID of the component whose last event should be replayed.") + @Schema(description = "The UUID of the component whose last event should be replayed.") public String getComponentId() { return componentId; } @@ -35,8 +35,7 @@ public void setComponentId(final String componentId) { this.componentId = componentId; } - @ApiModelProperty( - value = "Which nodes are to replay their last provenance event.", + @Schema(description = "Which nodes are to replay their last provenance event.", allowableValues = "ALL, PRIMARY" ) public String getNodes() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventResponseEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventResponseEntity.java index 5c4e8fd948390..dc694a749f990 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventResponseEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventResponseEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; import java.util.List; @@ -29,7 +29,7 @@ public class ReplayLastEventResponseEntity extends Entity { private ReplayLastEventSnapshotDTO aggregateSnapshot; private List nodeSnapshots; - @ApiModelProperty("The UUID of the component whose last event should be replayed.") + @Schema(description = "The UUID of the component whose last event should be replayed.") public String getComponentId() { return componentId; } @@ -38,8 +38,7 @@ public void setComponentId(final String componentId) { this.componentId = componentId; } - @ApiModelProperty( - value = "Which nodes were requested to replay their last provenance event.", + @Schema(description = "Which nodes were requested to replay their last provenance event.", allowableValues = "ALL, PRIMARY" ) public String getNodes() { @@ -50,7 +49,7 @@ public void setNodes(String nodes) { this.nodes = nodes; } - @ApiModelProperty("The aggregate result of all nodes' responses") + @Schema(description = "The aggregate result of all nodes' responses") public ReplayLastEventSnapshotDTO getAggregateSnapshot() { return aggregateSnapshot; } @@ -59,7 +58,7 @@ public void setAggregateSnapshot(final ReplayLastEventSnapshotDTO aggregateSnaps this.aggregateSnapshot = aggregateSnapshot; } - @ApiModelProperty("The node-wise results") + @Schema(description = "The node-wise results") public List getNodeSnapshots() { return nodeSnapshots; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventSnapshotDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventSnapshotDTO.java index 91ddfa18da68e..1493b642d93d5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventSnapshotDTO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReplayLastEventSnapshotDTO.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; import java.util.Collection; @@ -27,7 +27,7 @@ public class ReplayLastEventSnapshotDTO { private String failureExplanation; private Boolean eventAvailable; - @ApiModelProperty("The IDs of the events that were successfully replayed") + @Schema(description = "The IDs of the events that were successfully replayed") public Collection getEventsReplayed() { return eventsReplayed; } @@ -36,7 +36,7 @@ public void setEventsReplayed(final Collection eventsReplayed) { this.eventsReplayed = eventsReplayed; } - @ApiModelProperty("If unable to replay an event, specifies why the event could not be replayed") + @Schema(description = "If unable to replay an event, specifies why the event could not be replayed") public String getFailureExplanation() { return failureExplanation; } @@ -45,7 +45,7 @@ public void setFailureExplanation(final String failureExplanation) { this.failureExplanation = failureExplanation; } - @ApiModelProperty("Whether or not an event was available. This may not be populated if there was a failure.") + @Schema(description = "Whether or not an event was available. This may not be populated if there was a failure.") public Boolean getEventAvailable() { return eventAvailable; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java index 0c169f7af874e..f14cfc09ffe65 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskEntity.java @@ -18,7 +18,7 @@ import jakarta.xml.bind.annotation.XmlRootElement; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.PermissionsDTO; import org.apache.nifi.web.api.dto.ReportingTaskDTO; import org.apache.nifi.web.api.dto.status.ReportingTaskStatusDTO; @@ -50,8 +50,7 @@ public void setComponent(ReportingTaskDTO component) { /** * @return The permissions for this component operations */ - @ApiModelProperty( - value = "The permissions for this component operations." + @Schema(description = "The permissions for this component operations." ) @Override public PermissionsDTO getOperatePermissions() { @@ -66,9 +65,8 @@ public void setOperatePermissions(PermissionsDTO permissions) { /** * @return The status for this ReportingTask */ - @ApiModelProperty( - value = "The status for this ReportingTask.", - accessMode = ApiModelProperty.AccessMode.READ_ONLY + @Schema(description = "The status for this ReportingTask.", + accessMode = Schema.AccessMode.READ_ONLY ) public ReportingTaskStatusDTO getStatus() { return status; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java index c9bc4921dd9aa..db9a70b9896f1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTaskRunStatusEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlType; @@ -37,8 +37,7 @@ protected String[] getSupportedState() { * Run status for this ReportingTask. * @return The run status */ - @ApiModelProperty( - value = "The run status of the ReportingTask.", + @Schema(description = "The run status of the ReportingTask.", allowableValues = "RUNNING, STOPPED" ) public String getState() { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTasksEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTasksEntity.java index d61a8327af7c3..f756aff31c0ad 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTasksEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ReportingTasksEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlRootElement; @@ -48,9 +48,8 @@ public void setReportingTasks(Set reportingTasks) { * @return current time on the server */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "The current time on the system.", - dataType = "string" + @Schema(description = "The current time on the system.", + type = "string" ) public Date getCurrentTime() { return currentTime; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RunStatusDetailsRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RunStatusDetailsRequestEntity.java index ac9830ca59190..813302c9360ab 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RunStatusDetailsRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RunStatusDetailsRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; import java.util.Set; @@ -26,7 +26,7 @@ public class RunStatusDetailsRequestEntity extends Entity { private Set processorIds; - @ApiModelProperty("The IDs of all processors whose run status details should be provided") + @Schema(description = "The IDs of all processors whose run status details should be provided") public Set getProcessorIds() { return processorIds; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ScheduleComponentsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ScheduleComponentsEntity.java index 4af081814b2a2..9ec1092cd6c78 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ScheduleComponentsEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ScheduleComponentsEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -40,8 +40,7 @@ public class ScheduleComponentsEntity extends Entity { /** * @return The id of the ProcessGroup */ - @ApiModelProperty( - value = "The id of the ProcessGroup" + @Schema(description = "The id of the ProcessGroup" ) public String getId() { return id; @@ -54,8 +53,7 @@ public void setId(String id) { /** * @return The desired state of the descendant components. Possible states are 'RUNNING', 'STOPPED', 'ENABLED', and 'DISABLED' */ - @ApiModelProperty( - value = "The desired state of the descendant components", + @Schema(description = "The desired state of the descendant components", allowableValues = STATE_RUNNING + ", " + STATE_STOPPED + ", " + STATE_ENABLED + ", " + STATE_DISABLED ) public String getState() { @@ -69,8 +67,7 @@ public void setState(String state) { /** * @return The components to schedule. If not specified, all authorized descendant components will be used. */ - @ApiModelProperty( - value = "Optional components to schedule. If not specified, all authorized descendant components will be used." + @Schema(description = "Optional components to schedule. If not specified, all authorized descendant components will be used." ) public Map getComponents() { return components; @@ -80,8 +77,7 @@ public void setComponents(Map components) { this.components = components; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SnippetEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SnippetEntity.java index 8220d74469610..8be9731c3082e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SnippetEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SnippetEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.SnippetDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -35,7 +35,7 @@ public class SnippetEntity extends Entity { * * @return The SnippetDTO object */ - @ApiModelProperty("The snippet.") + @Schema(description = "The snippet.") public SnippetDTO getSnippet() { return snippet; } @@ -44,8 +44,7 @@ public void setSnippet(SnippetDTO snippet) { this.snippet = snippet; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/StartVersionControlRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/StartVersionControlRequestEntity.java index 4e91db8d59a7c..59d61e67b89fd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/StartVersionControlRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/StartVersionControlRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import org.apache.nifi.web.api.dto.VersionedFlowDTO; @@ -29,7 +29,7 @@ public class StartVersionControlRequestEntity extends Entity { private RevisionDTO processGroupRevision; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The versioned flow") + @Schema(description = "The versioned flow") public VersionedFlowDTO getVersionedFlow() { return versionedFlow; } @@ -38,7 +38,7 @@ public void setVersionedFlow(VersionedFlowDTO versionedFLow) { this.versionedFlow = versionedFLow; } - @ApiModelProperty("The Revision of the Process Group under Version Control") + @Schema(description = "The Revision of the Process Group under Version Control") public RevisionDTO getProcessGroupRevision() { return processGroupRevision; } @@ -47,8 +47,7 @@ public void setProcessGroupRevision(final RevisionDTO revision) { this.processGroupRevision = revision; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SubmitReplayRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SubmitReplayRequestEntity.java index fe63418c3e15a..23c0bc41d7195 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SubmitReplayRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/SubmitReplayRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; @@ -29,8 +29,7 @@ public class SubmitReplayRequestEntity extends Entity { private Long eventId; private String clusterNodeId; - @ApiModelProperty( - value = "The event identifier" + @Schema(description = "The event identifier" ) public Long getEventId() { return eventId; @@ -40,8 +39,7 @@ public void setEventId(Long eventId) { this.eventId = eventId; } - @ApiModelProperty( - value = "The identifier of the node where to submit the replay request." + @Schema(description = "The identifier of the node where to submit the replay request." ) public String getClusterNodeId() { return clusterNodeId; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UpdateControllerServiceReferenceRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UpdateControllerServiceReferenceRequestEntity.java index 5e82f6c9c6697..181e793e28548 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UpdateControllerServiceReferenceRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UpdateControllerServiceReferenceRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -34,8 +34,7 @@ public class UpdateControllerServiceReferenceRequestEntity extends Entity { private Boolean disconnectedNodeAcknowledged; private Boolean uiOnly; - @ApiModelProperty( - value = "The identifier of the Controller Service." + @Schema(description = "The identifier of the Controller Service." ) public String getId() { return id; @@ -45,8 +44,7 @@ public void setId(String id) { this.id = id; } - @ApiModelProperty( - value = "The new state of the references for the controller service.", + @Schema(description = "The new state of the references for the controller service.", allowableValues = "ENABLED, DISABLED, RUNNING, STOPPED" ) public String getState() { @@ -57,8 +55,7 @@ public void setState(String state) { this.state = state; } - @ApiModelProperty( - value = "The revisions for all referencing components." + @Schema(description = "The revisions for all referencing components." ) public Map getReferencingComponentRevisions() { return referencingComponentRevisions; @@ -68,8 +65,7 @@ public void setReferencingComponentRevisions(Map referencin this.referencingComponentRevisions = referencingComponentRevisions; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; @@ -79,9 +75,11 @@ public void setDisconnectedNodeAcknowledged(Boolean disconnectedNodeAcknowledged this.disconnectedNodeAcknowledged = disconnectedNodeAcknowledged; } - @ApiModelProperty( - value = "Indicates whether or not the response should only include fields necessary for rendering the NiFi User Interface. As such, when this value is set to true, some fields may be " + - "returned as null values, and the selected fields may change at any time without notice. As a result, this value should not be set to true by any client other than the UI." + @Schema(description = """ + Indicates whether or not the response should only include fields necessary for rendering the NiFi User Interface. + As such, when this value is set to true, some fields may be returned as null values, and the selected fields may change at any time without notice. + As a result, this value should not be set to true by any client other than the UI. + """ ) public Boolean getUiOnly() { return uiOnly; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UsersEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UsersEntity.java index cce6ee6e4cc64..f62664a4650e1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UsersEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/UsersEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.util.TimeAdapter; import jakarta.xml.bind.annotation.XmlRootElement; @@ -51,9 +51,8 @@ public void setUsers(Collection users) { * @return When this content was generated */ @XmlJavaTypeAdapter(TimeAdapter.class) - @ApiModelProperty( - value = "When this content was generated.", - dataType = "string" + @Schema(description = "When this content was generated.", + type = "string" ) public Date getGenerated() { return generated; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VerifyConfigRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VerifyConfigRequestEntity.java index 5dcb36d726696..b1d2004bff54c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VerifyConfigRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VerifyConfigRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.VerifyConfigRequestDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class VerifyConfigRequestEntity extends Entity { private VerifyConfigRequestDTO request; - @ApiModelProperty("The request") + @Schema(description = "The request") public VerifyConfigRequestDTO getRequest() { return request; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlComponentMappingEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlComponentMappingEntity.java index 8b532af48331c..2ca0319c5876b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlComponentMappingEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlComponentMappingEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.RevisionDTO; import org.apache.nifi.web.api.dto.VersionControlInformationDTO; @@ -31,7 +31,7 @@ public class VersionControlComponentMappingEntity extends Entity { private RevisionDTO processGroupRevision; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The Version Control information") + @Schema(description = "The Version Control information") public VersionControlInformationDTO getVersionControlInformation() { return versionControlDto; } @@ -40,7 +40,7 @@ public void setVersionControlInformation(VersionControlInformationDTO versionCon this.versionControlDto = versionControlDto; } - @ApiModelProperty("The mapping of Versioned Component Identifiers to instance ID's") + @Schema(description = "The mapping of Versioned Component Identifiers to instance ID's") public Map getVersionControlComponentMapping() { return versionControlComponentMapping; } @@ -49,7 +49,7 @@ public void setVersionControlComponentMapping(Map mapping) { this.versionControlComponentMapping = mapping; } - @ApiModelProperty("The revision of the Process Group") + @Schema(description = "The revision of the Process Group") public RevisionDTO getProcessGroupRevision() { return processGroupRevision; } @@ -58,8 +58,7 @@ public void setProcessGroupRevision(RevisionDTO processGroupRevision) { this.processGroupRevision = processGroupRevision; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlInformationEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlInformationEntity.java index 143d2e2cbaed5..c3af007fe6263 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlInformationEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionControlInformationEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.VersionControlInformationDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class VersionControlInformationEntity extends ProcessGroupDescriptorEntity { private VersionControlInformationDTO versionControlInformation; - @ApiModelProperty("The Version Control information") + @Schema(description = "The Version Control information") public VersionControlInformationDTO getVersionControlInformation() { return versionControlInformation; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowEntity.java index 642d8e52e4642..eced7b7221615 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.VersionedFlowDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -26,7 +26,7 @@ public class VersionedFlowEntity extends Entity { private VersionedFlowDTO versionedFlow; - @ApiModelProperty("The versioned flow") + @Schema(description = "The versioned flow") public VersionedFlowDTO getVersionedFlow() { return versionedFlow; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotEntity.java index 3a3e9e63bab05..6cdb3d5819fad 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.registry.flow.RegisteredFlowSnapshot; import org.apache.nifi.web.api.dto.RevisionDTO; @@ -31,7 +31,7 @@ public class VersionedFlowSnapshotEntity extends Entity { private Boolean updateDescendantVersionedFlows; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The versioned flow snapshot") + @Schema(description = "The versioned flow snapshot") public RegisteredFlowSnapshot getVersionedFlowSnapshot() { return versionedFlowSnapshot; } @@ -40,7 +40,7 @@ public void setVersionedFlow(RegisteredFlowSnapshot versionedFlowSnapshot) { this.versionedFlowSnapshot = versionedFlowSnapshot; } - @ApiModelProperty("The Revision of the Process Group under Version Control") + @Schema(description = "The Revision of the Process Group under Version Control") public RevisionDTO getProcessGroupRevision() { return processGroupRevision; } @@ -49,7 +49,7 @@ public void setProcessGroupRevision(final RevisionDTO revision) { this.processGroupRevision = revision; } - @ApiModelProperty("The ID of the Registry that this flow belongs to") + @Schema(description = "The ID of the Registry that this flow belongs to") public String getRegistryId() { return registryId; } @@ -58,7 +58,7 @@ public void setRegistryId(String registryId) { this.registryId = registryId; } - @ApiModelProperty("If the Process Group to be updated has a child or descendant Process Group that is also under " + @Schema(description = "If the Process Group to be updated has a child or descendant Process Group that is also under " + "Version Control, this specifies whether or not the contents of that child/descendant Process Group should be updated.") public Boolean getUpdateDescendantVersionedFlows() { return updateDescendantVersionedFlows; @@ -68,8 +68,7 @@ public void setUpdateDescendantVersionedFlows(Boolean update) { this.updateDescendantVersionedFlows = update; } - @ApiModelProperty( - value = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." + @Schema(description = "Acknowledges that this node is disconnected to allow for mutable requests to proceed." ) public Boolean isDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotMetadataEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotMetadataEntity.java index 2b354760a3910..5071c1d370a6f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotMetadataEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowSnapshotMetadataEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.registry.flow.RegisteredFlowSnapshotMetadata; import jakarta.xml.bind.annotation.XmlRootElement; @@ -27,7 +27,7 @@ public class VersionedFlowSnapshotMetadataEntity extends Entity { private RegisteredFlowSnapshotMetadata versionedFlowSnapshotMetadata; private String registryId; - @ApiModelProperty("The collection of registered flow snapshot metadata") + @Schema(description = "The collection of registered flow snapshot metadata") public RegisteredFlowSnapshotMetadata getVersionedFlowSnapshotMetadata() { return versionedFlowSnapshotMetadata; } @@ -36,7 +36,7 @@ public void setVersionedFlowSnapshotMetadata(RegisteredFlowSnapshotMetadata vers this.versionedFlowSnapshotMetadata = versionedFlowSnapshotMetadata; } - @ApiModelProperty("The ID of the Registry that this flow belongs to") + @Schema(description = "The ID of the Registry that this flow belongs to") public String getRegistryId() { return registryId; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowUpdateRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowUpdateRequestEntity.java index efddccc29e6ed..1bf3a23ecbbdb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowUpdateRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedFlowUpdateRequestEntity.java @@ -17,7 +17,7 @@ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.web.api.dto.VersionedFlowUpdateRequestDTO; import jakarta.xml.bind.annotation.XmlRootElement; @@ -25,7 +25,7 @@ @XmlRootElement(name = "registeredFlowUpdateRequestEntity") public class VersionedFlowUpdateRequestEntity extends FlowUpdateRequestEntity { - @ApiModelProperty("The Flow Update Request") + @Schema(description = "The Flow Update Request") public VersionedFlowUpdateRequestDTO getRequest() { if (request == null) { request = new VersionedFlowUpdateRequestDTO(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportRequestEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportRequestEntity.java index b4faf5cdf20d6..884cb3ba0fce4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportRequestEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportRequestEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import org.apache.nifi.flow.VersionedReportingTaskSnapshot; import jakarta.xml.bind.annotation.XmlRootElement; @@ -27,7 +27,7 @@ public class VersionedReportingTaskImportRequestEntity extends Entity { private VersionedReportingTaskSnapshot reportingTaskSnapshot; private Boolean disconnectedNodeAcknowledged; - @ApiModelProperty("The snapshot to import") + @Schema(description = "The snapshot to import") public VersionedReportingTaskSnapshot getReportingTaskSnapshot() { return reportingTaskSnapshot; } @@ -36,7 +36,7 @@ public void setReportingTaskSnapshot(VersionedReportingTaskSnapshot reportingTas this.reportingTaskSnapshot = reportingTaskSnapshot; } - @ApiModelProperty("The disconnected node acknowledged flag") + @Schema(description = "The disconnected node acknowledged flag") public Boolean getDisconnectedNodeAcknowledged() { return disconnectedNodeAcknowledged; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportResponseEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportResponseEntity.java index f708c4b34bb55..16ed10a4cb816 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportResponseEntity.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/VersionedReportingTaskImportResponseEntity.java @@ -16,7 +16,7 @@ */ package org.apache.nifi.web.api.entity; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; import jakarta.xml.bind.annotation.XmlRootElement; import java.util.Set; @@ -27,7 +27,7 @@ public class VersionedReportingTaskImportResponseEntity extends Entity { private Set reportingTasks; private Set controllerServices; - @ApiModelProperty("The reporting tasks created by the import") + @Schema(description = "The reporting tasks created by the import") public Set getReportingTasks() { return reportingTasks; } @@ -36,7 +36,7 @@ public void setReportingTasks(Set reportingTasks) { this.reportingTasks = reportingTasks; } - @ApiModelProperty("The controller services created by the import") + @Schema(description = "The controller services created by the import") public Set getControllerServices() { return controllerServices; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java index 002292740ca57..2e63e467f00c8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java @@ -63,12 +63,11 @@ import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -302,8 +301,7 @@ public void backupPolicies() throws JAXBException { final AuthorizationsHolder holder = authorizationsHolder.get(); final Authorizations authorizations = holder.getAuthorizations(); - final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - final String timestamp = dateFormat.format(new Date()); + final String timestamp = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss").format(OffsetDateTime.now()); final File backupFile = new File(authorizationsFile.getParentFile(), authorizationsFile.getName() + "." + timestamp); logger.info("Writing backup of Policies to {}", backupFile.getAbsolutePath()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java index 32a08cf36c131..084d74d2c15ba 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java @@ -59,12 +59,11 @@ import java.io.IOException; import java.io.StringWriter; import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -492,8 +491,7 @@ public void backupUsersAndGroups() throws AuthorizationAccessException { final UserGroupHolder holder = userGroupHolder.get(); final Tenants tenants = holder.getTenants(); - final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - final String timestamp = dateFormat.format(new Date()); + final String timestamp = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss").format(OffsetDateTime.now()); final File destinationFile = new File(tenantsFile.getParentFile(), tenantsFile.getName() + "." + timestamp); logger.info("Writing backup of Users & Groups to {}", destinationFile.getAbsolutePath()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java index a00d5ef7dc4d5..3423b12194a5d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java @@ -19,22 +19,17 @@ import org.junit.jupiter.api.Test; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.Date; -import java.util.Locale; import static org.junit.jupiter.api.Assertions.assertEquals; public class TestStatusHistoryEndpointMerger { @Test - public void testNormalizedStatusSnapshotDate() throws ParseException { - final DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:SS.SSS", Locale.US); - final Date date1 = df.parse("2014/01/01 00:00:00.000"); - final Date date2 = df.parse("2014/01/01 00:04:59.999"); - final Date date3 = df.parse("2014/01/01 00:05:00.000"); - final Date date4 = df.parse("2014/01/01 00:05:00.001"); + public void testNormalizedStatusSnapshotDate() { + final Date date1 = new Date(1388538000000L); + final Date date2 = new Date(1388538299999L); + final Date date3 = new Date(1388538300000L); + final Date date4 = new Date(1388538300001L); final Date normalized1 = StatusHistoryEndpointMerger.normalizeStatusSnapshotDate(date1, 300000); assertEquals(date1, normalized1); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/scheduling/ConnectableProcessContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/scheduling/ConnectableProcessContext.java index e7fc2e06e9c08..3d046411b579d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/scheduling/ConnectableProcessContext.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/repository/scheduling/ConnectableProcessContext.java @@ -25,7 +25,6 @@ import java.util.Set; import java.util.concurrent.TimeUnit; -import org.apache.nifi.components.DescribedValue; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.components.PropertyValue; import org.apache.nifi.components.resource.ResourceReference; @@ -154,7 +153,7 @@ public ResourceReferences asResources() { } @Override - public & DescribedValue> E asDescribedValue(Class enumType) throws IllegalArgumentException { + public > E asAllowableValue(Class enumType) throws IllegalArgumentException { return null; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java index af3cf4931eed8..d687deee3d8ef 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizer.java @@ -1202,10 +1202,11 @@ private ControllerServiceNode addControllerService(final ProcessGroup destinatio destination.addControllerService(newService); } - updateControllerService(newService, proposed, topLevelGroup); final Map decryptedProperties = getDecryptedProperties(proposed.getProperties()); createdExtensions.add(new CreatedExtension(newService, decryptedProperties)); + updateControllerService(newService, proposed, topLevelGroup); + return newService; } @@ -1410,7 +1411,7 @@ private Map populatePropertiesMap(final ComponentNode componentN final boolean sensitive = (descriptor != null && descriptor.isSensitive()) || (versionedDescriptor != null && versionedDescriptor.isSensitive()); - String value; + final String value; if (descriptor != null && referencesService && (proposedProperties.get(propertyName) != null)) { // Need to determine if the component's property descriptor for this service is already set to an id // of an existing service that is outside the current processor group, and if it is we want to leave @@ -1433,6 +1434,12 @@ private Map populatePropertiesMap(final ComponentNode componentN final String serviceVersionedComponentId = proposedProperties.get(propertyName); String instanceId = getServiceInstanceId(serviceVersionedComponentId, group); value = (instanceId == null) ? serviceVersionedComponentId : instanceId; + + // Find the same property descriptor in the component's CreatedExtension and replace it with the + // instance ID of the service + createdExtensions.stream().filter(ce -> ce.extension.equals(componentNode)).forEach(createdExtension -> { + createdExtension.propertyValues.replace(propertyName, value); + }); } else { value = existingExternalServiceId; } @@ -1460,8 +1467,7 @@ private Map populatePropertiesMap(final ComponentNode componentN // so we want to continue on and update the value to null. } - value = decrypt(value, syncOptions.getPropertyDecryptor()); - fullPropertyMap.put(propertyName, value); + fullPropertyMap.put(propertyName, decrypt(value, syncOptions.getPropertyDecryptor())); } } @@ -2266,13 +2272,14 @@ public void synchronize(final Port port, final VersionedPort proposed, final Pro if (port == null) { final ComponentType proposedType = proposed.getComponentType(); + final Port newPort; if (proposedType == ComponentType.INPUT_PORT) { - addInputPort(group, proposed, synchronizationOptions.getComponentIdGenerator(), proposed.getName()); + newPort = addInputPort(group, proposed, synchronizationOptions.getComponentIdGenerator(), proposed.getName()); } else { - addOutputPort(group, proposed, synchronizationOptions.getComponentIdGenerator(), proposed.getName()); + newPort = addOutputPort(group, proposed, synchronizationOptions.getComponentIdGenerator(), proposed.getName()); } - LOG.info("Successfully synchronized {} by adding it to the flow", port); + LOG.info("Successfully synchronized {} by adding it to the flow", newPort); } else if (proposed == null) { final Set stoppedDownstream = stopDownstreamComponents(port, timeout, synchronizationOptions); toRestart.addAll(stoppedDownstream); @@ -2400,11 +2407,12 @@ private ProcessorNode addProcessor(final ProcessGroup destination, final Version procNode.setVersionedComponentId(proposed.getIdentifier()); destination.addProcessor(procNode); - updateProcessor(procNode, proposed, topLevelGroup); final Map decryptedProperties = getDecryptedProperties(proposed.getProperties()); createdExtensions.add(new CreatedExtension(procNode, decryptedProperties)); + updateProcessor(procNode, proposed, topLevelGroup); + // Notify the processor node that the configuration (properties, e.g.) has been restored final ProcessContext processContext = context.getProcessContextFactory().apply(procNode); procNode.onConfigurationRestored(processContext); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java index 2d8dcfc4e3ce2..aee703bff231f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/flow/synchronization/StandardVersionedComponentSynchronizerTest.java @@ -19,12 +19,15 @@ import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.ValidationContext; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.connectable.Connectable; import org.apache.nifi.connectable.ConnectableType; import org.apache.nifi.connectable.Connection; import org.apache.nifi.connectable.Port; import org.apache.nifi.controller.ComponentNode; import org.apache.nifi.controller.ControllerService; +import org.apache.nifi.controller.ControllerServiceInitializationContext; import org.apache.nifi.controller.ProcessorNode; import org.apache.nifi.controller.PropertyConfiguration; import org.apache.nifi.controller.ReloadComponent; @@ -73,6 +76,7 @@ import org.apache.nifi.processor.ProcessContext; import org.apache.nifi.processor.Relationship; import org.apache.nifi.registry.flow.mapping.FlowMappingOptions; +import org.apache.nifi.reporting.InitializationException; import org.apache.nifi.scheduling.ExecutionNode; import org.apache.nifi.scheduling.SchedulingStrategy; import org.junit.jupiter.api.BeforeEach; @@ -84,12 +88,14 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -279,6 +285,8 @@ private ControllerServiceNode createMockControllerService() { when(service.isActive()).thenReturn(false); when(service.getProcessGroup()).thenReturn(group); when(service.getState()).thenReturn(ControllerServiceState.DISABLED); + when(service.getBulletinLevel()).thenReturn(LogLevel.WARN); + when(service.getControllerServiceImplementation()).thenReturn(new TestControllerService()); return service; } @@ -304,6 +312,16 @@ private Port createMockPort(final ConnectableType connectableType) { return port; } + private ProcessGroup createMockProcessGroup() { + final ProcessGroup processGroup = mock(ProcessGroup.class); + when(processGroup.getIdentifier()).thenReturn("processGroup"); + when(processGroup.getPosition()).thenReturn(new org.apache.nifi.connectable.Position(0, 0)); + when(processGroup.getFlowFileConcurrency()).thenReturn(FlowFileConcurrency.UNBOUNDED); + when(processGroup.getFlowFileOutboundPolicy()).thenReturn(FlowFileOutboundPolicy.BATCH_OUTPUT); + when(processGroup.getExecutionEngine()).thenReturn(ExecutionEngine.STANDARD); + + return processGroup; + } private Connection createMockConnection(final Connectable source, final Connectable destination, final ProcessGroup group) { final String uuid = UUID.randomUUID().toString(); @@ -342,12 +360,7 @@ private Connection createMockConnection(final Connectable source, final Connecta @Test public void testSynchronizeProcessorAddedMigrated() { - final ProcessGroup processGroup = mock(ProcessGroup.class); - when(processGroup.getIdentifier()).thenReturn("processGroup"); - when(processGroup.getPosition()).thenReturn(new org.apache.nifi.connectable.Position(0, 0)); - when(processGroup.getFlowFileConcurrency()).thenReturn(FlowFileConcurrency.UNBOUNDED); - when(processGroup.getFlowFileOutboundPolicy()).thenReturn(FlowFileOutboundPolicy.BATCH_OUTPUT); - when(processGroup.getExecutionEngine()).thenReturn(ExecutionEngine.STANDARD); + final ProcessGroup processGroup = createMockProcessGroup(); final VersionedProcessGroup rootGroup = new VersionedProcessGroup(); rootGroup.setIdentifier("rootGroup"); @@ -377,6 +390,51 @@ public void testSynchronizeProcessorAddedMigrated() { assertEquals(ENCODED_TEXT, propertyValue); } + @Test + public void testAddProcessorWithServiceAndMigration() { + final ProcessGroup processGroup = createMockProcessGroup(); + + final ProcessorNode processorNode = createMockProcessor(); + when(processorNode.getProcessGroup()).thenReturn(processGroup); + when(processorNode.getRawPropertyValues()).thenReturn(Collections.emptyMap()); + + final VersionedPropertyDescriptor versionedDescriptorCS = new VersionedPropertyDescriptor(); + final PropertyDescriptor descriptorCS = new PropertyDescriptor.Builder().name("cs") + .identifiesControllerService(ControllerService.class).build(); + versionedDescriptorCS.setName(descriptorCS.getName()); + versionedDescriptorCS.setIdentifiesControllerService(true); + final Map proposedDescriptors = + Map.of(versionedDescriptorCS.getName(), versionedDescriptorCS); + + ControllerServiceNode controllerServiceNode = createMockControllerService(); + when(flowManager.createControllerService(any(), any(), any(), anySet(), eq(true), eq(true), eq(null))).thenReturn(controllerServiceNode); + when(flowManager.createProcessor(any(), any(), any(), eq(true))).thenReturn(processorNode); + setReferences(controllerServiceNode, processorNode); + when(controllerServiceNode.getVersionedComponentId()).thenReturn(Optional.of("12345")); + + final VersionedProcessor versionedProcessor = createMinimalVersionedProcessor(); + final Map versionedProperties = Collections.singletonMap("cs", "12345"); + versionedProcessor.setProperties(versionedProperties); + versionedProcessor.setPropertyDescriptors(proposedDescriptors); + final VersionedControllerService versionedControllerService = createMinimalVersionedControllerService(); + + final VersionedProcessGroup versionedGroup = new VersionedProcessGroup(); + versionedGroup.setIdentifier("pg-v2"); + versionedGroup.setProcessors(Set.of(versionedProcessor)); + versionedGroup.setControllerServices(Set.of(versionedControllerService)); + + final VersionedExternalFlow externalFlow = new VersionedExternalFlow(); + externalFlow.setFlowContents(versionedGroup); + + when(processGroup.getControllerServices(false)).thenReturn(Set.of(controllerServiceNode)); + + synchronizer.synchronize(processGroup, externalFlow, synchronizationOptions); + + verify(processorNode).migrateConfiguration(propertiesCaptor.capture(), any()); + final Map migratedProperties = propertiesCaptor.getValue(); + assertEquals(controllerServiceNode.getIdentifier(), migratedProperties.get("cs")); + } + @Test public void testSynchronizeProcessorSensitiveDynamicProperties() throws FlowSynchronizationException, InterruptedException, TimeoutException { final Map versionedProperties = Collections.singletonMap(SENSITIVE_PROPERTY_NAME, ENCRYPTED_PROPERTY_VALUE); @@ -1386,4 +1444,35 @@ void assertProcessorUpdates(final ScheduledStateUpdate... updates } } } + + private static class TestControllerService implements ControllerService { + + @Override + public Collection validate(ValidationContext context) { + return null; + } + + @Override + public PropertyDescriptor getPropertyDescriptor(String name) { + return null; + } + + @Override + public void onPropertyModified(PropertyDescriptor descriptor, String oldValue, String newValue) { + } + + @Override + public List getPropertyDescriptors() { + return null; + } + + @Override + public String getIdentifier() { + return null; + } + + @Override + public void initialize(ControllerServiceInitializationContext context) throws InitializationException { + } + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/processor/TestStandardPropertyValue.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/processor/TestStandardPropertyValue.java index acd3e57269806..727b0271eb405 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/processor/TestStandardPropertyValue.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/test/java/org/apache/nifi/processor/TestStandardPropertyValue.java @@ -111,20 +111,34 @@ public void testGetValueAsIntegerAfterSubstitutingWithNonInteger() { } @Test - public void testGetValueAsDescribedValue() { - for (ExamplePropertyEnum enumValue : ExamplePropertyEnum.values()) { + public void testGetValueAsAllowableValue() { + for (ExampleDescribedValueEnum enumValue : ExampleDescribedValueEnum.values()) { final PropertyValue value = new StandardPropertyValue(enumValue.getValue(), lookup, ParameterLookup.EMPTY); - assertEquals(enumValue, value.asDescribedValue(ExamplePropertyEnum.class)); + assertEquals(enumValue, value.asAllowableValue(ExampleDescribedValueEnum.class)); + } + + final PropertyValue nullDescribedValue = new StandardPropertyValue(null, lookup, ParameterLookup.EMPTY); + assertNull(nullDescribedValue.asAllowableValue(ExampleDescribedValueEnum.class)); + + IllegalArgumentException describedValueException = assertThrows(IllegalArgumentException.class, () -> { + final PropertyValue invalidValue = new StandardPropertyValue("FOO", lookup, ParameterLookup.EMPTY); + invalidValue.asAllowableValue(ExampleDescribedValueEnum.class); + }); + assertEquals("ExampleDescribedValueEnum does not have an entry with value FOO", describedValueException.getMessage()); + + for (ExampleNonDescribedValueEnum enumValue : ExampleNonDescribedValueEnum.values()) { + final PropertyValue value = new StandardPropertyValue(enumValue.name(), lookup, ParameterLookup.EMPTY); + assertEquals(enumValue, value.asAllowableValue(ExampleNonDescribedValueEnum.class)); } final PropertyValue nullValue = new StandardPropertyValue(null, lookup, ParameterLookup.EMPTY); - assertNull(nullValue.asDescribedValue(ExamplePropertyEnum.class)); + assertNull(nullValue.asAllowableValue(ExampleNonDescribedValueEnum.class)); IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { final PropertyValue invalidValue = new StandardPropertyValue("FOO", lookup, ParameterLookup.EMPTY); - invalidValue.asDescribedValue(ExamplePropertyEnum.class); + invalidValue.asAllowableValue(ExampleNonDescribedValueEnum.class); }); - assertEquals("ExamplePropertyEnum does not have an entry with value FOO", exception.getMessage()); + assertEquals("ExampleNonDescribedValueEnum does not have an entry with value FOO", exception.getMessage()); } @Test @@ -197,7 +211,7 @@ public boolean isControllerServiceEnabling(final String serviceIdentifier) { } - private enum ExamplePropertyEnum implements DescribedValue { + private enum ExampleDescribedValueEnum implements DescribedValue { ONE("One Value", "One Display", "One Description"), OTHER("Other Value", "Other Display", "Other Description"), ANOTHER("Another Value", "Another Display", "Another Description"); @@ -206,7 +220,7 @@ private enum ExamplePropertyEnum implements DescribedValue { private final String displayName; private final String description; - ExamplePropertyEnum(final String value, final String displayName, final String description) { + ExampleDescribedValueEnum(final String value, final String displayName, final String description) { this.value = value; this.displayName = displayName; this.description = description; @@ -227,4 +241,6 @@ public String getDescription() { return this.description; } } + + private enum ExampleNonDescribedValueEnum { ONE, TWO, THREE, FOUR } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/ClassLoaderAwarePythonBridge.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/ClassLoaderAwarePythonBridge.java index 8a49feaf92e12..5679a8f45bb19 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/ClassLoaderAwarePythonBridge.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/ClassLoaderAwarePythonBridge.java @@ -96,9 +96,9 @@ public void discoverExtensions() { } @Override - public AsyncLoadedProcessor createProcessor(final String identifier, final String type, final String version, final boolean preferIsolatedProcess) { + public AsyncLoadedProcessor createProcessor(final String identifier, final String type, final String version, final boolean preferIsolatedProcess, final boolean initialize) { try (final NarCloseable narCloseable = NarCloseable.withComponentNarLoader(classLoader)) { - return delegate.createProcessor(identifier, type, version, preferIsolatedProcess); + return delegate.createProcessor(identifier, type, version, preferIsolatedProcess, initialize); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/ExtensionBuilder.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/ExtensionBuilder.java index 13c76098965e4..c50f9686832b6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/ExtensionBuilder.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/ExtensionBuilder.java @@ -866,7 +866,7 @@ private LoggableComponent createLoggablePythonProcessor() { // TODO: This is a hack because there's a bug in the UI that causes it to not load extensions that don't have a `.` in the type. final String processorType = type.startsWith("python.") ? type.substring("python.".length()) : type; - final Processor processor = pythonBridge.createProcessor(identifier, processorType, bundleCoordinate.getVersion(), true); + final Processor processor = pythonBridge.createProcessor(identifier, processorType, bundleCoordinate.getVersion(), true, true); final ComponentLog componentLog = new SimpleProcessLogger(identifier, processor, new StandardLoggingContext(null)); final TerminationAwareLogger terminationAwareLogger = new TerminationAwareLogger(componentLog); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardGarbageCollectionEvent.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardGarbageCollectionEvent.java index d697d7d11e7db..befd6c1b7de66 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardGarbageCollectionEvent.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardGarbageCollectionEvent.java @@ -18,9 +18,7 @@ import org.apache.nifi.util.FormatUtils; -import java.text.DateFormat; import java.text.NumberFormat; -import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.List; @@ -32,7 +30,6 @@ public class StandardGarbageCollectionEvent implements GarbageCollectionEvent { private final long startTime; private final long endTime; private final List heapSizes; - private final DateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS"); public StandardGarbageCollectionEvent(final String gcName, final String action, final String cause, final long startTime, final long endTime, final List heapSizes) { this.gcName = gcName; @@ -84,8 +81,8 @@ public String toString() { sb.append("GarbageCollectionEvent[collectorName=").append(gcName) .append(", action=").append(action) .append(", cause=").append(cause) - .append(", startTime=").append(dateFormat.format(new Date(startTime))) - .append(", endTime=").append(dateFormat.format(new Date(endTime))) + .append(", startTime=").append(new Date(startTime).toInstant()) + .append(", endTime=").append(new Date(endTime).toInstant()) .append(", duration=").append(NumberFormat.getInstance().format(endTime - startTime)) .append(" ms, heap sizes={"); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/cluster/ClusterProtocolHeartbeater.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/cluster/ClusterProtocolHeartbeater.java index 05059cf77ad52..55b86afa9a3c3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/cluster/ClusterProtocolHeartbeater.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/cluster/ClusterProtocolHeartbeater.java @@ -31,11 +31,8 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -102,7 +99,6 @@ public synchronized void send(final HeartbeatMessage heartbeatMessage) throws IO final long sendNanos = System.nanoTime() - sendStart; final long sendMillis = TimeUnit.NANOSECONDS.toMillis(sendNanos); - final DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS", Locale.US); final String flowElectionMessage = responseMessage.getFlowElectionMessage(); final String formattedElectionMessage = flowElectionMessage == null ? "" : "; " + flowElectionMessage; @@ -110,9 +106,9 @@ public synchronized void send(final HeartbeatMessage heartbeatMessage) throws IO logger.info("Heartbeat created at {} and sent to {} at {}; determining Cluster Coordinator took {} millis; DNS lookup for coordinator took {} millis; connecting to coordinator took {} " + "millis; sending heartbeat took {} millis; receiving first byte from response took {} millis; receiving full response took {} millis; total time was {} millis{}", - dateFormatter.format(new Date(heartbeatMessage.getHeartbeat().getCreatedTimestamp())), + Instant.ofEpochMilli(heartbeatMessage.getHeartbeat().getCreatedTimestamp()), heartbeatAddress, - dateFormatter.format(new Date()), + Instant.now(), TimeUnit.NANOSECONDS.toMillis(findCoordinatorNanos), timingDetails.getDnsLookupMillis(), timingDetails.getConnectMillis(), diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/manifest/StandardRuntimeManifestService.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/manifest/StandardRuntimeManifestService.java index b0851a076715d..a6e2b19ba7c48 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/manifest/StandardRuntimeManifestService.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/manifest/StandardRuntimeManifestService.java @@ -20,10 +20,29 @@ import org.apache.nifi.bundle.BundleDetails; import org.apache.nifi.c2.protocol.component.api.BuildInfo; import org.apache.nifi.c2.protocol.component.api.RuntimeManifest; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.extension.manifest.AllowableValue; +import org.apache.nifi.extension.manifest.ControllerServiceDefinition; +import org.apache.nifi.extension.manifest.ExpressionLanguageScope; +import org.apache.nifi.extension.manifest.Extension; import org.apache.nifi.extension.manifest.ExtensionManifest; +import org.apache.nifi.extension.manifest.ExtensionType; +import org.apache.nifi.extension.manifest.InputRequirement; +import org.apache.nifi.extension.manifest.MultiProcessorUseCase; +import org.apache.nifi.extension.manifest.ProcessorConfiguration; +import org.apache.nifi.extension.manifest.Property; +import org.apache.nifi.extension.manifest.UseCase; import org.apache.nifi.extension.manifest.parser.ExtensionManifestParser; +import org.apache.nifi.nar.ExtensionDefinition; import org.apache.nifi.nar.ExtensionManager; import org.apache.nifi.nar.NarClassLoadersHolder; +import org.apache.nifi.nar.PythonBundle; +import org.apache.nifi.processor.Processor; +import org.apache.nifi.python.PythonProcessorDetails; +import org.apache.nifi.python.processor.documentation.MultiProcessorUseCaseDetails; +import org.apache.nifi.python.processor.documentation.ProcessorConfigurationDetails; +import org.apache.nifi.python.processor.documentation.PropertyDescription; +import org.apache.nifi.python.processor.documentation.UseCaseDetails; import org.apache.nifi.runtime.manifest.ExtensionManifestContainer; import org.apache.nifi.runtime.manifest.RuntimeManifestBuilder; import org.apache.nifi.runtime.manifest.impl.SchedulingDefaultsFactory; @@ -33,12 +52,14 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; +import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -94,16 +115,186 @@ public RuntimeManifest getManifest() { getExtensionManifest(bundle).ifPresent(manifestBuilder::addBundle); } + getPythonExtensionManifests().forEach(manifestBuilder::addBundle); + return manifestBuilder.build(); } + private List getPythonExtensionManifests() { + final Map> extensionsPerVersion = new HashMap<>(); + final Set processorDefinitions = extensionManager.getExtensions(Processor.class); + for (final ExtensionDefinition definition : processorDefinitions) { + if (!PythonBundle.isPythonCoordinate(definition.getBundle().getBundleDetails().getCoordinate())) { + continue; + } + + final PythonProcessorDetails pythonProcessorDetails = extensionManager.getPythonProcessorDetails(definition.getImplementationClassName(), definition.getVersion()); + if (pythonProcessorDetails == null) { + LOGGER.debug("Could not find Python Processor Details for {} version {}", definition.getImplementationClassName(), definition.getVersion()); + continue; + } + + final Extension extension = createExtension(pythonProcessorDetails); + final List extensions = extensionsPerVersion.computeIfAbsent(definition.getVersion(), version -> new ArrayList<>()); + extensions.add(extension); + } + + if (extensionsPerVersion.isEmpty()) { + return List.of(); + } + + final List containers = new ArrayList<>(); + for (final Map.Entry> entry : extensionsPerVersion.entrySet()) { + final String version = entry.getKey(); + final List extensions = entry.getValue(); + + final ExtensionManifest extensionManifest = new ExtensionManifest(); + extensionManifest.setGroupId(PythonBundle.GROUP_ID); + extensionManifest.setArtifactId(PythonBundle.ARTIFACT_ID); + extensionManifest.setVersion(version); + extensionManifest.setExtensions(extensions); + + containers.add(new ExtensionManifestContainer(extensionManifest, Map.of())); + } + + return containers; + } + + private Extension createExtension(final PythonProcessorDetails pythonProcessorDetails) { + final Extension extension = new Extension(); + extension.setDescription(pythonProcessorDetails.getCapabilityDescription()); + extension.setName(pythonProcessorDetails.getProcessorType()); + extension.setInputRequirement(InputRequirement.INPUT_REQUIRED); + extension.setSupportsBatching(true); + extension.setType(ExtensionType.PROCESSOR); + extension.setTriggerWhenEmpty(false); + extension.setTriggerSerially(false); + extension.setTriggerWhenAnyDestinationAvailable(false); + + final List relationships = new ArrayList<>(); + extension.setRelationships(relationships); + for (final String relationshipName : List.of("success", "failure", "original")) { + final org.apache.nifi.extension.manifest.Relationship relationship = new org.apache.nifi.extension.manifest.Relationship(); + relationship.setAutoTerminated(false); + relationship.setName(relationshipName); + relationships.add(relationship); + } + + final List useCases = getUseCases(pythonProcessorDetails); + extension.setUseCases(useCases); + + final List multiProcessorUseCases = getMultiProcessorUseCases(pythonProcessorDetails); + extension.setMultiProcessorUseCases(multiProcessorUseCases); + + final List propertyDescriptions = pythonProcessorDetails.getPropertyDescriptions(); + final List manifestProperties = propertyDescriptions == null ? List.of() : propertyDescriptions.stream() + .map(StandardRuntimeManifestService::createManifestProperty) + .toList(); + extension.setProperties(manifestProperties); + + return extension; + } + + private static Property createManifestProperty(final PropertyDescription propertyDescription) { + final Property property = new Property(); + property.setName(propertyDescription.getName()); + property.setDescription(propertyDescription.getDescription()); + property.setDefaultValue(propertyDescription.getDefaultValue()); + property.setDisplayName(propertyDescription.getDisplayName()); + property.setDynamicallyModifiesClasspath(false); + property.setDynamic(false); + try { + property.setExpressionLanguageScope(ExpressionLanguageScope.valueOf(propertyDescription.getExpressionLanguageScope())); + } catch (final Exception e) { + property.setExpressionLanguageScope(ExpressionLanguageScope.NONE); + } + + property.setRequired(propertyDescription.isRequired()); + property.setSensitive(propertyDescription.isSensitive()); + + // TODO: Handle Allowable Values + property.setControllerServiceDefinition(getManifestControllerServiceDefinition(propertyDescription.getControllerServiceDefinition())); + + return property; + } + + private static ControllerServiceDefinition getManifestControllerServiceDefinition(final String controllerServiceClassName) { + if (controllerServiceClassName == null) { + return null; + } + + final ControllerServiceDefinition definition = new ControllerServiceDefinition(); + definition.setClassName(controllerServiceClassName); + return definition; + } + + private static List getManifestAllowableValues(final PropertyDescriptor propertyDescriptor) { + if (propertyDescriptor.getAllowableValues() == null) { + return List.of(); + } + + final List allowableValues = new ArrayList<>(); + for (final org.apache.nifi.components.AllowableValue allowableValue : propertyDescriptor.getAllowableValues()) { + final AllowableValue manifestAllowableValue = new AllowableValue(); + manifestAllowableValue.setDescription(allowableValue.getDescription()); + manifestAllowableValue.setValue(allowableValue.getValue()); + manifestAllowableValue.setDisplayName(allowableValue.getDisplayName()); + allowableValues.add(manifestAllowableValue); + } + return allowableValues; + } + + + private static List getUseCases(final PythonProcessorDetails pythonProcessorDetails) { + final List useCases = new ArrayList<>(); + for (final UseCaseDetails useCaseDetails : pythonProcessorDetails.getUseCases()) { + final UseCase useCase = new UseCase(); + useCases.add(useCase); + + useCase.setDescription(useCaseDetails.getDescription()); + useCase.setNotes(useCaseDetails.getNotes()); + useCase.setKeywords(useCaseDetails.getKeywords()); + useCase.setInputRequirement(InputRequirement.INPUT_REQUIRED); + useCase.setConfiguration(useCaseDetails.getConfiguration()); + } + return useCases; + } + + private static List getMultiProcessorUseCases(final PythonProcessorDetails pythonProcessorDetails) { + final List multiProcessorUseCases = new ArrayList<>(); + for (final MultiProcessorUseCaseDetails useCaseDetails : pythonProcessorDetails.getMultiProcessorUseCases()) { + final MultiProcessorUseCase useCase = new MultiProcessorUseCase(); + multiProcessorUseCases.add(useCase); + + useCase.setDescription(useCaseDetails.getDescription()); + useCase.setNotes(useCaseDetails.getNotes()); + useCase.setKeywords(useCaseDetails.getKeywords()); + + final List processorConfigurations = new ArrayList<>(); + useCase.setProcessorConfigurations(processorConfigurations); + for (final ProcessorConfigurationDetails processorConfig : useCaseDetails.getConfigurations()) { + final ProcessorConfiguration processorConfiguration = new ProcessorConfiguration(); + processorConfigurations.add(processorConfiguration); + + processorConfiguration.setConfiguration(processorConfig.getConfiguration()); + processorConfiguration.setProcessorClassName(processorConfig.getProcessorType()); + } + } + + return multiProcessorUseCases; + } + private Optional getExtensionManifest(final Bundle bundle) { final BundleDetails bundleDetails = bundle.getBundleDetails(); try { - final ExtensionManifest extensionManifest = loadExtensionManifest(bundleDetails); + final Optional extensionManifest = loadExtensionManifest(bundleDetails); + if (extensionManifest.isEmpty()) { + return Optional.empty(); + } + final Map additionalDetails = loadAdditionalDetails(bundleDetails); - final ExtensionManifestContainer container = new ExtensionManifestContainer(extensionManifest, additionalDetails); + final ExtensionManifestContainer container = new ExtensionManifestContainer(extensionManifest.get(), additionalDetails); return Optional.of(container); } catch (final IOException e) { LOGGER.error("Unable to load extension manifest for bundle [{}]", bundleDetails.getCoordinate(), e); @@ -111,11 +302,11 @@ private Optional getExtensionManifest(final Bundle b } } - private ExtensionManifest loadExtensionManifest(final BundleDetails bundleDetails) throws IOException { + private Optional loadExtensionManifest(final BundleDetails bundleDetails) throws IOException { final File manifestFile = new File(bundleDetails.getWorkingDirectory(), "META-INF/docs/extension-manifest.xml"); if (!manifestFile.exists()) { - throw new FileNotFoundException("Extension manifest files does not exist for " - + bundleDetails.getCoordinate() + " at " + manifestFile.getAbsolutePath()); + LOGGER.warn("There is no extension manifest for bundle [{}]", bundleDetails.getCoordinate()); + return Optional.empty(); } try (final InputStream inputStream = new FileInputStream(manifestFile)) { @@ -125,7 +316,7 @@ private ExtensionManifest loadExtensionManifest(final BundleDetails bundleDetail extensionManifest.setGroupId(bundleDetails.getCoordinate().getGroup()); extensionManifest.setArtifactId(bundleDetails.getCoordinate().getId()); extensionManifest.setVersion(bundleDetails.getCoordinate().getVersion()); - return extensionManifest; + return Optional.of(extensionManifest); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TestFlowConfigurationArchiveManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TestFlowConfigurationArchiveManager.java index 3a2ddb51eb809..7fb0505f6c253 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TestFlowConfigurationArchiveManager.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TestFlowConfigurationArchiveManager.java @@ -32,7 +32,8 @@ import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; -import java.text.SimpleDateFormat; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Date; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -160,13 +161,13 @@ private void createSimulatedOldArchives(final File[] oldArchives, final long int // Create old archive files. Altering file name and last modified date to simulate existing files. final long now = System.currentTimeMillis(); - final SimpleDateFormat dateFormat = new SimpleDateFormat("HHmmss"); + final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("HHmmss"); final FlowConfigurationArchiveManager archiveManager = createArchiveManager(null,null, null); for (int i = oldArchives.length; i > 0; i--) { final Date date = new Date(now - (intervalMillis * i)); - final String hhmmss = dateFormat.format(date); + final String hhmmss = dateFormat.format(date.toInstant().atZone(ZoneId.systemDefault())); final File archiveFile = archiveManager.archive(flowXmlFile); final String renamedArchiveName = archiveFile.getName().replaceFirst("T[\\d]{6}", "T" + hhmmss); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/pom.xml index 7492a45676eed..50dd8b5aa2f75 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/pom.xml @@ -30,6 +30,10 @@ org.apache.nifi nifi-utils + + org.apache.nifi + nifi-properties + org.apache.nifi nifi-framework-leader-election-shared diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/main/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/main/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManager.java index cd1396766d9d8..0272149470530 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/main/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManager.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/main/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManager.java @@ -25,6 +25,7 @@ import org.apache.nifi.kubernetes.client.StandardKubernetesClientProvider; import org.apache.nifi.kubernetes.leader.election.command.LeaderElectionCommandProvider; import org.apache.nifi.kubernetes.leader.election.command.StandardLeaderElectionCommandProvider; +import org.apache.nifi.util.NiFiProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,10 +74,14 @@ public class KubernetesLeaderElectionManager extends TrackedLeaderElectionManage private final LeaderElectionCommandProvider leaderElectionCommandProvider; + private final String roleIdPrefix; + /** - * Kubernetes Leader Election Manager default constructor + * Kubernetes Leader Election Manager constructor with NiFi Properties */ - public KubernetesLeaderElectionManager() { + public KubernetesLeaderElectionManager(final NiFiProperties nifiProperties) { + final String leasePrefix = nifiProperties.getProperty(NiFiProperties.CLUSTER_LEADER_ELECTION_KUBERNETES_LEASE_PREFIX); + this.roleIdPrefix = leasePrefix == null || leasePrefix.isBlank() ? null : leasePrefix; executorService = createExecutorService(); leaderElectionCommandProvider = createLeaderElectionCommandProvider(); } @@ -285,7 +290,7 @@ private String getRoleId(final String roleName) { if (roleId == null) { throw new IllegalArgumentException(String.format("Role Name [%s] not supported", roleName)); } - return roleId; + return roleIdPrefix == null ? roleId : String.format("%s-%s", roleIdPrefix, roleId); } private static class ParticipantRegistration { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/test/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManagerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/test/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManagerTest.java index 49c7110385dd9..05c6f636c53e4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/test/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManagerTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-leader-election/src/test/java/org/apache/nifi/kubernetes/leader/election/KubernetesLeaderElectionManagerTest.java @@ -19,6 +19,7 @@ import org.apache.nifi.controller.leader.election.LeaderElectionRole; import org.apache.nifi.controller.leader.election.LeaderElectionStateChangeListener; import org.apache.nifi.kubernetes.leader.election.command.LeaderElectionCommandProvider; +import org.apache.nifi.util.NiFiProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -28,6 +29,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; +import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.function.Consumer; @@ -49,6 +51,10 @@ class KubernetesLeaderElectionManagerTest { private static final String PARTICIPANT_ID = "Node-0"; + private static final String PREFIX = "label"; + + private static final String EMPTY_PREFIX = ""; + @Mock LeaderElectionStateChangeListener changeListener; @@ -68,7 +74,7 @@ class KubernetesLeaderElectionManagerTest { @BeforeEach void setManager() { leaderElectionCommandProvider = new ManagedLeaderElectionCommandProvider(); - manager = new MockKubernetesLeaderElectionManager(); + manager = new MockKubernetesLeaderElectionManager(new NiFiProperties()); } @Test @@ -184,6 +190,41 @@ void testUnregisterNotRegistered() { assertFalse(unregisteredActiveParticipant); } + @Test + void testRoleIdWithPrefix() { + final Properties properties = new Properties(); + properties.setProperty(NiFiProperties.CLUSTER_LEADER_ELECTION_KUBERNETES_LEASE_PREFIX, PREFIX); + final MockKubernetesLeaderElectionManager electionManager = new MockKubernetesLeaderElectionManager(new NiFiProperties(properties)); + + electionManager.start(); + + setSubmitStartLeading(); + + electionManager.register(ROLE, changeListener, PARTICIPANT_ID); + + captureRunCommand(); + + final String expected = String.format("%s-%s", PREFIX, LEADER_ELECTION_ROLE.getRoleId()); + assertEquals(expected, leaderElectionCommandProvider.name); + } + + @Test + void testRoleIdWithEmptyPrefix() { + final Properties properties = new Properties(); + properties.setProperty(NiFiProperties.CLUSTER_LEADER_ELECTION_KUBERNETES_LEASE_PREFIX, EMPTY_PREFIX); + final MockKubernetesLeaderElectionManager electionManager = new MockKubernetesLeaderElectionManager(new NiFiProperties(properties)); + + electionManager.start(); + + setSubmitStartLeading(); + + electionManager.register(ROLE, changeListener, PARTICIPANT_ID); + + captureRunCommand(); + + assertEquals(LEADER_ELECTION_ROLE.getRoleId(), leaderElectionCommandProvider.name); + } + private void setSubmitStartLeading() { doReturn(future).when(executorService).submit(isA(Runnable.class)); leaderElectionCommandProvider.runStartLeading = true; @@ -223,6 +264,10 @@ private void assertNotActiveParticipantNotLeader() { } private class MockKubernetesLeaderElectionManager extends KubernetesLeaderElectionManager { + public MockKubernetesLeaderElectionManager(NiFiProperties nifiProperties) { + super(nifiProperties); + } + @Override protected ExecutorService createExecutorService() { return executorService; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/pom.xml index fbb45f42dc4e0..a93989ddf070d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/pom.xml @@ -48,5 +48,14 @@ kubernetes-server-mock test + + org.apache.nifi + nifi-mock + + + org.apache.nifi + nifi-expression-language + test + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/main/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/main/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProvider.java index d07af6e2ebe45..a4d90d54217c4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/main/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProvider.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/main/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProvider.java @@ -38,8 +38,10 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.apache.nifi.components.AbstractConfigurableComponent; +import org.apache.nifi.components.PropertyDescriptor; +import org.apache.nifi.components.PropertyValue; +import org.apache.nifi.components.Validator; import org.apache.nifi.components.state.Scope; import org.apache.nifi.components.state.StateMap; import org.apache.nifi.components.state.StateProvider; @@ -52,14 +54,28 @@ * State Provider implementation based on Kubernetes ConfigMaps with Base64 encoded keys to meet Kubernetes constraints */ public class KubernetesConfigMapStateProvider extends AbstractConfigurableComponent implements StateProvider { + static final PropertyDescriptor CONFIG_MAP_NAME_PREFIX = new PropertyDescriptor.Builder() + .name("ConfigMap Name Prefix") + .description("Optional prefix that the Provider will prepend to Kubernetes ConfigMap names. The resulting ConfigMap name will contain nifi-component and the component identifier.") + .addValidator(Validator.VALID) + .required(false) + .build(); + + private static final List PROPERTIES = List.of(CONFIG_MAP_NAME_PREFIX); + private static final int MAX_UPDATE_ATTEMPTS = 5; + private static final Scope[] SUPPORTED_SCOPES = { Scope.CLUSTER }; private static final Charset KEY_CHARACTER_SET = StandardCharsets.UTF_8; - private static final String CONFIG_MAP_NAME_FORMAT = "nifi-component-%s"; + private static final String CONFIG_MAP_NAME_FORMAT = "%snifi-component-%%s"; - private static final Pattern CONFIG_MAP_NAME_PATTERN = Pattern.compile("^nifi-component-(.+)$"); + private static final String CONFIG_MAP_NAME_PATTERN_FORMAT = "^%snifi-component-(.+)$"; + + private static final String PREFIX_SEPARATOR = "-"; + + private static final String EMPTY_PREFIX = ""; private static final int COMPONENT_ID_GROUP = 1; @@ -70,6 +86,10 @@ public class KubernetesConfigMapStateProvider extends AbstractConfigurableCompon private final AtomicBoolean enabled = new AtomicBoolean(); + private String configMapNameFormat; + + private Pattern configMapNamePattern; + private KubernetesClient kubernetesClient; private String namespace; @@ -78,6 +98,11 @@ public class KubernetesConfigMapStateProvider extends AbstractConfigurableCompon private ComponentLog logger; + @Override + public List getSupportedPropertyDescriptors() { + return PROPERTIES; + } + /** * Get configured component identifier * @@ -99,6 +124,13 @@ public void initialize(final StateProviderInitializationContext context) { this.logger = context.getLogger(); this.kubernetesClient = getKubernetesClient(); this.namespace = new ServiceAccountNamespaceProvider().getNamespace(); + + final PropertyValue configMapNamePrefixProperty = context.getProperty(CONFIG_MAP_NAME_PREFIX); + final String prefixPropertyValue = configMapNamePrefixProperty.getValue(); + + final String configMapNamePrefix = prefixPropertyValue == null || prefixPropertyValue.isBlank() ? EMPTY_PREFIX : prefixPropertyValue + PREFIX_SEPARATOR; + configMapNameFormat = String.format(CONFIG_MAP_NAME_FORMAT, configMapNamePrefix); + configMapNamePattern = Pattern.compile(String.format(CONFIG_MAP_NAME_PATTERN_FORMAT, configMapNamePrefix)); } /** @@ -331,10 +363,10 @@ public Collection getStoredComponentIds() { return configMapList.getItems().stream() .map(ConfigMap::getMetadata) .map(ObjectMeta::getName) - .map(CONFIG_MAP_NAME_PATTERN::matcher) + .map(configMapNamePattern::matcher) .filter(Matcher::matches) .map(matcher -> matcher.group(COMPONENT_ID_GROUP)) - .collect(Collectors.toUnmodifiableList()); + .toList(); } /** @@ -363,7 +395,7 @@ private ConfigMapBuilder createConfigMapBuilder(final Map state, } private String getConfigMapName(final String componentId) { - return String.format(CONFIG_MAP_NAME_FORMAT, componentId); + return String.format(configMapNameFormat, componentId); } private Optional getVersion(final ConfigMap configMap) { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/test/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProviderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/test/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProviderTest.java index d0adbcd70f3c4..d833113b97d49 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/test/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProviderTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-kubernetes-bundle/nifi-framework-kubernetes-state-provider/src/test/java/org/apache/nifi/kubernetes/state/provider/KubernetesConfigMapStateProviderTest.java @@ -24,15 +24,20 @@ import io.fabric8.kubernetes.client.server.mock.KubernetesMockServerExtension; import io.fabric8.mockwebserver.dsl.HttpMethod; import okhttp3.mockwebserver.RecordedRequest; +import org.apache.nifi.components.ValidationResult; import org.apache.nifi.components.state.Scope; import org.apache.nifi.components.state.StateMap; import org.apache.nifi.components.state.StateProviderInitializationContext; import org.apache.nifi.logging.ComponentLog; +import org.apache.nifi.parameter.ParameterLookup; +import org.apache.nifi.util.MockProcessContext; +import org.apache.nifi.util.MockValidationContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.apache.nifi.attribute.expression.language.StandardPropertyValue; import java.io.IOException; import java.util.Collection; @@ -68,6 +73,10 @@ class KubernetesConfigMapStateProviderTest { private static final String STATE_VALUE = "now"; + private static final String CONFIG_MAP_NAME_PREFIX_VALUE = "label"; + + private static final String EMPTY = ""; + @Mock StateProviderInitializationContext context; @@ -93,12 +102,19 @@ void testGetSupportedScopes() { } @Test - void testInitializeShutdown() { - setContext(); - provider.initialize(context); + void testInitializeValidateShutdown() { + setContextWithConfigMapNamePrefix(EMPTY); + provider.initialize(context); assertEquals(IDENTIFIER, provider.getIdentifier()); + final MockProcessContext processContext = new MockProcessContext(provider); + processContext.setProperty(KubernetesConfigMapStateProvider.CONFIG_MAP_NAME_PREFIX, EMPTY); + final MockValidationContext validationContext = new MockValidationContext(processContext, null); + final Collection results = provider.validate(validationContext); + + assertTrue(results.isEmpty()); + provider.shutdown(); } @@ -293,9 +309,53 @@ void testReplaceConcurrentUpdate() throws IOException { assertFalse(replaced2); } + @Test + void testSetStateGetStateWithPrefix() throws IOException { + setContextWithConfigMapNamePrefix(CONFIG_MAP_NAME_PREFIX_VALUE); + provider.initialize(context); + + final Map state = Collections.singletonMap(STATE_PROPERTY, STATE_VALUE); + + provider.setState(state, COMPONENT_ID); + + final StateMap stateMap = provider.getState(COMPONENT_ID); + + assertNotNull(stateMap); + final Map stateRetrieved = stateMap.toMap(); + assertEquals(state, stateRetrieved); + + assertConfigMapFound(); + } + + @Test + void testSetStateGetStoredComponentIdsWithPrefix() throws IOException { + setContextWithConfigMapNamePrefix(CONFIG_MAP_NAME_PREFIX_VALUE); + provider.initialize(context); + + final Collection initialStoredComponentIds = provider.getStoredComponentIds(); + assertTrue(initialStoredComponentIds.isEmpty()); + + final Map state = Collections.singletonMap(STATE_PROPERTY, STATE_VALUE); + provider.setState(state, COMPONENT_ID); + + final Collection storedComponentIds = provider.getStoredComponentIds(); + final Iterator componentIds = storedComponentIds.iterator(); + + assertTrue(componentIds.hasNext()); + assertEquals(COMPONENT_ID, componentIds.next()); + } + private void setContext() { when(context.getIdentifier()).thenReturn(IDENTIFIER); when(context.getLogger()).thenReturn(logger); + when(context.getProperty(KubernetesConfigMapStateProvider.CONFIG_MAP_NAME_PREFIX)) + .thenReturn(new StandardPropertyValue(null, null, ParameterLookup.EMPTY)); + } + + private void setContextWithConfigMapNamePrefix(final String configMapNamePrefix) { + setContext(); + when(context.getProperty(KubernetesConfigMapStateProvider.CONFIG_MAP_NAME_PREFIX)) + .thenReturn(new StandardPropertyValue(configMapNamePrefix, null, ParameterLookup.EMPTY)); } private void assertStateEquals(final Map expected, final StateMap stateMap) { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionDefinition.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionDefinition.java index ba266680e0ed1..29adda1201fb1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionDefinition.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionDefinition.java @@ -180,7 +180,7 @@ private void requireSet(final Object value, final String fieldName) { } } - enum ExtensionRuntime { + public enum ExtensionRuntime { JAVA, PYTHON; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java index aa6a0c9b1f871..a6c308f0d9c18 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/ExtensionManager.java @@ -19,6 +19,7 @@ import org.apache.nifi.bundle.Bundle; import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.components.ConfigurableComponent; +import org.apache.nifi.python.PythonProcessorDetails; import java.net.URL; import java.util.List; @@ -151,6 +152,14 @@ default InstanceClassLoader createInstanceClassLoader(String classType, String i */ ConfigurableComponent getTempComponent(String classType, BundleCoordinate bundleCoordinate); + /** + * Returns the details about the Python Processor with the given type and version + * @param processorType the type of the Processor + * @param version the version of the Processor + * @return the details for the Python Processor, or null if no Processor can be given that match the given type and version + */ + PythonProcessorDetails getPythonProcessorDetails(String processorType, String version); + /** * Logs the available class loaders. */ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java index bed296e3c247b..3931f46898bd4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java @@ -96,6 +96,7 @@ public class StandardExtensionDiscoveringManager implements ExtensionDiscovering private final Map bundleCoordinateBundleLookup = new HashMap<>(); private final Map classLoaderBundleLookup = new HashMap<>(); private final Map tempComponentLookup = new HashMap<>(); + private final Map> pythonProcessorDetails = new HashMap<>(); private final Map instanceClassloaderLookup = new ConcurrentHashMap<>(); private final ConcurrentMap sharedBaseClassloaders = new ConcurrentHashMap<>(); @@ -201,7 +202,7 @@ public void discoverPythonExtensions(final Bundle pythonBundle) { final Bundle bundle = new Bundle(bundleDetails, pythonBundle.getClassLoader()); // TODO: This is a workaround because the UI has a bug that causes it not to work properly if the type doesn't have a '.' in it - final String className = "python." + details.getProcessorType(); + final String className = PYTHON_TYPE_PREFIX + details.getProcessorType(); final ExtensionDefinition extensionDefinition = new ExtensionDefinition.Builder() .implementationClassName(className) .runtime(ExtensionRuntime.PYTHON) @@ -218,6 +219,10 @@ public void discoverPythonExtensions(final Bundle pythonBundle) { final List bundlesForClass = classNameBundleLookup.computeIfAbsent(className, key -> new ArrayList<>()); bundlesForClass.add(bundle); bundleCoordinateBundleLookup.putIfAbsent(bundleDetails.getCoordinate(), bundle); + + final List detailsList = this.pythonProcessorDetails.computeIfAbsent(details.getProcessorType(), key -> new ArrayList<>()); + detailsList.add(details); + logger.info("Discovered Python Processor {}", details.getProcessorType()); } else { logger.debug("Python Processor {} is already known", details.getProcessorType()); @@ -231,6 +236,23 @@ public void discoverPythonExtensions(final Bundle pythonBundle) { } } + @Override + public PythonProcessorDetails getPythonProcessorDetails(final String processorType, final String version) { + final String canonicalProcessorType = stripPythonTypePrefix(processorType); + final List detailsList = this.pythonProcessorDetails.get(canonicalProcessorType); + if (detailsList == null) { + return null; + } + + for (final PythonProcessorDetails processorDetails : detailsList) { + if (processorDetails.getProcessorVersion().equals(version)) { + return processorDetails; + } + } + + return null; + } + private BundleDetails createBundleDetailsWithOverriddenVersion(final BundleDetails details, final String version) { final BundleCoordinate overriddenCoordinate = new BundleCoordinate(details.getCoordinate().getGroup(), details.getCoordinate().getId(), version); @@ -705,10 +727,10 @@ public synchronized ConfigurableComponent getTempComponent(final String classTyp final ConfigurableComponent tempComponent; if (PythonBundle.isPythonCoordinate(bundle.getBundleDetails().getCoordinate())) { // TODO: This is a workaround due to bug in UI. Fix bug in UI. - final String type = classType.startsWith(PYTHON_TYPE_PREFIX) ? classType.substring(PYTHON_TYPE_PREFIX.length()) : classType; + final String type = stripPythonTypePrefix(classType); final String procId = "temp-component-" + type; - tempComponent = pythonBridge.createProcessor(procId, type, bundleCoordinate.getVersion(), false); + tempComponent = pythonBridge.createProcessor(procId, type, bundleCoordinate.getVersion(), false, false); } else { final Class componentClass = Class.forName(classType, true, bundleClassLoader); tempComponent = (ConfigurableComponent) componentClass.getDeclaredConstructor().newInstance(); @@ -729,6 +751,16 @@ public synchronized ConfigurableComponent getTempComponent(final String classTyp } } + private static String stripPythonTypePrefix(final String value) { + if (value == null) { + return null; + } + if (value.startsWith(PYTHON_TYPE_PREFIX)) { + return value.substring(PYTHON_TYPE_PREFIX.length()); + } + + return value; + } private static String getClassBundleKey(final String classType, final BundleCoordinate bundleCoordinate) { return classType + "_" + bundleCoordinate.getCoordinate(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/PythonBundle.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/PythonBundle.java index 6c3c65174a39a..ad21ae4d5647f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/PythonBundle.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-nar-utils/src/main/java/org/apache/nifi/nar/PythonBundle.java @@ -26,8 +26,11 @@ import java.util.Objects; public class PythonBundle { - private static final BundleCoordinate PYTHON_BUNDLE_COORDINATE = new BundleCoordinate( - "org.apache.nifi", "python-extensions", BundleCoordinate.DEFAULT_VERSION); + public static final String GROUP_ID = "org.apache.nifi"; + public static final String ARTIFACT_ID = "python-extensions"; + public static final String VERSION = BundleCoordinate.DEFAULT_VERSION; + + private static final BundleCoordinate PYTHON_BUNDLE_COORDINATE = new BundleCoordinate(GROUP_ID, ARTIFACT_ID, VERSION); public static Bundle create(final NiFiProperties properties, final ClassLoader classLoader) { final File pythonWorkingDirectory = new File(properties.getProperty(NiFiProperties.PYTHON_WORKING_DIRECTORY, NiFiProperties.DEFAULT_PYTHON_WORKING_DIRECTORY)); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml index 66da4b73b7cbf..b973224863a95 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml @@ -269,6 +269,8 @@ 100 10 ./logs + + 0 diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml index 241ea0bf79420..ae33e0484e7cd 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/logback.xml @@ -196,6 +196,8 @@ + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties index e53b291dcc08c..922e4f9deaeec 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties @@ -335,6 +335,9 @@ nifi.analytics.connection.model.implementation=${nifi.analytics.connection.model nifi.analytics.connection.model.score.name=${nifi.analytics.connection.model.score.name} nifi.analytics.connection.model.score.threshold=${nifi.analytics.connection.model.score.threshold} +# kubernetes # +nifi.cluster.leader.election.kubernetes.lease.prefix=${nifi.cluster.leader.election.kubernetes.lease.prefix} + # flow analysis properties nifi.flow.analysis.background.task.schedule=${nifi.flow.analysis.background.task.schedule} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml index 8689480bf5354..1fd40ea6a3dc3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml @@ -64,10 +64,15 @@ Open - + kubernetes-provider org.apache.nifi.kubernetes.state.provider.KubernetesConfigMapStateProvider + @@ -776,4 +777,8 @@ + + + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/openapi/openapi.yaml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/openapi/openapi.yaml index b70df8ff816b4..fbed1e7591e63 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/openapi/openapi.yaml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/openapi/openapi.yaml @@ -20,6 +20,7 @@ openAPI: description: REST API definition for Apache NiFi web services contact: email: dev@nifi.apache.org + url: https://nifi.apache.org license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/index.mustache b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/index.mustache deleted file mode 100644 index 5a80128c73c73..0000000000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/index.mustache +++ /dev/null @@ -1,734 +0,0 @@ - - - - - {{appName}}-{{version}} - - - - - - - - -

    - -
    {{appName}}
    -
    {{version}}
    -
    -
    -
    -
    {{appDescription}}
    -
    -
    - -
    User authentication and token endpoints
    -
    -
    - -
    -
    -
    - -
    Get controller configuration, Manage the cluster, Create reporting tasks
    -
    -
    - -
    -
    -
    - -
    Manage controller services, Update controller service references
    -
    -
    - -
    -
    -
    - -
    Manage reporting tasks
    -
    -
    - -
    -
    -
    - -
    Get counters, Reset counters
    -
    -
    - -
    -
    -
    - -
    Get the data flow, Obtain component status, Query history
    -
    -
    - -
    -
    -
    - -
    Manage Parameter Contexts and associated validation
    -
    -
    - -
    -
    -
    - -
    Manage Parameter Providers and associated validation
    -
    -
    - -
    -
    -
    - -
    Create components, Instantiate a template, Upload a template
    -
    -
    - -
    -
    -
    - -
    Create a processor, Set properties, Schedule
    -
    -
    - -
    -
    -
    - -
    Create a connection, Set queue priority, Update connection destination
    -
    -
    - -
    -
    -
    - -
    View queue contents, Download flowfile content, Empty queue
    -
    -
    - -
    -
    -
    - -
    Create an input port, Set remote port access control
    -
    -
    - -
    -
    -
    - -
    Create an output port, Set remote port access control
    -
    -
    - -
    -
    -
    - -
    Create a remote group, Enable transmission
    -
    -
    - -
    -
    -
    - -
    Create a label, Set label style
    -
    -
    - -
    -
    -
    - -
    Manage funnels
    -
    -
    - -
    -
    -
    - -
    Query provenance, Search event lineage
    -
    -
    - -
    -
    -
    - -
    Download content, Replay
    -
    -
    - -
    -
    -
    - -
    Add users and group, Group users
    -
    -
    - -
    -
    -
    - -
    Get policies, Create policies
    -
    -
    - -
    -
    -
    - -
    Get resources
    -
    -
    - -
    -
    -
    - -
    Get available ports, Get peers
    -
    -
    - -
    -
    -
    - -
    Send data, Receive data
    -
    -
    - -
    -
    -
    - -
    Create a snippet, Move a snippet, Delete a snippet
    -
    -
    - -
    -
    -
    - -
    Download a template, Delete a template
    -
    -
    - -
    -
    -
    - -
    Get system diagnostics
    -
    -
    - -
    -
    -
    - -
    Manage versions of process groups
    -
    -
    - -
    - - {{#models}} - {{#model}} - {{> model}} - {{/model}} - {{/models}} - - \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/model.mustache b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/model.mustache deleted file mode 100644 index 045e367c7bedc..0000000000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/model.mustache +++ /dev/null @@ -1,61 +0,0 @@ -{{!-- - 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. ---}} - \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/operation.mustache b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/operation.mustache deleted file mode 100644 index 5908001c315f1..0000000000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/operation.mustache +++ /dev/null @@ -1,133 +0,0 @@ -{{!-- - 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. ---}} - \ No newline at end of file diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/style.css.mustache b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/style.css.mustache new file mode 100644 index 0000000000000..4dc8b82d81a9a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/templates/style.css.mustache @@ -0,0 +1,138 @@ +{{!-- + 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. +--}} +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + font-stretch: normal; + src: url(https://fonts.gstatic.com/s/opensans/v27/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0B4gaVI.woff2) format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +body { + font-family: "Open Sans","DejaVu Sans",sans-serif; + margin: 0 auto; + width: 100%; + max-width: 62.5em; +} + +h1 { + font-size: 2.75em; + color: rgba(0,0,0,0.85); + font-weight: 300; + font-style: normal; + line-height: 1.2; + word-spacing: -.05em; +} + +h2 { + font-size: 2em; +} + +h3 { + font-size: 1.5em; +} + +h4 { + font-size: 1.25em; +} + +h2, h3, h4, h5, h6 { + font-weight: 300; + font-style: normal; + color: #7a2518; + line-height: 1.2; + word-spacing: -.05em; +} + +a { + color: #2156a5; + text-decoration: none; +} + +h1 > a { + color: #7a2518; +} + +h2 > a { + color: #7a2518; +} + +h3 > a { + color: #7a2518; +} + +h4 > a { + color: #7a2518; +} + +h5 > a { + color: #7a2518; +} + +h6 > a { + color: #7a2518; +} + +pre { + background: #f7f7f8; + line-height: 1.45; + padding: 1em; + border-radius: 4px; +} + +.app-desc { + margin-bottom: 10px; +} + +.license-info { + margin-bottom: 10px; +} + +.license-url { + margin-bottom: 10px; +} + +.http-method { + text-transform: uppercase; +} + +code { + white-space: pre; +} + +code.huge { + font-size: 1.5em; +} + +.up { + display: none; +} + +.field-items { + margin-left: 10px; +} + +.param-desc { + margin-bottom: 10px; +} + +.param-type { + font-style: italic; +} + +.param-header { + font-weight: bold; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestProcessGroupResource.java index 88c21265dc40a..a0900f2f84f71 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestProcessGroupResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestProcessGroupResource.java @@ -90,7 +90,7 @@ public void testUpdateProcessGroupNotExecuted_WhenUserNotAuthorized(@Mock HttpSe doThrow(AccessDeniedException.class).when(serviceFacade).authorizeAccess(any(AuthorizeAccess.class)); assertThrows(AccessDeniedException.class, () -> - processGroupResource.updateProcessGroup(httpServletRequest, "id", processGroupEntity)); + processGroupResource.updateProcessGroup("id", processGroupEntity)); verify(serviceFacade, never()).verifyUpdateProcessGroup(any()); verify(serviceFacade, never()).updateProcessGroup(any(), any()); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/package-lock.json b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/package-lock.json index 88a5cfe76f504..bdfc546804a32 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/package-lock.json +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/package-lock.json @@ -15372,9 +15372,9 @@ } }, "node_modules/vite": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz", - "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz", + "integrity": "sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w==", "dev": true, "dependencies": { "esbuild": "^0.18.10", diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts index aa4da05e99a00..3a70a49d5bb5c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts @@ -52,6 +52,12 @@ const routes: Routes = [ canMatch: [authenticationGuard], loadChildren: () => import('./pages/users/feature/users.module').then((m) => m.UsersModule) }, + { + path: 'access-policies', + canMatch: [authenticationGuard], + loadChildren: () => + import('./pages/access-policies/feature/access-policies.module').then((m) => m.AccessPoliciesModule) + }, { path: 'summary', canMatch: [authenticationGuard], @@ -62,6 +68,11 @@ const routes: Routes = [ canMatch: [authenticationGuard], loadChildren: () => import('./pages/bulletins/feature/bulletins.module').then((m) => m.BulletinsModule) }, + { + path: 'queue', + canMatch: [authenticationGuard], + loadChildren: () => import('./pages/queue/feature/queue.module').then((m) => m.QueueModule) + }, { path: '', canMatch: [authenticationGuard], diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts index da836bc227b81..4fde32890c049 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts @@ -40,8 +40,8 @@ import { StatusHistoryEffects } from './state/status-history/status-history.effe import { MatDialogModule } from '@angular/material/dialog'; import { ControllerServiceStateEffects } from './state/contoller-service-state/controller-service-state.effects'; import { SystemDiagnosticsEffects } from './state/system-diagnostics/system-diagnostics.effects'; +import { FlowConfigurationEffects } from './state/flow-configuration/flow-configuration.effects'; -// @ts-ignore @NgModule({ declarations: [AppComponent], imports: [ @@ -62,6 +62,7 @@ import { SystemDiagnosticsEffects } from './state/system-diagnostics/system-diag CurrentUserEffects, ExtensionTypesEffects, AboutEffects, + FlowConfigurationEffects, StatusHistoryEffects, ControllerServiceStateEffects, SystemDiagnosticsEffects diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies-routing.module.ts new file mode 100644 index 0000000000000..a611103f263d2 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies-routing.module.ts @@ -0,0 +1,56 @@ +/* + * 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. + */ + +import { RouterModule, Routes } from '@angular/router'; +import { NgModule } from '@angular/core'; +import { AccessPolicies } from './access-policies.component'; +import { FlowConfiguration } from '../../../state/flow-configuration'; +import { checkFlowConfiguration } from '../../../service/guard/flow-configuration.guard'; + +const routes: Routes = [ + { + path: '', + component: AccessPolicies, + canMatch: [ + checkFlowConfiguration( + (flowConfiguration: FlowConfiguration) => flowConfiguration.supportsManagedAuthorizer + ) + ], + children: [ + { + path: 'global', + loadChildren: () => + import('../ui/global-access-policies/global-access-policies.module').then( + (m) => m.GlobalAccessPoliciesModule + ) + }, + { + path: '', + loadChildren: () => + import('../ui/component-access-policies/component-access-policies.module').then( + (m) => m.ComponentAccessPoliciesModule + ) + } + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AccessPoliciesRoutingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.html new file mode 100644 index 0000000000000..0c95453feabb9 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.html @@ -0,0 +1,28 @@ + + +
    +
    + +
    +
    +

    Access Policies

    +
    +
    + +
    +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.scss new file mode 100644 index 0000000000000..b19b15a73cc28 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.scss @@ -0,0 +1,20 @@ +/*! + * 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. + */ + +.access-policies-header { + color: #728e9b; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.spec.ts new file mode 100644 index 0000000000000..035f496df00bd --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.spec.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ + +import { AccessPolicies } from './access-policies.component'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { RouterModule } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { provideMockStore } from '@ngrx/store/testing'; +import { initialState } from '../state/access-policy/access-policy.reducer'; +import { Component } from '@angular/core'; + +describe('AccessPolicies', () => { + let component: AccessPolicies; + let fixture: ComponentFixture; + + @Component({ + selector: 'navigation', + standalone: true, + template: '' + }) + class MockNavigation {} + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [AccessPolicies], + imports: [RouterModule, RouterTestingModule, MockNavigation], + providers: [ + provideMockStore({ + initialState + }) + ] + }); + fixture = TestBed.createComponent(AccessPolicies); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.ts new file mode 100644 index 0000000000000..9efae42064996 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.component.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { NiFiState } from '../../../state'; +import { startCurrentUserPolling, stopCurrentUserPolling } from '../../../state/current-user/current-user.actions'; + +@Component({ + selector: 'access-policies', + templateUrl: './access-policies.component.html', + styleUrls: ['./access-policies.component.scss'] +}) +export class AccessPolicies implements OnInit, OnDestroy { + constructor(private store: Store) {} + + ngOnInit(): void { + this.store.dispatch(startCurrentUserPolling()); + } + + ngOnDestroy(): void { + this.store.dispatch(stopCurrentUserPolling()); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.module.ts new file mode 100644 index 0000000000000..163a532eed2f1 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/feature/access-policies.module.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AccessPolicies } from './access-policies.component'; +import { AccessPoliciesRoutingModule } from './access-policies-routing.module'; +import { StoreModule } from '@ngrx/store'; +import { reducers, accessPoliciesFeatureKey } from '../state'; +import { EffectsModule } from '@ngrx/effects'; +import { MatDialogModule } from '@angular/material/dialog'; +import { AccessPolicyEffects } from '../state/access-policy/access-policy.effects'; +import { TenantsEffects } from '../state/tenants/tenants.effects'; +import { PolicyComponentEffects } from '../state/policy-component/policy-component.effects'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; + +@NgModule({ + declarations: [AccessPolicies], + exports: [AccessPolicies], + imports: [ + CommonModule, + AccessPoliciesRoutingModule, + StoreModule.forFeature(accessPoliciesFeatureKey, reducers), + EffectsModule.forFeature(AccessPolicyEffects, TenantsEffects, PolicyComponentEffects), + MatDialogModule, + Navigation + ] +}) +export class AccessPoliciesModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/service/access-policy.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/service/access-policy.service.ts new file mode 100644 index 0000000000000..34ab4bf9598dc --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/service/access-policy.service.ts @@ -0,0 +1,110 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Client } from '../../../service/client.service'; +import { Observable } from 'rxjs'; +import { AccessPolicyEntity, ComponentResourceAction, ResourceAction } from '../state/shared'; +import { NiFiCommon } from '../../../service/nifi-common.service'; +import { TenantEntity } from '../../../state/shared'; + +@Injectable({ providedIn: 'root' }) +export class AccessPolicyService { + private static readonly API: string = '../nifi-api'; + + constructor( + private httpClient: HttpClient, + private client: Client, + private nifiCommon: NiFiCommon + ) {} + + /** + * The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling + * does not work on absolute URLs, so we need to strip off the proto for the request header to be added. + * + * https://stackoverflow.com/a/59586462 + * + * @param url + * @private + */ + private stripProtocol(url: string): string { + return this.nifiCommon.substringAfterFirst(url, ':'); + } + + createAccessPolicy(resourceAction: ResourceAction): Observable { + let resource: string = `/${resourceAction.resource}`; + if (resourceAction.resourceIdentifier) { + resource += `/${resourceAction.resourceIdentifier}`; + } + + const payload: unknown = { + revision: { + version: 0, + clientId: this.client.getClientId() + }, + component: { + action: resourceAction.action, + resource, + userGroups: [], + users: [] + } + }; + + return this.httpClient.post(`${AccessPolicyService.API}/policies`, payload); + } + + getAccessPolicy(resourceAction: ResourceAction): Observable { + const path: string[] = [resourceAction.action, resourceAction.resource]; + if (resourceAction.resourceIdentifier) { + path.push(resourceAction.resourceIdentifier); + } + return this.httpClient.get(`${AccessPolicyService.API}/policies/${path.join('/')}`); + } + + getPolicyComponent(resourceAction: ComponentResourceAction): Observable { + return this.httpClient.get( + `${AccessPolicyService.API}/${resourceAction.resource}/${resourceAction.resourceIdentifier}` + ); + } + + updateAccessPolicy(accessPolicy: AccessPolicyEntity, users: TenantEntity[], userGroups: TenantEntity[]) { + const payload: unknown = { + revision: this.client.getRevision(accessPolicy), + component: { + id: accessPolicy.id, + userGroups, + users + } + }; + + return this.httpClient.put(this.stripProtocol(accessPolicy.uri), payload); + } + + deleteAccessPolicy(accessPolicy: AccessPolicyEntity): Observable { + const revision: any = this.client.getRevision(accessPolicy); + return this.httpClient.delete(this.stripProtocol(accessPolicy.uri), { params: revision }); + } + + getUsers(): Observable { + return this.httpClient.get(`${AccessPolicyService.API}/tenants/users`); + } + + getUserGroups(): Observable { + return this.httpClient.get(`${AccessPolicyService.API}/tenants/user-groups`); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.actions.ts new file mode 100644 index 0000000000000..2a81093301834 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.actions.ts @@ -0,0 +1,98 @@ +/* + * 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. + */ + +import { createAction, props } from '@ngrx/store'; +import { + LoadAccessPolicyError, + LoadAccessPolicyRequest, + AccessPolicyResponse, + SelectGlobalAccessPolicyRequest, + SetAccessPolicyRequest, + ResetAccessPolicy, + RemoveTenantFromPolicyRequest, + AddTenantsToPolicyRequest, + SelectComponentAccessPolicyRequest +} from './index'; + +const ACCESS_POLICY_PREFIX: string = '[Access Policy]'; + +export const selectGlobalAccessPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Select Global Access Policy`, + props<{ request: SelectGlobalAccessPolicyRequest }>() +); + +export const selectComponentAccessPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Select Component Access Policy`, + props<{ request: SelectComponentAccessPolicyRequest }>() +); + +export const setAccessPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Set Access Policy`, + props<{ request: SetAccessPolicyRequest }>() +); + +export const reloadAccessPolicy = createAction(`${ACCESS_POLICY_PREFIX} Reload Access Policy`); + +export const loadAccessPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Load Access Policy`, + props<{ request: LoadAccessPolicyRequest }>() +); + +export const loadAccessPolicySuccess = createAction( + `${ACCESS_POLICY_PREFIX} Load Access Policy Success`, + props<{ response: AccessPolicyResponse }>() +); + +export const createAccessPolicy = createAction(`${ACCESS_POLICY_PREFIX} Create Access Policy`); + +export const createAccessPolicySuccess = createAction( + `${ACCESS_POLICY_PREFIX} Create Access Policy Success`, + props<{ response: AccessPolicyResponse }>() +); + +export const openAddTenantToPolicyDialog = createAction(`${ACCESS_POLICY_PREFIX} Open Add Tenant To Policy Dialog`); + +export const addTenantsToPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Add Tenants To Policy`, + props<{ request: AddTenantsToPolicyRequest }>() +); + +export const promptRemoveTenantFromPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Prompt Remove Tenant From Policy`, + props<{ request: RemoveTenantFromPolicyRequest }>() +); + +export const removeTenantFromPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Remove Tenant From Policy`, + props<{ request: RemoveTenantFromPolicyRequest }>() +); + +export const promptDeleteAccessPolicy = createAction(`${ACCESS_POLICY_PREFIX} Prompt Delete Access Policy`); + +export const deleteAccessPolicy = createAction(`${ACCESS_POLICY_PREFIX} Delete Access Policy`); + +export const resetAccessPolicy = createAction( + `${ACCESS_POLICY_PREFIX} Reset Access Policy`, + props<{ response: ResetAccessPolicy }>() +); + +export const accessPolicyApiError = createAction( + `${ACCESS_POLICY_PREFIX} Access Policy Api Error`, + props<{ response: LoadAccessPolicyError }>() +); + +export const resetAccessPolicyState = createAction(`${ACCESS_POLICY_PREFIX} Reset Access Policy State`); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.effects.ts new file mode 100644 index 0000000000000..93b956d576d51 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.effects.ts @@ -0,0 +1,394 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; +import { NiFiState } from '../../../../state'; +import { Store } from '@ngrx/store'; +import { Router } from '@angular/router'; +import * as AccessPolicyActions from './access-policy.actions'; +import { catchError, from, map, of, switchMap, take, tap } from 'rxjs'; +import { MatDialog } from '@angular/material/dialog'; +import { AccessPolicyService } from '../../service/access-policy.service'; +import { AccessPolicyEntity, ComponentResourceAction, PolicyStatus, ResourceAction } from '../shared'; +import { selectAccessPolicy, selectResourceAction, selectSaving } from './access-policy.selectors'; +import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; +import { isDefinedAndNotNull, TenantEntity } from '../../../../state/shared'; +import { AddTenantToPolicyDialog } from '../../ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component'; +import { AddTenantsToPolicyRequest } from './index'; +import { selectUserGroups, selectUsers } from '../tenants/tenants.selectors'; + +@Injectable() +export class AccessPolicyEffects { + constructor( + private actions$: Actions, + private store: Store, + private router: Router, + private accessPoliciesService: AccessPolicyService, + private dialog: MatDialog + ) {} + + setAccessPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.setAccessPolicy), + map((action) => action.request), + switchMap((request) => + of( + AccessPolicyActions.loadAccessPolicy({ + request: { + resourceAction: request.resourceAction + } + }) + ) + ) + ) + ); + + reloadAccessPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.reloadAccessPolicy), + concatLatestFrom(() => this.store.select(selectResourceAction).pipe(isDefinedAndNotNull())), + switchMap(([action, resourceAction]) => { + return of( + AccessPolicyActions.loadAccessPolicy({ + request: { + resourceAction + } + }) + ); + }) + ) + ); + + loadAccessPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.loadAccessPolicy), + map((action) => action.request), + switchMap((request) => + from(this.accessPoliciesService.getAccessPolicy(request.resourceAction)).pipe( + map((response) => { + const accessPolicy: AccessPolicyEntity = response; + + let requestedResource: string = `/${request.resourceAction.resource}`; + if (request.resourceAction.resourceIdentifier) { + requestedResource += `/${request.resourceAction.resourceIdentifier}`; + } + + let policyStatus: PolicyStatus | undefined; + if (accessPolicy.component.resource === requestedResource) { + policyStatus = PolicyStatus.Found; + } else { + policyStatus = PolicyStatus.Inherited; + } + + return AccessPolicyActions.loadAccessPolicySuccess({ + response: { + accessPolicy, + policyStatus + } + }); + }), + catchError((error) => { + let policyStatus: PolicyStatus | undefined; + if (error.status === 404) { + policyStatus = PolicyStatus.NotFound; + } else if (error.status === 403) { + policyStatus = PolicyStatus.Forbidden; + } + + if (policyStatus) { + return of( + AccessPolicyActions.resetAccessPolicy({ + response: { + policyStatus + } + }) + ); + } else { + return of( + AccessPolicyActions.accessPolicyApiError({ + response: { + error: error.error + } + }) + ); + } + }) + ) + ) + ) + ); + + createAccessPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.createAccessPolicy), + concatLatestFrom(() => this.store.select(selectResourceAction).pipe(isDefinedAndNotNull())), + switchMap(([action, resourceAction]) => + from(this.accessPoliciesService.createAccessPolicy(resourceAction)).pipe( + map((response) => { + const accessPolicy: AccessPolicyEntity = response; + const policyStatus: PolicyStatus = PolicyStatus.Found; + + return AccessPolicyActions.createAccessPolicySuccess({ + response: { + accessPolicy, + policyStatus + } + }); + }), + catchError((error) => + of( + AccessPolicyActions.accessPolicyApiError({ + response: { + error: error.error + } + }) + ) + ) + ) + ) + ) + ); + + selectGlobalAccessPolicy$ = createEffect( + () => + this.actions$.pipe( + ofType(AccessPolicyActions.selectGlobalAccessPolicy), + map((action) => action.request), + tap((request) => { + const resourceAction: ResourceAction = request.resourceAction; + const commands: string[] = [ + '/access-policies', + 'global', + resourceAction.action, + resourceAction.resource + ]; + if (resourceAction.resourceIdentifier) { + commands.push(resourceAction.resourceIdentifier); + } + + this.router.navigate(commands); + }) + ), + { dispatch: false } + ); + + selectComponentAccessPolicy$ = createEffect( + () => + this.actions$.pipe( + ofType(AccessPolicyActions.selectComponentAccessPolicy), + map((action) => action.request), + tap((request) => { + const resourceAction: ComponentResourceAction = request.resourceAction; + const commands: string[] = [ + '/access-policies', + resourceAction.action, + resourceAction.policy, + resourceAction.resource, + resourceAction.resourceIdentifier + ]; + this.router.navigate(commands); + }) + ), + { dispatch: false } + ); + + openAddTenantToPolicyDialog$ = createEffect( + () => + this.actions$.pipe( + ofType(AccessPolicyActions.openAddTenantToPolicyDialog), + concatLatestFrom(() => this.store.select(selectAccessPolicy)), + tap(([action, accessPolicy]) => { + const dialogReference = this.dialog.open(AddTenantToPolicyDialog, { + data: { + accessPolicy + }, + panelClass: 'medium-dialog' + }); + + dialogReference.componentInstance.saving$ = this.store.select(selectSaving); + dialogReference.componentInstance.users$ = this.store.select(selectUsers); + dialogReference.componentInstance.userGroups$ = this.store.select(selectUserGroups); + + dialogReference.componentInstance.addTenants + .pipe(take(1)) + .subscribe((request: AddTenantsToPolicyRequest) => { + this.store.dispatch(AccessPolicyActions.addTenantsToPolicy({ request })); + }); + }) + ), + { dispatch: false } + ); + + addTenantsToPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.addTenantsToPolicy), + map((action) => action.request), + concatLatestFrom(() => this.store.select(selectAccessPolicy).pipe(isDefinedAndNotNull())), + switchMap(([request, accessPolicy]) => { + const users: TenantEntity[] = [...accessPolicy.component.users, ...request.users]; + const userGroups: TenantEntity[] = [...accessPolicy.component.userGroups, ...request.userGroups]; + + return from(this.accessPoliciesService.updateAccessPolicy(accessPolicy, users, userGroups)).pipe( + map((response: any) => { + this.dialog.closeAll(); + + return AccessPolicyActions.loadAccessPolicySuccess({ + response: { + accessPolicy: response, + policyStatus: PolicyStatus.Found + } + }); + }), + catchError((error) => + of( + AccessPolicyActions.accessPolicyApiError({ + response: { + error: error.error + } + }) + ) + ) + ); + }) + ) + ); + + promptRemoveTenantFromPolicy$ = createEffect( + () => + this.actions$.pipe( + ofType(AccessPolicyActions.promptRemoveTenantFromPolicy), + map((action) => action.request), + tap((request) => { + const dialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Update Policy', + message: `Remove '${request.tenant.component.identity}' from this policy?` + }, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + this.store.dispatch(AccessPolicyActions.removeTenantFromPolicy({ request })); + }); + }) + ), + { dispatch: false } + ); + + removeTenantFromPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.removeTenantFromPolicy), + map((action) => action.request), + concatLatestFrom(() => this.store.select(selectAccessPolicy).pipe(isDefinedAndNotNull())), + switchMap(([request, accessPolicy]) => { + const users: TenantEntity[] = [...accessPolicy.component.users]; + const userGroups: TenantEntity[] = [...accessPolicy.component.userGroups]; + + let tenants: TenantEntity[]; + if (request.tenantType === 'user') { + tenants = users; + } else { + tenants = userGroups; + } + + if (tenants) { + const tenantIndex: number = tenants.findIndex( + (tenant: TenantEntity) => request.tenant.id === tenant.id + ); + if (tenantIndex > -1) { + tenants.splice(tenantIndex, 1); + } + } + + return from(this.accessPoliciesService.updateAccessPolicy(accessPolicy, users, userGroups)).pipe( + map((response: any) => { + return AccessPolicyActions.loadAccessPolicySuccess({ + response: { + accessPolicy: response, + policyStatus: PolicyStatus.Found + } + }); + }), + catchError((error) => + of( + AccessPolicyActions.accessPolicyApiError({ + response: { + error: error.error + } + }) + ) + ) + ); + }) + ) + ); + + promptDeleteAccessPolicy$ = createEffect( + () => + this.actions$.pipe( + ofType(AccessPolicyActions.promptDeleteAccessPolicy), + tap((request) => { + const dialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Delete Policy', + message: + 'Are you sure you want to delete this policy? By doing so, the permissions for this component will revert to the inherited policy if applicable.' + }, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + this.store.dispatch(AccessPolicyActions.deleteAccessPolicy()); + }); + }) + ), + { dispatch: false } + ); + + deleteAccessPolicy$ = createEffect(() => + this.actions$.pipe( + ofType(AccessPolicyActions.deleteAccessPolicy), + concatLatestFrom(() => [ + this.store.select(selectResourceAction).pipe(isDefinedAndNotNull()), + this.store.select(selectAccessPolicy).pipe(isDefinedAndNotNull()) + ]), + switchMap(([action, resourceAction, accessPolicy]) => + from(this.accessPoliciesService.deleteAccessPolicy(accessPolicy)).pipe( + map((response) => { + // the policy was removed, we need to reload the policy for this resource and action to fetch + // the inherited policy or correctly when it's not found + return AccessPolicyActions.loadAccessPolicy({ + request: { + resourceAction + } + }); + }), + catchError((error) => + of( + AccessPolicyActions.accessPolicyApiError({ + response: { + error: error.error + } + }) + ) + ) + ) + ) + ) + ); +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.reducer.ts new file mode 100644 index 0000000000000..0f2300b13d01c --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.reducer.ts @@ -0,0 +1,82 @@ +/* + * 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. + */ + +import { AccessPolicyState } from './index'; +import { createReducer, on } from '@ngrx/store'; +import { + addTenantsToPolicy, + createAccessPolicySuccess, + accessPolicyApiError, + loadAccessPolicy, + loadAccessPolicySuccess, + removeTenantFromPolicy, + resetAccessPolicyState, + resetAccessPolicy, + setAccessPolicy +} from './access-policy.actions'; + +export const initialState: AccessPolicyState = { + saving: false, + loadedTimestamp: '', + error: null, + status: 'pending' +}; + +export const accessPolicyReducer = createReducer( + initialState, + on(setAccessPolicy, (state, { request }) => ({ + ...state, + resourceAction: request.resourceAction + })), + on(loadAccessPolicy, (state, { request }) => ({ + ...state, + status: 'loading' as const + })), + on(loadAccessPolicySuccess, createAccessPolicySuccess, (state, { response }) => ({ + ...state, + accessPolicy: response.accessPolicy, + policyStatus: response.policyStatus, + loadedTimestamp: response.accessPolicy.generated, + saving: false, + status: 'success' as const + })), + on(addTenantsToPolicy, (state, { request }) => ({ + ...state, + saving: true + })), + on(removeTenantFromPolicy, (state, { request }) => ({ + ...state, + saving: true + })), + on(resetAccessPolicy, (state, { response }) => ({ + ...state, + accessPolicy: undefined, + policyStatus: response.policyStatus, + loadedTimestamp: 'N/A', + status: 'success' as const + })), + on(accessPolicyApiError, (state, { response }) => ({ + ...state, + error: response.error, + accessPolicy: undefined, + policyStatus: undefined, + status: 'error' as const + })), + on(resetAccessPolicyState, (state) => ({ + ...initialState + })) +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.selectors.ts new file mode 100644 index 0000000000000..37fa1d6b35934 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/access-policy.selectors.ts @@ -0,0 +1,66 @@ +/* + * 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. + */ + +import { createSelector } from '@ngrx/store'; +import { AccessPoliciesState, selectAccessPoliciesState } from '../index'; +import { accessPolicyFeatureKey, AccessPolicyState } from './index'; +import { selectCurrentRoute } from '../../../../state/router/router.selectors'; +import { ComponentResourceAction, ResourceAction } from '../shared'; + +export const selectAccessPolicyState = createSelector( + selectAccessPoliciesState, + (state: AccessPoliciesState) => state[accessPolicyFeatureKey] +); + +export const selectResourceAction = createSelector( + selectAccessPolicyState, + (state: AccessPolicyState) => state.resourceAction +); + +export const selectAccessPolicy = createSelector( + selectAccessPolicyState, + (state: AccessPolicyState) => state.accessPolicy +); + +export const selectSaving = createSelector(selectAccessPolicyState, (state: AccessPolicyState) => state.saving); + +export const selectGlobalResourceActionFromRoute = createSelector(selectCurrentRoute, (route) => { + let selectedResourceAction: ResourceAction | null = null; + if (route?.params.action && route?.params.resource) { + // always select the action and resource from the route + selectedResourceAction = { + action: route.params.action, + resource: route.params.resource, + resourceIdentifier: route.params.resourceIdentifier + }; + } + return selectedResourceAction; +}); + +export const selectComponentResourceActionFromRoute = createSelector(selectCurrentRoute, (route) => { + let selectedResourceAction: ComponentResourceAction | null = null; + if (route?.params.action && route?.params.policy && route?.params.resource && route?.params.resourceIdentifier) { + // always select the action and resource from the route + selectedResourceAction = { + action: route.params.action, + policy: route.params.policy, + resource: route.params.resource, + resourceIdentifier: route.params.resourceIdentifier + }; + } + return selectedResourceAction; +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/index.ts new file mode 100644 index 0000000000000..d9b0a4fa53b5d --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/access-policy/index.ts @@ -0,0 +1,74 @@ +/* + * 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. + */ + +import { AccessPolicyEntity, ComponentResourceAction, PolicyStatus, ResourceAction } from '../shared'; +import { TenantEntity, UserEntity, UserGroupEntity } from '../../../../state/shared'; + +export const accessPolicyFeatureKey = 'accessPolicy'; + +export interface SetAccessPolicyRequest { + resourceAction: ResourceAction; +} + +export interface SelectGlobalAccessPolicyRequest { + resourceAction: ResourceAction; +} + +export interface SelectComponentAccessPolicyRequest { + resourceAction: ComponentResourceAction; +} + +export interface LoadAccessPolicyRequest { + resourceAction: ResourceAction; +} + +export interface AccessPolicyResponse { + accessPolicy: AccessPolicyEntity; + policyStatus?: PolicyStatus; +} + +export interface ResetAccessPolicy { + policyStatus: PolicyStatus; +} + +export interface LoadAccessPolicyError { + error: string; +} + +export interface RemoveTenantFromPolicyRequest { + tenantType: 'user' | 'userGroup'; + tenant: TenantEntity; +} + +export interface AddTenantToPolicyDialogRequest { + accessPolicy: AccessPolicyEntity; +} + +export interface AddTenantsToPolicyRequest { + users: TenantEntity[]; + userGroups: TenantEntity[]; +} + +export interface AccessPolicyState { + resourceAction?: ResourceAction; + policyStatus?: PolicyStatus; + accessPolicy?: AccessPolicyEntity; + saving: boolean; + loadedTimestamp: string; + error: string | null; + status: 'pending' | 'loading' | 'error' | 'success'; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/index.ts new file mode 100644 index 0000000000000..746fe2c4aecbc --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/index.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ + +import { Action, combineReducers, createFeatureSelector } from '@ngrx/store'; +import { accessPolicyFeatureKey, AccessPolicyState } from './access-policy'; +import { accessPolicyReducer } from './access-policy/access-policy.reducer'; +import { tenantsFeatureKey, TenantsState } from './tenants'; +import { tenantsReducer } from './tenants/tenants.reducer'; +import { policyComponentFeatureKey, PolicyComponentState } from './policy-component'; +import { policyComponentReducer } from './policy-component/policy-component.reducer'; + +export const accessPoliciesFeatureKey = 'accessPolicies'; + +export interface AccessPoliciesState { + [accessPolicyFeatureKey]: AccessPolicyState; + [tenantsFeatureKey]: TenantsState; + [policyComponentFeatureKey]: PolicyComponentState; +} + +export function reducers(state: AccessPoliciesState | undefined, action: Action) { + return combineReducers({ + [accessPolicyFeatureKey]: accessPolicyReducer, + [tenantsFeatureKey]: tenantsReducer, + [policyComponentFeatureKey]: policyComponentReducer + })(state, action); +} + +export const selectAccessPoliciesState = createFeatureSelector(accessPoliciesFeatureKey); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/index.ts new file mode 100644 index 0000000000000..5579d16880faf --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/index.ts @@ -0,0 +1,39 @@ +/* + * 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. + */ + +import { ComponentResourceAction } from '../shared'; + +export const policyComponentFeatureKey = 'policyComponent'; + +export interface LoadPolicyComponentRequest { + componentResourceAction: ComponentResourceAction; +} + +export interface LoadPolicyComponentSuccess { + label: string; + resource: string; + allowRemoteAccess: boolean; +} + +export interface PolicyComponentState { + label: string; + allowRemoteAccess: boolean; + resource: string; + loadedTimestamp: string; + error: string | null; + status: 'pending' | 'loading' | 'error' | 'success'; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.actions.ts new file mode 100644 index 0000000000000..e046d2cc9e491 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.actions.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +import { createAction, props } from '@ngrx/store'; +import { LoadPolicyComponentRequest, LoadPolicyComponentSuccess } from './index'; + +const POLICY_COMPONENT_PREFIX: string = '[Policy Component]'; + +export const loadPolicyComponent = createAction( + `${POLICY_COMPONENT_PREFIX} Load Policy Component`, + props<{ request: LoadPolicyComponentRequest }>() +); + +export const loadPolicyComponentSuccess = createAction( + `${POLICY_COMPONENT_PREFIX} Load Policy Component Success`, + props<{ response: LoadPolicyComponentSuccess }>() +); + +export const policyComponentApiError = createAction( + `${POLICY_COMPONENT_PREFIX} Policy Component Api Error`, + props<{ error: string }>() +); + +export const resetPolicyComponentState = createAction(`${POLICY_COMPONENT_PREFIX} Reset Policy Component State`); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.effects.ts new file mode 100644 index 0000000000000..baa50398bdde5 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.effects.ts @@ -0,0 +1,73 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import * as PolicyComponentActions from './policy-component.actions'; +import { catchError, from, map, of, switchMap } from 'rxjs'; +import { AccessPolicyService } from '../../service/access-policy.service'; + +@Injectable() +export class PolicyComponentEffects { + constructor( + private actions$: Actions, + private accessPoliciesService: AccessPolicyService + ) {} + + loadPolicyComponent$ = createEffect(() => + this.actions$.pipe( + ofType(PolicyComponentActions.loadPolicyComponent), + map((action) => action.request), + switchMap((request) => + from(this.accessPoliciesService.getPolicyComponent(request.componentResourceAction)).pipe( + map((response) => + PolicyComponentActions.loadPolicyComponentSuccess({ + response: { + label: response.component.name, + resource: request.componentResourceAction.resource, + allowRemoteAccess: + request.componentResourceAction.resource === 'input-ports' || + request.componentResourceAction.resource === 'output-ports' + ? response.allowRemoteAccess + : false + } + }) + ), + catchError((error) => { + if (error.status === 403) { + return of( + PolicyComponentActions.loadPolicyComponentSuccess({ + response: { + label: request.componentResourceAction.resourceIdentifier, + resource: request.componentResourceAction.resource, + allowRemoteAccess: false + } + }) + ); + } else { + return of( + PolicyComponentActions.policyComponentApiError({ + error: error.error + }) + ); + } + }) + ) + ) + ) + ); +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.reducer.ts new file mode 100644 index 0000000000000..024a4ac0bd28a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.reducer.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ + +import { PolicyComponentState } from './index'; +import { createReducer, on } from '@ngrx/store'; +import { + loadPolicyComponent, + loadPolicyComponentSuccess, + resetPolicyComponentState, + policyComponentApiError +} from './policy-component.actions'; + +export const initialState: PolicyComponentState = { + label: '', + resource: '', + allowRemoteAccess: false, + loadedTimestamp: '', + error: null, + status: 'pending' +}; + +export const policyComponentReducer = createReducer( + initialState, + on(loadPolicyComponent, (state) => ({ + ...state, + status: 'loading' as const + })), + on(loadPolicyComponentSuccess, (state, { response }) => ({ + ...state, + label: response.label, + resource: response.resource, + allowRemoteAccess: response.allowRemoteAccess, + status: 'success' as const + })), + on(policyComponentApiError, (state, { error }) => ({ + ...state, + error: error, + status: 'error' as const + })), + on(resetPolicyComponentState, (state) => ({ + ...initialState + })) +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.selectors.ts new file mode 100644 index 0000000000000..4a9d7d6bc9c40 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/policy-component/policy-component.selectors.ts @@ -0,0 +1,25 @@ +/* + * 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. + */ + +import { createSelector } from '@ngrx/store'; +import { AccessPoliciesState, selectAccessPoliciesState } from '../index'; +import { policyComponentFeatureKey } from './index'; + +export const selectPolicyComponentState = createSelector( + selectAccessPoliciesState, + (state: AccessPoliciesState) => state[policyComponentFeatureKey] +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/shared/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/shared/index.ts new file mode 100644 index 0000000000000..3564ce195e066 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/shared/index.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ + +import { AccessPolicySummary, Permissions, Revision, TenantEntity } from '../../../../state/shared'; + +export enum PolicyStatus { + Found = 'Found', + Inherited = 'Inherited', + NotFound = 'NotFound', + Forbidden = 'Forbidden' +} + +export enum Action { + Read = 'read', + Write = 'write' +} + +export interface ResourceAction { + resource: string; + resourceIdentifier?: string; + action: Action; +} + +export interface ComponentResourceAction extends ResourceAction { + resourceIdentifier: string; + policy: string; +} + +export interface AccessPolicyEntity { + id: string; + component: AccessPolicy; + revision: Revision; + uri: string; + permissions: Permissions; + generated: string; +} + +export interface AccessPolicy extends AccessPolicySummary { + users: TenantEntity[]; + userGroups: TenantEntity[]; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/index.ts new file mode 100644 index 0000000000000..abfa1b8ff7e62 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/index.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +import { UserEntity, UserGroupEntity } from '../../../../state/shared'; + +export const tenantsFeatureKey = 'tenants'; + +export interface LoadTenantsSuccess { + users: UserEntity[]; + userGroups: UserGroupEntity[]; +} + +export interface TenantsState { + users: UserEntity[]; + userGroups: UserGroupEntity[]; + loadedTimestamp: string; + error: string | null; + status: 'pending' | 'loading' | 'error' | 'success'; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.actions.ts new file mode 100644 index 0000000000000..573c88ba7525a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.actions.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ + +import { createAction, props } from '@ngrx/store'; +import { LoadTenantsSuccess } from './index'; + +const TENANTS_PREFIX: string = '[Tenants]'; + +export const loadTenants = createAction(`${TENANTS_PREFIX} Load Tenants`); + +export const loadTenantsSuccess = createAction( + `${TENANTS_PREFIX} Load Tenants Success`, + props<{ response: LoadTenantsSuccess }>() +); + +export const tenantsApiError = createAction(`${TENANTS_PREFIX} Tenants Api Error`, props<{ error: string }>()); + +export const resetTenantsState = createAction(`${TENANTS_PREFIX} Reset Tenants State`); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.effects.ts new file mode 100644 index 0000000000000..4d6b10101a952 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.effects.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import * as TenantsActions from './tenants.actions'; +import { catchError, combineLatest, map, of, switchMap } from 'rxjs'; +import { AccessPolicyService } from '../../service/access-policy.service'; + +@Injectable() +export class TenantsEffects { + constructor( + private actions$: Actions, + private accessPoliciesService: AccessPolicyService + ) {} + + loadTenants$ = createEffect(() => + this.actions$.pipe( + ofType(TenantsActions.loadTenants), + switchMap(() => + combineLatest([this.accessPoliciesService.getUsers(), this.accessPoliciesService.getUserGroups()]).pipe( + map(([usersResponse, userGroupsResponse]) => + TenantsActions.loadTenantsSuccess({ + response: { + users: usersResponse.users, + userGroups: userGroupsResponse.userGroups + } + }) + ), + catchError((error) => + of( + TenantsActions.tenantsApiError({ + error: error.error + }) + ) + ) + ) + ) + ) + ); +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.reducer.ts new file mode 100644 index 0000000000000..a971604af705d --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.reducer.ts @@ -0,0 +1,50 @@ +/* + * 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. + */ + +import { TenantsState } from './index'; +import { createReducer, on } from '@ngrx/store'; +import { loadTenants, loadTenantsSuccess, resetTenantsState, tenantsApiError } from './tenants.actions'; + +export const initialState: TenantsState = { + users: [], + userGroups: [], + loadedTimestamp: '', + error: null, + status: 'pending' +}; + +export const tenantsReducer = createReducer( + initialState, + on(loadTenants, (state) => ({ + ...state, + status: 'loading' as const + })), + on(loadTenantsSuccess, (state, { response }) => ({ + ...state, + users: response.users, + userGroups: response.userGroups, + status: 'success' as const + })), + on(tenantsApiError, (state, { error }) => ({ + ...state, + error: error, + status: 'error' as const + })), + on(resetTenantsState, (state) => ({ + ...initialState + })) +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.selectors.ts new file mode 100644 index 0000000000000..97b75f0a02cfa --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/state/tenants/tenants.selectors.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +import { createSelector } from '@ngrx/store'; +import { AccessPoliciesState, selectAccessPoliciesState } from '../index'; +import { tenantsFeatureKey, TenantsState } from './index'; + +export const selectTenants = createSelector( + selectAccessPoliciesState, + (state: AccessPoliciesState) => state[tenantsFeatureKey] +); + +export const selectUsers = createSelector(selectTenants, (state: TenantsState) => state.users); + +export const selectUserGroups = createSelector(selectTenants, (state: TenantsState) => state.userGroups); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.html new file mode 100644 index 0000000000000..ca63632e8dafb --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.html @@ -0,0 +1,54 @@ + + +

    Add Users/Groups To Policy

    +
    + +
    + Users + + {{ user.component.identity }} + + +
    +
    + User Groups + + + {{ userGroup.component.identity }} + + +
    +
    + All users and groups are assigned to this policy. +
    +
    + + + + +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.scss new file mode 100644 index 0000000000000..d4bb96e3f2d0f --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.scss @@ -0,0 +1,31 @@ +/* + * 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. + */ + +@use '@angular/material' as mat; + +.add-tenant-to-policy-form { + @include mat.button-density(-1); + + .fa { + color: #004849; + } + + mat-selection-list { + max-height: 250px; + overflow: auto; + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.spec.ts new file mode 100644 index 0000000000000..e9ade3e655148 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.spec.ts @@ -0,0 +1,82 @@ +/* + * 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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddTenantToPolicyDialog } from './add-tenant-to-policy-dialog.component'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { AddTenantToPolicyDialogRequest } from '../../../state/access-policy'; + +describe('AddTenantToPolicyDialog', () => { + let component: AddTenantToPolicyDialog; + let fixture: ComponentFixture; + + const data: AddTenantToPolicyDialogRequest = { + accessPolicy: { + revision: { + clientId: '311032c3-f210-42f9-8a31-862c88b5fbd4', + version: 4 + }, + id: 'f99bccd1-a30e-3e4a-98a2-dbc708edc67f', + uri: 'https://localhost:4200/nifi-api/policies/f99bccd1-a30e-3e4a-98a2-dbc708edc67f', + permissions: { + canRead: true, + canWrite: true + }, + generated: '15:48:06 EST', + component: { + id: 'f99bccd1-a30e-3e4a-98a2-dbc708edc67f', + resource: '/flow', + action: 'read', + configurable: true, + users: [ + { + revision: { + version: 0 + }, + id: 'bc646be3-146f-3cf2-bfd6-3a9f687ee7ab', + permissions: { + canRead: true, + canWrite: true + }, + component: { + id: 'bc646be3-146f-3cf2-bfd6-3a9f687ee7ab', + identity: 'identify', + configurable: false + } + } + ], + userGroups: [] + } + } + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AddTenantToPolicyDialog, BrowserAnimationsModule], + providers: [{ provide: MAT_DIALOG_DATA, useValue: data }] + }); + fixture = TestBed.createComponent(AddTenantToPolicyDialog); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.ts new file mode 100644 index 0000000000000..0ee1c126b782d --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/add-tenant-to-policy-dialog/add-tenant-to-policy-dialog.component.ts @@ -0,0 +1,153 @@ +/* + * 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. + */ + +import { Component, DestroyRef, EventEmitter, inject, Inject, Input, Output } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { AccessPolicy } from '../../../state/shared'; +import { MatButtonModule } from '@angular/material/button'; +import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; +import { MatRadioModule } from '@angular/material/radio'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { AsyncPipe, NgForOf, NgIf } from '@angular/common'; +import { Observable } from 'rxjs'; +import { MatListModule } from '@angular/material/list'; +import { TenantEntity, UserEntity, UserGroupEntity } from '../../../../../state/shared'; +import { AddTenantsToPolicyRequest, AddTenantToPolicyDialogRequest } from '../../../state/access-policy'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { NifiSpinnerDirective } from '../../../../../ui/common/spinner/nifi-spinner.directive'; + +@Component({ + selector: 'add-tenant-to-policy-dialog', + standalone: true, + imports: [ + MatDialogModule, + MatButtonModule, + FormsModule, + MatFormFieldModule, + MatInputModule, + ReactiveFormsModule, + MatRadioModule, + MatCheckboxModule, + NgIf, + AsyncPipe, + MatListModule, + NgForOf, + NifiSpinnerDirective + ], + templateUrl: './add-tenant-to-policy-dialog.component.html', + styleUrls: ['./add-tenant-to-policy-dialog.component.scss'] +}) +export class AddTenantToPolicyDialog { + @Input() set users$(users$: Observable) { + users$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((users: UserEntity[]) => { + const policy: AccessPolicy = this.request.accessPolicy.component; + + this.filteredUsers = users.filter((user: UserEntity) => { + return !policy.users.some((tenant: TenantEntity) => tenant.id === user.id); + }); + + this.userLookup.clear(); + this.filteredUsers.forEach((user: UserEntity) => { + this.userLookup.set(user.id, user); + }); + }); + } + + @Input() set userGroups$(userGroups$: Observable) { + userGroups$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((userGroups: UserGroupEntity[]) => { + const policy: AccessPolicy = this.request.accessPolicy.component; + + this.filteredUserGroups = userGroups.filter((userGroup: UserGroupEntity) => { + return !policy.userGroups.some((tenant: TenantEntity) => tenant.id === userGroup.id); + }); + + this.userGroupLookup.clear(); + this.filteredUserGroups.forEach((user: UserGroupEntity) => { + this.userGroupLookup.set(user.id, user); + }); + }); + } + + @Input() saving$!: Observable; + + @Output() addTenants: EventEmitter = new EventEmitter(); + + private destroyRef = inject(DestroyRef); + + addTenantsForm: FormGroup; + filteredUsers: UserEntity[] = []; + filteredUserGroups: UserGroupEntity[] = []; + + userLookup: Map = new Map(); + userGroupLookup: Map = new Map(); + + constructor( + @Inject(MAT_DIALOG_DATA) private request: AddTenantToPolicyDialogRequest, + private formBuilder: FormBuilder + ) { + this.addTenantsForm = this.formBuilder.group({ + users: new FormControl([]), + userGroups: new FormControl([]) + }); + } + + addClicked(): void { + const users: TenantEntity[] = []; + + const usersSelected: string[] = this.addTenantsForm.get('users')?.value; + usersSelected.forEach((userId: string) => { + const user: UserEntity | undefined = this.userLookup.get(userId); + if (user) { + users.push({ + id: user.id, + revision: user.revision, + permissions: user.permissions, + component: { + id: user.component.id, + identity: user.component.identity, + configurable: user.component.configurable + } + }); + } + }); + + const userGroups: TenantEntity[] = []; + const userGroupsSelected: string[] = this.addTenantsForm.get('userGroups')?.value; + userGroupsSelected.forEach((userGroupId: string) => { + const userGroup: UserGroupEntity | undefined = this.userGroupLookup.get(userGroupId); + if (userGroup) { + userGroups.push({ + id: userGroup.id, + revision: userGroup.revision, + permissions: userGroup.permissions, + component: { + id: userGroup.component.id, + identity: userGroup.component.identity, + configurable: userGroup.component.configurable + } + }); + } + }); + + this.addTenants.next({ + users, + userGroups + }); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.html new file mode 100644 index 0000000000000..357defd7a17fd --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.html @@ -0,0 +1,57 @@ + +
    +
    + + + + + + + + + + + + + + +
    User + {{ item.user }} + +
    +
    +
    +
    +
    +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.scss new file mode 100644 index 0000000000000..44602528424ed --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.scss @@ -0,0 +1,24 @@ +/*! + * 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. + */ + +.policy-table { + .listing-table { + .mat-column-actions { + width: 75px; + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.spec.ts new file mode 100644 index 0000000000000..1fd95e1a6784e --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.spec.ts @@ -0,0 +1,54 @@ +/* + * 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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PolicyTable } from './policy-table.component'; +import { MatTableModule } from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatInputModule } from '@angular/material/input'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatSelectModule } from '@angular/material/select'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { CurrentUser } from '../../../../../state/current-user'; + +describe('PolicyTable', () => { + let component: PolicyTable; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [], + imports: [ + PolicyTable, + MatTableModule, + MatSortModule, + MatInputModule, + ReactiveFormsModule, + MatSelectModule, + NoopAnimationsModule + ] + }); + fixture = TestBed.createComponent(PolicyTable); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.ts new file mode 100644 index 0000000000000..5b5880f4efdfa --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/common/policy-table/policy-table.component.ts @@ -0,0 +1,143 @@ +/* + * 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. + */ + +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatTableDataSource, MatTableModule } from '@angular/material/table'; +import { MatSortModule, Sort } from '@angular/material/sort'; +import { NiFiCommon } from '../../../../../service/nifi-common.service'; +import { CurrentUser } from '../../../../../state/current-user'; +import { TenantEntity, UserEntity } from '../../../../../state/shared'; +import { NgIf } from '@angular/common'; +import { AccessPolicyEntity } from '../../../state/shared'; +import { RemoveTenantFromPolicyRequest } from '../../../state/access-policy'; + +export interface TenantItem { + id: string; + user: string; + tenantType: 'user' | 'userGroup'; + configurable: boolean; +} + +@Component({ + selector: 'policy-table', + standalone: true, + templateUrl: './policy-table.component.html', + imports: [MatTableModule, MatSortModule, NgIf], + styleUrls: ['./policy-table.component.scss', '../../../../../../assets/styles/listing-table.scss'] +}) +export class PolicyTable { + displayedColumns: string[] = ['user', 'actions']; + dataSource: MatTableDataSource = new MatTableDataSource(); + + tenantLookup: Map = new Map(); + + @Input() set policy(policy: AccessPolicyEntity | undefined) { + const tenantItems: TenantItem[] = []; + + if (policy) { + policy.component.users.forEach((user) => { + this.tenantLookup.set(user.id, user); + tenantItems.push({ + id: user.id, + tenantType: 'user', + user: user.component.identity, + configurable: user.component.configurable + }); + }); + policy.component.userGroups.forEach((userGroup) => { + this.tenantLookup.set(userGroup.id, userGroup); + tenantItems.push({ + id: userGroup.id, + tenantType: 'userGroup', + user: userGroup.component.identity, + configurable: userGroup.component.configurable + }); + }); + } + + this.dataSource.data = this.sortUsers(tenantItems, this.sort); + this._policy = policy; + } + + @Input() supportsPolicyModification!: boolean; + + @Output() removeTenantFromPolicy: EventEmitter = + new EventEmitter(); + + private _policy: AccessPolicyEntity | undefined; + selectedTenantId: string | null = null; + + sort: Sort = { + active: 'user', + direction: 'asc' + }; + + constructor(private nifiCommon: NiFiCommon) {} + + updateSort(sort: Sort): void { + this.sort = sort; + this.dataSource.data = this.sortUsers(this.dataSource.data, sort); + } + + sortUsers(items: TenantItem[], sort: Sort): TenantItem[] { + const data: TenantItem[] = items.slice(); + return data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + + let retVal: number = 0; + switch (sort.active) { + case 'user': + retVal = this.nifiCommon.compareString(a.user, b.user); + break; + } + + return retVal * (isAsc ? 1 : -1); + }); + } + + select(item: TenantItem): void { + this.selectedTenantId = item.id; + } + + isSelected(item: TenantItem): boolean { + if (this.selectedTenantId) { + return item.id == this.selectedTenantId; + } + return false; + } + + canRemove(): boolean { + if (this._policy) { + return ( + this.supportsPolicyModification && + this._policy.permissions.canWrite && + this._policy.component.configurable + ); + } + return false; + } + + removeClicked(item: TenantItem): void { + const tenant: TenantEntity | undefined = this.tenantLookup.get(item.id); + if (tenant) { + this.removeTenantFromPolicy.next({ + tenantType: item.tenantType, + tenant + }); + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies-routing.module.ts new file mode 100644 index 0000000000000..ffe6845ba2faa --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies-routing.module.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ComponentAccessPolicies } from './component-access-policies.component'; +import { authorizationGuard } from '../../../../service/guard/authorization.guard'; +import { CurrentUser } from '../../../../state/current-user'; + +const routes: Routes = [ + { + path: ':action/:policy/:resource/:resourceIdentifier', + canMatch: [authorizationGuard((user: CurrentUser) => user.tenantsPermissions.canRead)], + component: ComponentAccessPolicies + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ComponentAccessPoliciesRoutingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.html new file mode 100644 index 0000000000000..f97374c1cbd62 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.html @@ -0,0 +1,153 @@ + + + +
    + +
    + + + +
    +
    +
    + + No policy for the specified resource. + + Create a new policy. + + + + + + + + + Not authorized to access the policy for the specified resource. + +
    +
    +
    +
    +
    +
    + +
    +
    {{ policyComponentState.label }}
    +
    {{ getContextType() }}
    +
    +
    +
    + + Policy + + + {{ option.text }} + + + + +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    +
    + +
    Last updated:
    +
    {{ accessPolicyState.loadedTimestamp }}
    +
    +
    +
    +
    +
    +
    + + No component specific administrators. + + Add policy for additional administrators. + + + + Showing effective policy inherited from the controller. + + Override this policy. + + + + Showing effective policy inherited from global parameter context policy. + + Override this policy. + + + + Showing effective policy inherited from Process Group. + + Override this policy. + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.scss new file mode 100644 index 0000000000000..7e9a22925f9fa --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.scss @@ -0,0 +1,48 @@ +/*! + * 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. + */ + +.component-access-policies { + a { + font-size: 16px; + } + + .policy-select { + .mat-mdc-form-field { + width: 300px; + } + } + + .operation-context-logo { + .icon { + font-size: 36px; + color: #ad9897; + } + } + + .operation-context-name { + font-size: 18px; + color: #262626; + width: 370px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + .operation-context-type { + color: #728e9b; + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.spec.ts new file mode 100644 index 0000000000000..3f6f5f5f847fd --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.spec.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +import { ComponentAccessPolicies } from './component-access-policies.component'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideMockStore } from '@ngrx/store/testing'; +import { initialState } from '../../state/access-policy/access-policy.reducer'; + +describe('ComponentAccessPolicies', () => { + let component: ComponentAccessPolicies; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [ComponentAccessPolicies], + providers: [provideMockStore({ initialState })] + }); + fixture = TestBed.createComponent(ComponentAccessPolicies); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.ts new file mode 100644 index 0000000000000..b22bdeb566565 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.component.ts @@ -0,0 +1,439 @@ +/* + * 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. + */ + +import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; +import { + createAccessPolicy, + openAddTenantToPolicyDialog, + promptDeleteAccessPolicy, + promptRemoveTenantFromPolicy, + reloadAccessPolicy, + resetAccessPolicyState, + selectComponentAccessPolicy, + setAccessPolicy +} from '../../state/access-policy/access-policy.actions'; +import { AccessPolicyState, RemoveTenantFromPolicyRequest } from '../../state/access-policy'; +import { initialState } from '../../state/access-policy/access-policy.reducer'; +import { + selectAccessPolicyState, + selectComponentResourceActionFromRoute +} from '../../state/access-policy/access-policy.selectors'; +import { distinctUntilChanged, filter } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { NiFiCommon } from '../../../../service/nifi-common.service'; +import { ComponentType, isDefinedAndNotNull, SelectOption, TextTipInput } from '../../../../state/shared'; +import { TextTip } from '../../../../ui/common/tooltips/text-tip/text-tip.component'; +import { AccessPolicyEntity, Action, ComponentResourceAction, PolicyStatus, ResourceAction } from '../../state/shared'; +import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import { loadTenants, resetTenantsState } from '../../state/tenants/tenants.actions'; +import { loadPolicyComponent, resetPolicyComponentState } from '../../state/policy-component/policy-component.actions'; +import { selectPolicyComponentState } from '../../state/policy-component/policy-component.selectors'; +import { PolicyComponentState } from '../../state/policy-component'; + +@Component({ + selector: 'global-access-policies', + templateUrl: './component-access-policies.component.html', + styleUrls: ['./component-access-policies.component.scss'] +}) +export class ComponentAccessPolicies implements OnInit, OnDestroy { + flowConfiguration$ = this.store.select(selectFlowConfiguration); + accessPolicyState$ = this.store.select(selectAccessPolicyState); + policyComponentState$ = this.store.select(selectPolicyComponentState); + currentUser$ = this.store.select(selectCurrentUser); + + protected readonly TextTip = TextTip; + protected readonly Action = Action; + protected readonly PolicyStatus = PolicyStatus; + protected readonly ComponentType = ComponentType; + + policyForm: FormGroup; + policyActionOptions: SelectOption[] = [ + { + text: 'view the component', + value: 'read-component', + description: 'Allows users to view component configuration details' + }, + { + text: 'modify the component', + value: 'write-component', + description: 'Allows users to modify component configuration details' + }, + { + text: 'operate the component', + value: 'write-operation', + description: + 'Allows users to operate components by changing component run status (start/stop/enable/disable), remote port transmission status, or terminating processor threads' + }, + { + text: 'view provenance', + value: 'read-provenance-data', + description: 'Allows users to view provenance events generated by this component' + }, + { + text: 'view the data', + value: 'read-data', + description: + 'Allows users to view metadata and content for this component in flowfile queues in outbound connections and through provenance events' + }, + { + text: 'modify the data', + value: 'write-data', + description: + 'Allows users to empty flowfile queues in outbound connections and submit replays through provenance events' + }, + { + text: 'receive data via site-to-site', + value: 'write-receive-data', + description: 'Allows this port to receive data from these NiFi instances', + disabled: true + }, + { + text: 'send data via site-to-site', + value: 'write-send-data', + description: 'Allows this port to send data to these NiFi instances', + disabled: true + }, + { + text: 'view the policies', + value: 'read-policies', + description: 'Allows users to view the list of users who can view/modify this component' + }, + { + text: 'modify the policies', + value: 'write-policies', + description: 'Allows users to modify the list of users who can view/modify this component' + } + ]; + + action!: Action; + resource!: string; + policy!: string; + resourceIdentifier!: string; + + @ViewChild('inheritedFromPolicies') inheritedFromPolicies!: TemplateRef; + @ViewChild('inheritedFromController') inheritedFromController!: TemplateRef; + @ViewChild('inheritedFromGlobalParameterContexts') inheritedFromGlobalParameterContexts!: TemplateRef; + @ViewChild('inheritedFromProcessGroup') inheritedFromProcessGroup!: TemplateRef; + + constructor( + private store: Store, + private formBuilder: FormBuilder, + private nifiCommon: NiFiCommon + ) { + this.policyForm = this.formBuilder.group({ + policyAction: new FormControl(this.policyActionOptions[0].value, Validators.required) + }); + + this.store + .select(selectComponentResourceActionFromRoute) + .pipe( + isDefinedAndNotNull(), + distinctUntilChanged((a, b) => { + return ( + a.action == b.action && + a.policy == b.policy && + a.resource == b.resource && + a.resourceIdentifier == b.resourceIdentifier + ); + }), + takeUntilDestroyed() + ) + .subscribe((componentResourceAction) => { + if (componentResourceAction) { + this.action = componentResourceAction.action; + this.policy = componentResourceAction.policy; + this.resource = componentResourceAction.resource; + this.resourceIdentifier = componentResourceAction.resourceIdentifier; + + // data transfer policies for site to site are presented different in the form so + // we need to distinguish by type + let policyForResource: string = this.policy; + if (this.policy === 'data-transfer') { + if (this.resource === 'input-ports') { + policyForResource = 'receive-data'; + } else { + policyForResource = 'send-data'; + } + } + + this.policyForm.get('policyAction')?.setValue(`${this.action}-${policyForResource}`); + + // component policies are presented simply as '/processors/1234' while non-component policies + // like viewing provenance for a specific component is presented as `/provenance-data/processors/1234` + let resourceToLoad: string = this.resource; + if (componentResourceAction.policy !== 'component') { + resourceToLoad = `${this.policy}/${this.resource}`; + } + + const resourceAction: ResourceAction = { + action: this.action, + resource: resourceToLoad, + resourceIdentifier: this.resourceIdentifier + }; + + this.store.dispatch( + loadPolicyComponent({ + request: { + componentResourceAction + } + }) + ); + this.store.dispatch( + setAccessPolicy({ + request: { + resourceAction + } + }) + ); + } + }); + } + + ngOnInit(): void { + this.store.dispatch(loadFlowConfiguration()); + this.store.dispatch(loadTenants()); + } + + isInitialLoading(state: AccessPolicyState): boolean { + return state.loadedTimestamp == initialState.loadedTimestamp; + } + + isComponentPolicy(option: SelectOption, policyComponentState: PolicyComponentState): boolean { + // consider the type of component to override which policies shouldn't be supported + + if (policyComponentState.resource === 'process-groups') { + switch (option.value) { + case 'write-send-data': + case 'write-receive-data': + return false; + } + } else if ( + policyComponentState.resource === 'controller-services' || + policyComponentState.resource === 'reporting-tasks' + ) { + switch (option.value) { + case 'read-data': + case 'write-data': + case 'write-send-data': + case 'write-receive-data': + case 'read-provenance-data': + return false; + } + } else if ( + policyComponentState.resource === 'parameter-contexts' || + policyComponentState.resource === 'parameter-providers' + ) { + switch (option.value) { + case 'read-data': + case 'write-data': + case 'write-send-data': + case 'write-receive-data': + case 'read-provenance-data': + case 'write-operation': + return false; + } + } else if (policyComponentState.resource === 'labels') { + switch (option.value) { + case 'write-operation': + case 'read-data': + case 'write-data': + case 'write-send-data': + case 'write-receive-data': + return false; + } + } else if (policyComponentState.resource === 'input-ports' && policyComponentState.allowRemoteAccess) { + // if input ports allow remote access, disable send data. if input ports do not allow remote + // access it will fall through to the else block where both send and receive data will be disabled + switch (option.value) { + case 'write-send-data': + return false; + } + } else if (policyComponentState.resource === 'output-ports' && policyComponentState.allowRemoteAccess) { + // if output ports allow remote access, disable receive data. if output ports do not allow remote + // access it will fall through to the else block where both send and receive data will be disabled + switch (option.value) { + case 'write-receive-data': + return false; + } + } else { + switch (option.value) { + case 'write-send-data': + case 'write-receive-data': + return false; + } + } + + // enable all other options + return true; + } + + getSelectOptionTipData(option: SelectOption): TextTipInput { + return { + // @ts-ignore + text: option.description + }; + } + + getContextIcon(): string { + switch (this.resource) { + case 'processors': + return 'icon-processor'; + case 'input-ports': + return 'icon-port-in'; + case 'output-ports': + return 'icon-port-out'; + case 'funnels': + return 'icon-funnel'; + case 'labels': + return 'icon-label'; + case 'remote-process-groups': + return 'icon-group-remote'; + case 'parameter-contexts': + return 'icon-drop'; + } + + return 'icon-group'; + } + + getContextType(): string { + switch (this.resource) { + case 'processors': + return 'Processor'; + case 'input-ports': + return 'Input Ports'; + case 'output-ports': + return 'Output Ports'; + case 'funnels': + return 'Funnel'; + case 'labels': + return 'Label'; + case 'remote-process-groups': + return 'Remote Process Group'; + case 'parameter-contexts': + return 'Parameter Contexts'; + } + + return 'Process Group'; + } + + policyActionChanged(value: string): void { + let action: Action; + let policy: string; + + switch (value) { + case 'read-component': + action = Action.Read; + policy = 'component'; + break; + case 'write-component': + action = Action.Write; + policy = 'component'; + break; + case 'write-operation': + action = Action.Write; + policy = 'operation'; + break; + case 'read-data': + action = Action.Read; + policy = 'data'; + break; + case 'write-data': + action = Action.Write; + policy = 'data'; + break; + case 'read-provenance-data': + action = Action.Read; + policy = 'provenance-data'; + break; + case 'read-policies': + action = Action.Read; + policy = 'policies'; + break; + case 'write-policies': + action = Action.Write; + policy = 'policies'; + break; + default: + action = Action.Write; + policy = 'data-transfer'; + break; + } + + this.store.dispatch( + selectComponentAccessPolicy({ + request: { + resourceAction: { + action, + policy, + resource: this.resource, + resourceIdentifier: this.resourceIdentifier + } + } + }) + ); + } + + getTemplateForInheritedPolicy(policy: AccessPolicyEntity): TemplateRef { + if (policy.component.resource.startsWith('/policies')) { + return this.inheritedFromPolicies; + } else if (policy.component.resource === '/controller') { + return this.inheritedFromController; + } else if (policy.component.resource === '/parameter-contexts') { + return this.inheritedFromGlobalParameterContexts; + } + + return this.inheritedFromProcessGroup; + } + + getInheritedProcessGroupRoute(policy: AccessPolicyEntity): string[] { + return ['/process-groups', this.nifiCommon.substringAfterLast(policy.component.resource, '/')]; + } + + createNewPolicy(): void { + this.store.dispatch(createAccessPolicy()); + } + + removeTenantFromPolicy(request: RemoveTenantFromPolicyRequest): void { + this.store.dispatch( + promptRemoveTenantFromPolicy({ + request + }) + ); + } + + addTenantToPolicy(): void { + this.store.dispatch(openAddTenantToPolicyDialog()); + } + + deletePolicy(): void { + this.store.dispatch(promptDeleteAccessPolicy()); + } + + refreshGlobalAccessPolicy(): void { + this.store.dispatch(reloadAccessPolicy()); + } + + ngOnDestroy(): void { + this.store.dispatch(resetAccessPolicyState()); + this.store.dispatch(resetTenantsState()); + this.store.dispatch(resetPolicyComponentState()); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.module.ts new file mode 100644 index 0000000000000..548ac64904442 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/component-access-policies/component-access-policies.module.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { ComponentAccessPolicies } from './component-access-policies.component'; +import { CommonModule } from '@angular/common'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { MatTableModule } from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatInputModule } from '@angular/material/input'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatSelectModule } from '@angular/material/select'; +import { ComponentAccessPoliciesRoutingModule } from './component-access-policies-routing.module'; +import { NifiTooltipDirective } from '../../../../ui/common/tooltips/nifi-tooltip.directive'; +import { PolicyTable } from '../common/policy-table/policy-table.component'; + +@NgModule({ + declarations: [ComponentAccessPolicies], + exports: [ComponentAccessPolicies], + imports: [ + CommonModule, + ComponentAccessPoliciesRoutingModule, + NgxSkeletonLoaderModule, + MatTableModule, + MatSortModule, + MatInputModule, + ReactiveFormsModule, + MatSelectModule, + NifiTooltipDirective, + PolicyTable + ] +}) +export class ComponentAccessPoliciesModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies-routing.module.ts new file mode 100644 index 0000000000000..ef4446978cefa --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies-routing.module.ts @@ -0,0 +1,50 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { GlobalAccessPolicies } from './global-access-policies.component'; +import { authorizationGuard } from '../../../../service/guard/authorization.guard'; +import { CurrentUser } from '../../../../state/current-user'; + +const routes: Routes = [ + { + path: ':action/:resource', + canMatch: [ + authorizationGuard( + (user: CurrentUser) => + user.tenantsPermissions.canRead && + user.policiesPermissions.canRead && + user.policiesPermissions.canWrite + ) + ], + component: GlobalAccessPolicies, + children: [ + { + path: ':resourceIdentifier', + component: GlobalAccessPolicies + } + ] + }, + { path: '', pathMatch: 'full', redirectTo: 'read/flow' } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class GlobalAccessPoliciesRoutingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.html new file mode 100644 index 0000000000000..035b7982028d8 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.html @@ -0,0 +1,160 @@ + + + +
    + +
    + + +
    +
    +
    + + No policy for the specified resource. + + Create a new policy. + + + + + + + + + Not authorized to access the policy for the specified resource. + +
    +
    +
    +
    +
    +
    + + Policy + + {{ option.text }} + + + +
    +
    + + Option + + {{ option.text }} + + + +
    +
    + + Action + + view + modify + + +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    +
    + +
    Last updated:
    +
    {{ accessPolicyState.loadedTimestamp }}
    +
    +
    +
    +
    +
    + + Showing effective policy inherited from all policies. + + Override this policy. + + + + Showing effective policy inherited from the controller. + + Override this policy. + + + + No restriction specific users. + + Create a new policy. + + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.scss new file mode 100644 index 0000000000000..59a35034165bb --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.scss @@ -0,0 +1,40 @@ +/*! + * 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. + */ + +.global-access-policies { + a { + font-size: 16px; + } + + .resource-select { + .mat-mdc-form-field { + width: 300px; + } + } + + .resource-identifier-select { + .mat-mdc-form-field { + width: 375px; + } + } + + .action-select { + .mat-mdc-form-field { + width: 150px; + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.spec.ts new file mode 100644 index 0000000000000..3171130730cbc --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.spec.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +import { GlobalAccessPolicies } from './global-access-policies.component'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { provideMockStore } from '@ngrx/store/testing'; +import { initialState } from '../../state/access-policy/access-policy.reducer'; + +describe('GlobalAccessPolicies', () => { + let component: GlobalAccessPolicies; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [GlobalAccessPolicies], + providers: [provideMockStore({ initialState })] + }); + fixture = TestBed.createComponent(GlobalAccessPolicies); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.ts new file mode 100644 index 0000000000000..6f0f7f89bd293 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.component.ts @@ -0,0 +1,306 @@ +/* + * 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. + */ + +import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; +import { + createAccessPolicy, + openAddTenantToPolicyDialog, + promptDeleteAccessPolicy, + promptRemoveTenantFromPolicy, + reloadAccessPolicy, + resetAccessPolicyState, + selectGlobalAccessPolicy, + setAccessPolicy +} from '../../state/access-policy/access-policy.actions'; +import { AccessPolicyState, RemoveTenantFromPolicyRequest } from '../../state/access-policy'; +import { initialState } from '../../state/access-policy/access-policy.reducer'; +import { + selectAccessPolicyState, + selectGlobalResourceActionFromRoute +} from '../../state/access-policy/access-policy.selectors'; +import { distinctUntilChanged, filter } from 'rxjs'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { NiFiCommon } from '../../../../service/nifi-common.service'; +import { + ComponentType, + isDefinedAndNotNull, + RequiredPermission, + SelectOption, + TextTipInput +} from '../../../../state/shared'; +import { TextTip } from '../../../../ui/common/tooltips/text-tip/text-tip.component'; +import { AccessPolicyEntity, Action, PolicyStatus, ResourceAction } from '../../state/shared'; +import { loadExtensionTypesForPolicies } from '../../../../state/extension-types/extension-types.actions'; +import { selectRequiredPermissions } from '../../../../state/extension-types/extension-types.selectors'; +import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import { AccessPoliciesState } from '../../state'; +import { loadTenants, resetTenantsState } from '../../state/tenants/tenants.actions'; +import { loadCurrentUser } from '../../../../state/current-user/current-user.actions'; + +@Component({ + selector: 'global-access-policies', + templateUrl: './global-access-policies.component.html', + styleUrls: ['./global-access-policies.component.scss'] +}) +export class GlobalAccessPolicies implements OnInit, OnDestroy { + flowConfiguration$ = this.store.select(selectFlowConfiguration); + accessPolicyState$ = this.store.select(selectAccessPolicyState); + currentUser$ = this.store.select(selectCurrentUser); + + protected readonly TextTip = TextTip; + protected readonly Action = Action; + protected readonly PolicyStatus = PolicyStatus; + protected readonly ComponentType = ComponentType; + + policyForm: FormGroup; + resourceOptions: SelectOption[]; + requiredPermissionOptions!: SelectOption[]; + supportsReadWriteAction: boolean = false; + supportsResourceIdentifier: boolean = false; + + @ViewChild('inheritedFromPolicies') inheritedFromPolicies!: TemplateRef; + @ViewChild('inheritedFromController') inheritedFromController!: TemplateRef; + @ViewChild('inheritedFromNoRestrictions') inheritedFromNoRestrictions!: TemplateRef; + + constructor( + private store: Store, + private formBuilder: FormBuilder, + private nifiCommon: NiFiCommon + ) { + this.resourceOptions = this.nifiCommon.getAllPolicyTypeListing(); + + this.policyForm = this.formBuilder.group({ + resource: new FormControl(null, Validators.required), + action: new FormControl(null, Validators.required) + }); + + this.store + .select(selectRequiredPermissions) + .pipe(takeUntilDestroyed()) + .subscribe((requiredPermissions: RequiredPermission[]) => { + const regardlessOfRestrictions: string = 'regardless of restrictions'; + + const options: SelectOption[] = [ + { + text: regardlessOfRestrictions, + value: '', + description: + 'Allows users to create/modify all restricted components regardless of restrictions.' + } + ]; + + options.push( + ...requiredPermissions.map((requiredPermission) => ({ + text: "requiring '" + requiredPermission.label + "'", + value: requiredPermission.id, + description: + "Allows users to create/modify restricted components requiring '" + + requiredPermission.label + + "'" + })) + ); + + this.requiredPermissionOptions = options.sort((a: SelectOption, b: SelectOption): number => { + if (a.text === regardlessOfRestrictions) { + return -1; + } else if (b.text === regardlessOfRestrictions) { + return 1; + } + + return this.nifiCommon.compareString(a.text, b.text); + }); + }); + + this.store + .select(selectGlobalResourceActionFromRoute) + .pipe( + isDefinedAndNotNull(), + distinctUntilChanged((a, b) => { + return ( + a.action == b.action && a.resource == b.resource && a.resourceIdentifier == b.resourceIdentifier + ); + }), + takeUntilDestroyed() + ) + .subscribe((resourceAction) => { + if (resourceAction) { + this.supportsReadWriteAction = this.globalPolicySupportsReadWrite(resourceAction.resource); + + this.policyForm.get('resource')?.setValue(resourceAction.resource); + this.policyForm.get('action')?.setValue(resourceAction.action); + + this.updateResourceIdentifierVisibility(resourceAction.resource); + + if (resourceAction.resource === 'restricted-components' && resourceAction.resourceIdentifier) { + this.policyForm.get('resourceIdentifier')?.setValue(resourceAction.resourceIdentifier); + } + + this.store.dispatch( + setAccessPolicy({ + request: { + resourceAction + } + }) + ); + } + }); + } + + ngOnInit(): void { + this.store.dispatch(loadFlowConfiguration()); + this.store.dispatch(loadTenants()); + this.store.dispatch(loadExtensionTypesForPolicies()); + } + + isInitialLoading(state: AccessPolicyState): boolean { + return state.loadedTimestamp == initialState.loadedTimestamp; + } + + getSelectOptionTipData(option: SelectOption): TextTipInput { + return { + // @ts-ignore + text: option.description + }; + } + + resourceChanged(value: string): void { + if (this.globalPolicySupportsReadWrite(value)) { + this.supportsReadWriteAction = true; + this.supportsResourceIdentifier = false; + + // reset the action + this.policyForm.get('action')?.setValue(Action.Read); + } else { + this.supportsReadWriteAction = false; + + // since this resource does not support read and write, update the form with the appropriate action this resource does support + this.policyForm.get('action')?.setValue(this.globalPolicySupportsWrite(value) ? Action.Write : Action.Read); + + this.updateResourceIdentifierVisibility(value); + } + + this.store.dispatch( + selectGlobalAccessPolicy({ + request: { + resourceAction: { + resource: this.policyForm.get('resource')?.value, + action: this.policyForm.get('action')?.value, + resourceIdentifier: this.policyForm.get('resourceIdentifier')?.value + } + } + }) + ); + } + + private globalPolicySupportsReadWrite(resource: string): boolean { + return ( + resource === 'controller' || + resource === 'parameter-contexts' || + resource === 'counters' || + resource === 'policies' || + resource === 'tenants' + ); + } + + private globalPolicySupportsWrite(resource: string): boolean { + return resource === 'proxy' || resource === 'restricted-components'; + } + + private updateResourceIdentifierVisibility(resource: string): void { + if (resource === 'restricted-components') { + this.supportsResourceIdentifier = true; + this.policyForm.addControl('resourceIdentifier', new FormControl('')); + } else { + this.supportsResourceIdentifier = false; + this.policyForm.removeControl('resourceIdentifier'); + } + } + + actionChanged(): void { + this.store.dispatch( + selectGlobalAccessPolicy({ + request: { + resourceAction: { + resource: this.policyForm.get('resource')?.value, + action: this.policyForm.get('action')?.value, + resourceIdentifier: this.policyForm.get('resourceIdentifier')?.value + } + } + }) + ); + } + + resourceIdentifierChanged(): void { + this.store.dispatch( + selectGlobalAccessPolicy({ + request: { + resourceAction: { + resource: this.policyForm.get('resource')?.value, + action: this.policyForm.get('action')?.value, + resourceIdentifier: this.policyForm.get('resourceIdentifier')?.value + } + } + }) + ); + } + + getTemplateForInheritedPolicy(policy: AccessPolicyEntity): TemplateRef { + if (policy.component.resource === '/policies') { + return this.inheritedFromPolicies; + } else if (policy.component.resource === '/controller') { + return this.inheritedFromController; + } + + return this.inheritedFromNoRestrictions; + } + + createNewPolicy(): void { + this.store.dispatch(createAccessPolicy()); + } + + removeTenantFromPolicy(request: RemoveTenantFromPolicyRequest): void { + this.store.dispatch( + promptRemoveTenantFromPolicy({ + request + }) + ); + } + + addTenantToPolicy(): void { + this.store.dispatch(openAddTenantToPolicyDialog()); + } + + deletePolicy(): void { + this.store.dispatch(promptDeleteAccessPolicy()); + } + + refreshGlobalAccessPolicy(): void { + this.store.dispatch(reloadAccessPolicy()); + } + + ngOnDestroy(): void { + // reload the current user to ensure the latest global policies + this.store.dispatch(loadCurrentUser()); + + this.store.dispatch(resetAccessPolicyState()); + this.store.dispatch(resetTenantsState()); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.module.ts new file mode 100644 index 0000000000000..8657202f9d0da --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/access-policies/ui/global-access-policies/global-access-policies.module.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { GlobalAccessPolicies } from './global-access-policies.component'; +import { CommonModule } from '@angular/common'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { MatTableModule } from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { MatInputModule } from '@angular/material/input'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatSelectModule } from '@angular/material/select'; +import { GlobalAccessPoliciesRoutingModule } from './global-access-policies-routing.module'; +import { NifiTooltipDirective } from '../../../../ui/common/tooltips/nifi-tooltip.directive'; +import { PolicyTable } from '../common/policy-table/policy-table.component'; + +@NgModule({ + declarations: [GlobalAccessPolicies], + exports: [GlobalAccessPolicies], + imports: [ + CommonModule, + GlobalAccessPoliciesRoutingModule, + NgxSkeletonLoaderModule, + MatTableModule, + MatSortModule, + MatInputModule, + ReactiveFormsModule, + MatSelectModule, + NifiTooltipDirective, + PolicyTable + ] +}) +export class GlobalAccessPoliciesModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.component.html index 5e212d9d69aa4..94f3467a2fd8f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.component.html @@ -15,14 +15,12 @@ ~ limitations under the License. --> -
    -
    +
    +
    + +
    +

    NiFi Bulletin Board

    - -
    -
    - +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.module.ts index f2f180b490d10..8d6f02b924697 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/feature/bulletins.module.ts @@ -25,6 +25,7 @@ import { BulletinBoardEffects } from '../state/bulletin-board/bulletin-board.eff import { BulletinsRoutingModule } from './bulletins-routing.module'; import { CounterListingModule } from '../../counters/ui/counter-listing/counter-listing.module'; import { BulletinBoard } from '../ui/bulletin-board/bulletin-board.component'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; @NgModule({ declarations: [Bulletins], @@ -35,7 +36,8 @@ import { BulletinBoard } from '../ui/bulletin-board/bulletin-board.component'; StoreModule.forFeature(bulletinsFeatureKey, reducers), EffectsModule.forFeature(BulletinBoardEffects), CounterListingModule, - BulletinBoard + BulletinBoard, + Navigation ] }) export class BulletinsModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/state/bulletin-board/bulletin-board.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/state/bulletin-board/bulletin-board.effects.ts index b24b18072751e..31417f205e300 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/state/bulletin-board/bulletin-board.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/bulletins/state/bulletin-board/bulletin-board.effects.ts @@ -16,12 +16,12 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { NiFiState } from '../../../../state'; import { Router } from '@angular/router'; import * as BulletinBoardActions from './bulletin-board.actions'; -import { asyncScheduler, from, interval, map, of, switchMap, takeUntil, withLatestFrom } from 'rxjs'; +import { asyncScheduler, from, interval, map, of, switchMap, takeUntil } from 'rxjs'; import { BulletinBoardService } from '../../service/bulletin-board.service'; import { selectBulletinBoardFilter, selectLastBulletinId } from './bulletin-board.selectors'; import { LoadBulletinBoardRequest } from './index'; @@ -77,7 +77,10 @@ export class BulletinBoardEffects { takeUntil(this.actions$.pipe(ofType(BulletinBoardActions.stopBulletinBoardPolling))) ) ), - withLatestFrom(this.store.select(selectBulletinBoardFilter), this.store.select(selectLastBulletinId)), + concatLatestFrom(() => [ + this.store.select(selectBulletinBoardFilter), + this.store.select(selectLastBulletinId) + ]), switchMap(([, filter, lastBulletinId]) => { const request: LoadBulletinBoardRequest = {}; if (lastBulletinId > 0) { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.html index 73fcf5e390ac5..6847c486aafa3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.html @@ -15,14 +15,12 @@ ~ limitations under the License. --> -
    -
    +
    +
    + +
    +

    NiFi Counters

    - -
    -
    - +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.spec.ts index e30779c978b8d..fba71a451e958 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.component.spec.ts @@ -22,15 +22,23 @@ import { initialState } from '../state/counter-listing/counter-listing.reducer'; import { CounterListing } from '../ui/counter-listing/counter-listing.component'; import { RouterModule } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { Component } from '@angular/core'; describe('Counters', () => { let component: Counters; let fixture: ComponentFixture; + @Component({ + selector: 'navigation', + standalone: true, + template: '' + }) + class MockNavigation {} + beforeEach(() => { TestBed.configureTestingModule({ declarations: [Counters, CounterListing], - imports: [RouterModule, RouterTestingModule], + imports: [RouterModule, RouterTestingModule, MockNavigation], providers: [provideMockStore({ initialState })] }); fixture = TestBed.createComponent(Counters); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.module.ts index 0d4d5d8939d44..1b8acdfa5c3b8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/feature/counters.module.ts @@ -25,6 +25,7 @@ import { EffectsModule } from '@ngrx/effects'; import { CounterListingEffects } from '../state/counter-listing/counter-listing.effects'; import { CounterListingModule } from '../ui/counter-listing/counter-listing.module'; import { MatDialogModule } from '@angular/material/dialog'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; @NgModule({ declarations: [Counters], @@ -35,7 +36,8 @@ import { MatDialogModule } from '@angular/material/dialog'; StoreModule.forFeature(countersFeatureKey, reducers), EffectsModule.forFeature(CounterListingEffects), CounterListingModule, - MatDialogModule + MatDialogModule, + Navigation ] }) export class CountersModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.html index ee1eb3580f292..6e44252da518d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.html @@ -44,6 +44,7 @@ [dataSource]="dataSource" matSort matSortDisableClear + (matSortChange)="sortData($event)" [matSortActive]="initialSortColumn" [matSortDirection]="initialSortDirection"> diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.ts index 36d95a6ce1ebd..2ae859dfcef9d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/counters/ui/counter-listing/counter-table/counter-table.component.ts @@ -15,10 +15,10 @@ * limitations under the License. */ -import { AfterViewInit, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; import { CounterEntity } from '../../../state/counter-listing'; import { MatTableDataSource } from '@angular/material/table'; -import { MatSort } from '@angular/material/sort'; +import { Sort } from '@angular/material/sort'; import { FormBuilder, FormGroup } from '@angular/forms'; import { debounceTime } from 'rxjs'; import { NiFiCommon } from '../../../../../service/nifi-common.service'; @@ -39,24 +39,14 @@ export class CounterTable implements AfterViewInit { dataSource: MatTableDataSource = new MatTableDataSource(); filterForm: FormGroup; - @Input() initialSortColumn: 'context' | 'name' = 'context'; + @Input() initialSortColumn: 'context' | 'name' | 'value' = 'context'; @Input() initialSortDirection: 'asc' | 'desc' = 'asc'; @Input() set counters(counterEntities: CounterEntity[]) { - this.dataSource = new MatTableDataSource(counterEntities); - this.dataSource.sort = this.sort; - this.dataSource.sortingDataAccessor = (data: CounterEntity, displayColumn: string) => { - switch (displayColumn) { - case 'context': - return this.formatContext(data); - case 'name': - return this.formatName(data); - case 'value': - return data.valueCount; - default: - return ''; - } - }; + this.dataSource.data = this.sortEntities(counterEntities, { + active: this.initialSortColumn, + direction: this.initialSortDirection + }); this.dataSource.filterPredicate = (data: CounterEntity, filter: string) => { const { filterTerm, filterColumn } = JSON.parse(filter); @@ -93,8 +83,6 @@ export class CounterTable implements AfterViewInit { @Output() resetCounter: EventEmitter = new EventEmitter(); - @ViewChild(MatSort) sort!: MatSort; - constructor( private formBuilder: FormBuilder, private nifiCommon: NiFiCommon @@ -103,8 +91,6 @@ export class CounterTable implements AfterViewInit { } ngAfterViewInit(): void { - this.dataSource.sort = this.sort; - this.filterForm .get('filterTerm') ?.valueChanges.pipe(debounceTime(500)) @@ -140,4 +126,32 @@ export class CounterTable implements AfterViewInit { event.stopPropagation(); this.resetCounter.next(counter); } + + sortData(sort: Sort) { + this.dataSource.data = this.sortEntities(this.dataSource.data, sort); + } + + private sortEntities(data: CounterEntity[], sort: Sort): CounterEntity[] { + if (!data) { + return []; + } + return data.slice().sort((a, b) => { + const isAsc = sort.direction === 'asc'; + let retVal = 0; + switch (sort.active) { + case 'name': + retVal = this.nifiCommon.compareString(this.formatName(a), this.formatName(b)); + break; + case 'value': + retVal = this.nifiCommon.compareNumber(a.valueCount, b.valueCount); + break; + case 'context': + retVal = this.nifiCommon.compareString(this.formatContext(a), this.formatContext(b)); + break; + default: + return 0; + } + return retVal * (isAsc ? 1 : -1); + }); + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts index e1fdf96d7ebe6..04ea46e637d89 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts @@ -28,6 +28,7 @@ import { canvasFeatureKey, reducers } from '../state'; import { MatDialogModule } from '@angular/material/dialog'; import { ControllerServicesEffects } from '../state/controller-services/controller-services.effects'; import { ParameterEffects } from '../state/parameter/parameter.effects'; +import { QueueEffects } from '../state/queue/queue.effects'; @NgModule({ declarations: [FlowDesigner, VersionControlTip], @@ -36,7 +37,13 @@ import { ParameterEffects } from '../state/parameter/parameter.effects'; CommonModule, FlowDesignerRoutingModule, StoreModule.forFeature(canvasFeatureKey, reducers), - EffectsModule.forFeature(FlowEffects, TransformEffects, ControllerServicesEffects, ParameterEffects), + EffectsModule.forFeature( + FlowEffects, + TransformEffects, + ControllerServicesEffects, + ParameterEffects, + QueueEffects + ), NgOptimizedImage, MatDialogModule ] diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts index 21a49215da7f1..e7273d5db2409 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts @@ -31,6 +31,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('ConnectableBehavior', () => { let service: ConnectableBehavior; @@ -40,7 +44,8 @@ describe('ConnectableBehavior', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -55,6 +60,10 @@ describe('ConnectableBehavior', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts index abf24c14855ab..d28a4c4168f73 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('DraggableBehavior', () => { let service: DraggableBehavior; @@ -41,7 +45,8 @@ describe('DraggableBehavior', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('DraggableBehavior', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts index bf1a38ea8afff..8a8074a875749 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('EditableBehaviorService', () => { let service: EditableBehavior; @@ -40,7 +44,8 @@ describe('EditableBehaviorService', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; beforeEach(() => { @@ -60,6 +65,10 @@ describe('EditableBehaviorService', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts index b9399b19cd772..e157963476440 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts @@ -31,6 +31,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('QuickSelectBehavior', () => { let service: QuickSelectBehavior; @@ -40,7 +44,8 @@ describe('QuickSelectBehavior', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -55,6 +60,10 @@ describe('QuickSelectBehavior', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts index 05a4f80321a49..52d05081a379d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts @@ -30,6 +30,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('SelectableBehavior', () => { let service: SelectableBehavior; @@ -39,7 +43,8 @@ describe('SelectableBehavior', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -54,6 +59,10 @@ describe('SelectableBehavior', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts index 235318deb7170..3545e43e46f2c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../state/current-user/current-user.sele import * as fromUser from '../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../state/parameter'; import * as fromParameter from '../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../queue/state'; +import * as fromQueue from '../state/queue/queue.reducer'; describe('BirdseyeView', () => { let service: BirdseyeView; @@ -41,7 +45,8 @@ describe('BirdseyeView', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('BirdseyeView', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts index 04fbca2d85cd9..1210caef125c4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-context-menu.service.ts @@ -30,18 +30,31 @@ import { navigateToControllerServicesForProcessGroup, navigateToEditComponent, navigateToEditCurrentProcessGroup, + navigateToManageComponentPolicies, navigateToProvenanceForComponent, + navigateToQueueListing, navigateToViewStatusHistoryForComponent, reloadFlow, - replayLastProvenanceEvent + replayLastProvenanceEvent, + runOnce, + startComponents, + startCurrentProcessGroup, + stopComponents, + stopCurrentProcessGroup } from '../state/flow/flow.actions'; import { ComponentType } from '../../../state/shared'; -import { DeleteComponentRequest, MoveComponentRequest } from '../state/flow'; +import { + DeleteComponentRequest, + MoveComponentRequest, + StartComponentRequest, + StopComponentRequest +} from '../state/flow'; import { ContextMenuDefinition, ContextMenuDefinitionProvider, ContextMenuItemDefinition } from '../../../ui/common/context-menu/context-menu.component'; +import { promptEmptyQueueRequest, promptEmptyQueuesRequest } from '../state/queue/queue.actions'; @Injectable({ providedIn: 'root' }) export class CanvasContextMenu implements ContextMenuDefinitionProvider { @@ -49,13 +62,13 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { id: 'version', menuItems: [ { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsStartFlowVersioning return false; }, clazz: 'fa fa-upload', text: 'Start version control', - action: function (store: Store) { + action: () => { // TODO - saveFlowVersion } }, @@ -63,57 +76,57 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsCommitFlowVersion return false; }, clazz: 'fa fa-upload', text: 'Commit local changes', - action: function (store: Store) { + action: () => { // TODO - saveFlowVersion } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsForceCommitFlowVersion return false; }, clazz: 'fa fa-upload', text: 'Commit local changes', - action: function (store: Store) { + action: () => { // TODO - forceSaveFlowVersion } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - hasLocalChanges return false; }, clazz: 'fa', text: 'Show local changes', - action: function (store: Store) { + action: () => { // TODO - showLocalChanges } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - hasLocalChanges return false; }, clazz: 'fa fa-undo', text: 'Revert local changes', - action: function (store: Store) { + action: () => { // TODO - revertLocalChanges } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsChangeFlowVersion return false; }, clazz: 'fa', text: 'Change version', - action: function (store: Store) { + action: () => { // TODO - changeFlowVersion } }, @@ -121,13 +134,13 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsStopFlowVersioning return false; }, clazz: 'fa', text: 'Stop version control', - action: function (store: Store) { + action: () => { // TODO - stopVersionControl } } @@ -138,14 +151,14 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { id: 'provenance-replay', menuItems: [ { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.canReplayComponentProvenance(selection); + condition: (selection: any) => { + return this.canvasUtils.canReplayComponentProvenance(selection); }, clazz: 'fa', text: 'All nodes', - action: function (store: Store, selection: any) { + action: (selection: any) => { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( replayLastProvenanceEvent({ request: { componentId: selectionData.id, @@ -156,14 +169,14 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.canReplayComponentProvenance(selection); + condition: (selection: any) => { + return this.canvasUtils.canReplayComponentProvenance(selection); }, clazz: 'fa', text: 'Primary node', - action: function (store: Store, selection: any) { + action: (selection: any) => { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( replayLastProvenanceEvent({ request: { componentId: selectionData.id, @@ -180,22 +193,22 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { id: 'upstream-downstream', menuItems: [ { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.hasUpstream(selection); + condition: (selection: any) => { + return this.canvasUtils.hasUpstream(selection); }, clazz: 'icon', text: 'Upstream', - action: function (store: Store) { + action: () => { // TODO - showUpstream } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.hasDownstream(selection); + condition: (selection: any) => { + return this.canvasUtils.hasDownstream(selection); }, clazz: 'icon', text: 'Downstream', - action: function (store: Store) { + action: () => { // TODO - showDownstream } } @@ -206,24 +219,24 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { id: 'align', menuItems: [ { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canAlign return false; }, clazz: 'fa fa-align-center fa-rotate-90', text: 'Horizontally', - action: function (store: Store) { + action: () => { // TODO - alignHorizontal } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canAlign return false; }, clazz: 'fa fa-align-center', text: 'Vertically', - action: function (store: Store) { + action: () => { // TODO - alignVertical } } @@ -234,24 +247,24 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { id: 'download', menuItems: [ { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsDownloadFlow return false; }, clazz: 'fa', text: 'Without external services', - action: function (store: Store) { + action: () => { // TODO - downloadFlowWithoutExternalServices } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - supportsDownloadFlow return false; }, clazz: 'fa', text: 'With external services', - action: function (store: Store) { + action: () => { // TODO - downloadFlowWithExternalServices } } @@ -262,40 +275,40 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { id: 'root', menuItems: [ { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.emptySelection(selection); + condition: (selection: any) => { + return this.canvasUtils.emptySelection(selection); }, clazz: 'fa fa-refresh', text: 'Refresh', - action: function (store: Store) { - store.dispatch(reloadFlow()); + action: () => { + this.store.dispatch(reloadFlow()); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isNotRootGroupAndEmptySelection(selection); + condition: (selection: any) => { + return this.canvasUtils.isNotRootGroupAndEmptySelection(selection); }, clazz: 'fa fa-level-up', text: 'Leave group', - action: function (store: Store) { - store.dispatch(leaveProcessGroup()); + action: () => { + this.store.dispatch(leaveProcessGroup()); } }, { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isConfigurable(selection); + condition: (selection: any) => { + return this.canvasUtils.isConfigurable(selection); }, clazz: 'fa fa-gear', text: 'Configure', - action: function (store: Store, selection: any) { + action: (selection: any) => { if (selection.empty()) { - store.dispatch(navigateToEditCurrentProcessGroup()); + this.store.dispatch(navigateToEditCurrentProcessGroup()); } else { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( navigateToEditComponent({ request: { type: selectionData.type, @@ -307,23 +320,23 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isProcessGroup(selection) || selection.empty(); + condition: (selection: any) => { + return this.canvasUtils.isProcessGroup(selection) || selection.empty(); }, clazz: 'fa fa-list', text: 'Controller Services', - action: function (store: Store, selection: any, canvasUtils: CanvasUtils) { + action: (selection: any) => { if (selection.empty()) { - store.dispatch( + this.store.dispatch( navigateToControllerServicesForProcessGroup({ request: { - id: canvasUtils.getProcessGroupId() + id: this.canvasUtils.getProcessGroupId() } }) ); } else { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( navigateToControllerServicesForProcessGroup({ request: { id: selectionData.id @@ -334,24 +347,24 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - hasDetails return false; }, clazz: 'fa fa-gear', text: 'View configuration', - action: function (store: Store, selection: any) { + action: (selection: any) => { // TODO - showDetails... Can we support read only and configurable in the same dialog/form? } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - hasParameterContext return false; }, clazz: 'fa', text: 'Parameters', - action: function (store: Store) { + action: () => { // TODO - open parameter context } }, @@ -367,16 +380,16 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isProcessGroup(selection); + condition: (selection: any) => { + return this.canvasUtils.isProcessGroup(selection); }, clazz: 'fa fa-sign-in', text: 'Enter group', - action: function (store: Store, selection: any) { + action: (selection: any) => { const d: any = selection.datum(); // enter the selected group - store.dispatch( + this.store.dispatch( enterProcessGroup({ request: { id: d.id @@ -389,133 +402,233 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - isRunnable - return false; + condition: (selection: any) => { + const startable = this.canvasUtils.getStartable(selection); + + // To mimic the operation palette behavior, offer the start context menu option if any of the selected items + // are runnable or can start transmitting. However, if all the startable components are RGPs, we will defer + // to the Enable Transmission menu option and not show the start option. + const allRpgs = + startable.filter((d: any) => d.type === ComponentType.RemoteProcessGroup).size() === + startable.size(); + + return this.canvasUtils.areAnyRunnable(selection) && !allRpgs; }, clazz: 'fa fa-play', text: 'Start', - action: function (store: Store) { - // TODO - start + action: (selection: any) => { + if (selection.empty()) { + // attempting to start the current process group + this.store.dispatch(startCurrentProcessGroup()); + } else { + const components: StartComponentRequest[] = []; + const startable = this.canvasUtils.getStartable(selection); + startable.each((d: any) => { + components.push({ + id: d.id, + uri: d.uri, + type: d.type, + revision: d.revision + }); + }); + this.store.dispatch( + startComponents({ + request: { + components + } + }) + ); + } } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - isStoppable - return false; + condition: (selection: any) => { + const stoppable = this.canvasUtils.getStoppable(selection); + + // To mimic the operation palette behavior, offer the stop context menu option if any of the selected items + // are runnable or can stop transmitting. However, if all the stoppable components are RGPs, we will defer + // to the Disable Transmission menu option and not show the start option. + const allRpgs = + stoppable.filter((d: any) => d.type === ComponentType.RemoteProcessGroup).size() === + stoppable.size(); + + return this.canvasUtils.areAnyStoppable(selection) && !allRpgs; }, clazz: 'fa fa-stop', text: 'Stop', - action: function (store: Store) { - // TODO - stop + action: (selection: any) => { + if (selection.empty()) { + // attempting to start the current process group + this.store.dispatch(stopCurrentProcessGroup()); + } else { + const components: StopComponentRequest[] = []; + const stoppable = this.canvasUtils.getStoppable(selection); + stoppable.each((d: any) => { + components.push({ + id: d.id, + uri: d.uri, + type: d.type, + revision: d.revision + }); + }); + this.store.dispatch( + stopComponents({ + request: { + components + } + }) + ); + } } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - isRunnableProcessor - return false; + condition: (selection: any) => { + if (selection.size() !== 1) { + return false; + } + return this.canvasUtils.areRunnable(selection) && this.canvasUtils.isProcessor(selection); }, clazz: 'fa fa-caret-right', text: 'Run Once', - action: function (store: Store) { - // TODO - runOnce + action: (selection: any) => { + const d: any = selection.datum(); + this.store.dispatch( + runOnce({ + request: { + uri: d.uri, + revision: d.revision + } + }) + ); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canTerminate return false; }, clazz: 'fa fa-hourglass-end', text: 'Terminate', - action: function (store: Store) { + action: () => { // TODO - terminate } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canEnable return false; }, clazz: 'fa fa-flash', text: 'Enable', - action: function (store: Store) { + action: () => { // TODO - enable } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canDisable return false; }, clazz: 'icon icon-enable-false', text: 'Disable', - action: function (store: Store) { + action: () => { // TODO - disable } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - canStartTransmission - return false; + condition: (selection: any) => { + return this.canvasUtils.canAllStartTransmitting(selection); }, clazz: 'fa fa-bullseye', text: 'Enable transmission', - action: function (store: Store) { - // TODO - enableTransmission + action: (selection: d3.Selection) => { + const components: StartComponentRequest[] = []; + const startable = this.canvasUtils.getStartable(selection); + startable.each((d: any) => { + components.push({ + id: d.id, + uri: d.uri, + type: d.type, + revision: d.revision + }); + }); + + this.store.dispatch( + startComponents({ + request: { + components + } + }) + ); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - canStopTransmission - return false; + condition: (selection: any) => { + return this.canvasUtils.canAllStopTransmitting(selection); }, clazz: 'icon icon-transmit-false', text: 'Disable transmission', - action: function (store: Store) { - // TODO - disableTransmission + action: (selection: d3.Selection) => { + const components: StopComponentRequest[] = []; + + const stoppable = this.canvasUtils.getStoppable(selection); + stoppable.each((d: any) => { + components.push({ + id: d.id, + uri: d.uri, + type: d.type, + revision: d.revision + }); + }); + this.store.dispatch( + stopComponents({ + request: { + components + } + }) + ); } }, { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isProcessGroup(selection); + condition: (selection: any) => { + return this.canvasUtils.isProcessGroup(selection); }, clazz: 'fa fa-flash', text: 'Enable all controller services', - action: function (store: Store) { + action: () => { // TODO - enableAllControllerServices } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.emptySelection(selection); + condition: (selection: any) => { + return this.canvasUtils.emptySelection(selection); }, clazz: 'fa fa-flash', text: 'Enable all controller services', - action: function (store: Store) { + action: () => { // TODO - enableAllControllerServices } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isProcessGroup(selection); + condition: (selection: any) => { + return this.canvasUtils.isProcessGroup(selection); }, clazz: 'icon icon-enable-false', text: 'Disable all controller services', - action: function (store: Store) { + action: () => { // TODO - disableAllControllerServices } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.emptySelection(selection); + condition: (selection: any) => { + return this.canvasUtils.emptySelection(selection); }, clazz: 'icon icon-enable-false', text: 'Disable all controller services', - action: function (store: Store) { + action: () => { // TODO - disableAllControllerServices } }, @@ -523,15 +636,15 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.canAccessComponentProvenance(selection); + condition: (selection: any) => { + return this.canvasUtils.canAccessComponentProvenance(selection); }, clazz: 'icon icon-provenance', // imgStyle: 'context-menu-provenance', text: 'View data provenance', - action: function (store: Store, selection: any) { + action: (selection: any) => { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( navigateToProvenanceForComponent({ id: selectionData.id }) @@ -547,14 +660,14 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: (canvasUtils: CanvasUtils, selection: any) => { - return canvasUtils.canViewStatusHistory(selection); + condition: (selection: any) => { + return this.canvasUtils.canViewStatusHistory(selection); }, clazz: 'fa fa-area-chart', text: 'View status history', - action: (store: Store, selection: any) => { + action: (selection: any) => { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( navigateToViewStatusHistoryForComponent({ request: { type: selectionData.type, @@ -565,35 +678,41 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - isStatefulProcessor return false; }, clazz: 'fa fa-tasks', text: 'View state', - action: function (store: Store) { + action: () => { // TODO - viewState } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - canListQueue - return false; + condition: (selection: any) => { + return this.canvasUtils.isConnection(selection); }, clazz: 'fa fa-list', text: 'List queue', - action: function (store: Store) { - // TODO - listQueue + action: (selection: any) => { + const selectionData = selection.datum(); + this.store.dispatch( + navigateToQueueListing({ + request: { + connectionId: selectionData.id + } + }) + ); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - hasUsage return false; }, clazz: 'fa fa-book', text: 'View usage', - action: function (store: Store) { + action: () => { // TODO - showUsage } }, @@ -606,12 +725,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isRemoteProcessGroup(selection); + condition: (selection: any) => { + return this.canvasUtils.isRemoteProcessGroup(selection); }, clazz: 'fa fa-refresh', text: 'Refresh remote', - action: function (store: Store) { + action: () => { // TODO - refreshRemoteFlow } }, @@ -619,34 +738,78 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isRemoteProcessGroup(selection); + condition: (selection: any) => { + return this.canvasUtils.isRemoteProcessGroup(selection); }, clazz: 'fa fa-cloud', text: 'Manage remote ports', - action: function (store: Store) { + action: () => { // TODO - remotePorts } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - canManagePolicies - return false; + condition: (selection: any) => { + return ( + this.canvasUtils.supportsManagedAuthorizer() && this.canvasUtils.canManagePolicies(selection) + ); }, clazz: 'fa fa-key', text: 'Manage access policies', - action: function (store: Store) { - // TODO - managePolicies + action: (selection: any) => { + if (selection.empty()) { + this.store.dispatch( + navigateToManageComponentPolicies({ + request: { + resource: 'process-groups', + id: this.canvasUtils.getProcessGroupId() + } + }) + ); + } else { + const selectionData = selection.datum(); + const componentType: ComponentType = selectionData.type; + + let resource: string = 'process-groups'; + switch (componentType) { + case ComponentType.Processor: + resource = 'processors'; + break; + case ComponentType.InputPort: + resource = 'input-ports'; + break; + case ComponentType.OutputPort: + resource = 'output-ports'; + break; + case ComponentType.Funnel: + resource = 'funnels'; + break; + case ComponentType.Label: + resource = 'labels'; + break; + case ComponentType.RemoteProcessGroup: + resource = 'remote-process-groups'; + break; + } + + this.store.dispatch( + navigateToManageComponentPolicies({ + request: { + resource, + id: selectionData.id + } + }) + ); + } } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canChangeProcessorVersion return false; }, clazz: 'fa fa-exchange', text: 'Change version', - action: function (store: Store) { + action: () => { // TODO - changeVersion } }, @@ -654,20 +817,20 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isConnection(selection); + condition: (selection: any) => { + return this.canvasUtils.isConnection(selection); }, clazz: 'fa fa-long-arrow-left', text: 'Go to source', - action: function (store: Store, selection: any, canvasUtils: CanvasUtils) { + action: (selection: any) => { const selectionData = selection.datum(); - const remoteConnectableType: string = canvasUtils.getConnectableTypeForSource( + const remoteConnectableType: string = this.canvasUtils.getConnectableTypeForSource( ComponentType.RemoteProcessGroup ); // if the source is remote if (selectionData.sourceType == remoteConnectableType) { - store.dispatch( + this.store.dispatch( navigateToComponent({ request: { id: selectionData.sourceGroupId, @@ -676,12 +839,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { }) ); } else { - const type: ComponentType | null = canvasUtils.getComponentTypeForSource( + const type: ComponentType | null = this.canvasUtils.getComponentTypeForSource( selectionData.sourceType ); if (type) { - store.dispatch( + this.store.dispatch( navigateToComponent({ request: { id: selectionData.sourceId, @@ -695,20 +858,20 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isConnection(selection); + condition: (selection: any) => { + return this.canvasUtils.isConnection(selection); }, clazz: 'fa fa-long-arrow-right', text: 'Go to destination', - action: function (store: Store, selection: any, canvasUtils: CanvasUtils) { + action: (selection: any) => { const selectionData = selection.datum(); - const remoteConnectableType: string = canvasUtils.getConnectableTypeForDestination( + const remoteConnectableType: string = this.canvasUtils.getConnectableTypeForDestination( ComponentType.RemoteProcessGroup ); // if the source is remote if (selectionData.destinationType == remoteConnectableType) { - store.dispatch( + this.store.dispatch( navigateToComponent({ request: { id: selectionData.destinationGroupId, @@ -717,12 +880,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { }) ); } else { - const type: ComponentType | null = canvasUtils.getComponentTypeForDestination( + const type: ComponentType | null = this.canvasUtils.getComponentTypeForDestination( selectionData.destinationType ); if (type) { - store.dispatch( + this.store.dispatch( navigateToComponent({ request: { id: selectionData.destinationId, @@ -744,44 +907,44 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { subMenuId: this.ALIGN.id }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - canMoveToFront return false; }, clazz: 'fa fa-clone', text: 'Bring to front', - action: function (store: Store) { + action: () => { // TODO - toFront } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return selection.size() === 1 && !canvasUtils.isConnection(selection); + condition: (selection: any) => { + return selection.size() === 1 && !this.canvasUtils.isConnection(selection); }, clazz: 'fa fa-crosshairs', text: 'Center in view', - action: function (store: Store) { - store.dispatch(centerSelectedComponent()); + action: () => { + this.store.dispatch(centerSelectedComponent()); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - isColorable return false; }, clazz: 'fa fa-paint-brush', text: 'Change color', - action: function (store: Store) { + action: () => { // TODO - fillColor } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isRemoteProcessGroup(selection); + condition: (selection: any) => { + return this.canvasUtils.isRemoteProcessGroup(selection); }, clazz: 'fa fa-external-link', text: 'Go to', - action: function (store: Store) { + action: () => { // TODO - openUri } }, @@ -789,12 +952,12 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isNotRootGroup(); + condition: (selection: any) => { + return this.canvasUtils.isNotRootGroup(); }, clazz: 'fa fa-arrows', text: 'Move to parent group', - action: function (store: Store, selection: any, canvasUtils: CanvasUtils) { + action: (selection: any) => { const components: MoveComponentRequest[] = []; selection.each(function (d: any) { components.push({ @@ -806,24 +969,24 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { }); // move the selection into the group - store.dispatch( + this.store.dispatch( moveComponents({ request: { components, // @ts-ignore - groupId: canvasUtils.getParentProcessGroupId() + groupId: this.canvasUtils.getParentProcessGroupId() } }) ); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isDisconnected(selection); + condition: (selection: any) => { + return this.canvasUtils.isDisconnected(selection); }, - clazz: 'icon icon-group', + clazz: 'fa icon-group', text: 'Group', - action: function (store: Store, selection: any, canvasUtils: CanvasUtils) { + action: (selection: any) => { const moveComponents: MoveComponentRequest[] = []; selection.each(function (d: any) { moveComponents.push({ @@ -835,11 +998,11 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { }); // move the selection into the group - store.dispatch( + this.store.dispatch( getParameterContextsAndOpenGroupComponentsDialog({ request: { moveComponents, - position: canvasUtils.getOrigin(selection) + position: this.canvasUtils.getOrigin(selection) } }) ); @@ -857,24 +1020,24 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - isCopyable return false; }, clazz: 'fa fa-copy', text: 'Copy', - action: function (store: Store) { + action: () => { // TODO - copy } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { + condition: (selection: any) => { // TODO - isPastable return false; }, clazz: 'fa fa-paste', text: 'Paste', - action: function (store: Store) { + action: () => { // TODO - paste } }, @@ -882,46 +1045,57 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { isSeparator: true }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - // TODO - canEmptyQueue - return false; + condition: (selection: any) => { + return this.canvasUtils.isConnection(selection); }, clazz: 'fa fa-minus-circle', text: 'Empty queue', - action: function (store: Store) { - // TODO - emptyQueue - } - }, - { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.isProcessGroup(selection); - }, - clazz: 'fa fa-minus-circle', - text: 'Empty all queues', - action: function (store: Store) { - // TODO - emptyAllQueues in selected PG + action: (selection: any) => { + const selectionData = selection.datum(); + + this.store.dispatch( + promptEmptyQueueRequest({ + request: { + connectionId: selectionData.id + } + }) + ); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.emptySelection(selection); + condition: (selection: any) => { + return selection.empty() || this.canvasUtils.isProcessGroup(selection); }, clazz: 'fa fa-minus-circle', text: 'Empty all queues', - action: function (store: Store) { - // TODO - emptyAllQueues in current PG + action: (selection: any) => { + let processGroupId: string; + if (selection.empty()) { + processGroupId = this.canvasUtils.getProcessGroupId(); + } else { + const selectionData = selection.datum(); + processGroupId = selectionData.id; + } + + this.store.dispatch( + promptEmptyQueuesRequest({ + request: { + processGroupId + } + }) + ); } }, { - condition: function (canvasUtils: CanvasUtils, selection: any) { - return canvasUtils.areDeletable(selection); + condition: (selection: any) => { + return this.canvasUtils.areDeletable(selection); }, clazz: 'fa fa-trash', text: 'Delete', - action: function (store: Store, selection: any) { + action: (selection: any) => { if (selection.size() === 1) { const selectionData = selection.datum(); - store.dispatch( + this.store.dispatch( deleteComponents({ request: [ { @@ -943,7 +1117,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { entity: d }); }); - store.dispatch( + this.store.dispatch( deleteComponents({ request: requests }) @@ -978,7 +1152,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { // include if the condition matches if (menuItem.condition) { - return menuItem.condition(this.canvasUtils, selection); + return menuItem.condition(selection); } // include if there is no condition (non conditional item, separator, sub menu, etc) @@ -988,7 +1162,7 @@ export class CanvasContextMenu implements ContextMenuDefinitionProvider { menuItemClicked(menuItem: ContextMenuItemDefinition, event: MouseEvent): void { if (menuItem.action) { const selection = this.canvasUtils.getSelection(); - menuItem.action(this.store, selection, this.canvasUtils, event); + menuItem.action(selection, event); } } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts index 26bb27db85fc6..45013d9b60ab1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts @@ -31,6 +31,10 @@ import { selectCurrentUser } from '../../../state/current-user/current-user.sele import * as fromUser from '../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../state/parameter'; import * as fromParameter from '../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../queue/state'; +import * as fromQueue from '../state/queue/queue.reducer'; describe('CanvasUtils', () => { let service: CanvasUtils; @@ -40,7 +44,8 @@ describe('CanvasUtils', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -55,6 +60,10 @@ describe('CanvasUtils', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.ts index 53c0f413915e7..4e5152060927f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.ts @@ -35,6 +35,9 @@ import { NiFiCommon } from '../../../service/nifi-common.service'; import { CurrentUser } from '../../../state/current-user'; import { initialState as initialUserState } from '../../../state/current-user/current-user.reducer'; import { selectCurrentUser } from '../../../state/current-user/current-user.selectors'; +import { FlowConfiguration } from '../../../state/flow-configuration'; +import { initialState as initialFlowConfigurationState } from '../../../state/flow-configuration/flow-configuration.reducer'; +import { selectFlowConfiguration } from '../../../state/flow-configuration/flow-configuration.selectors'; @Injectable({ providedIn: 'root' @@ -49,6 +52,7 @@ export class CanvasUtils { private parentProcessGroupId: string | null = initialFlowState.flow.processGroupFlow.parentGroupId; private canvasPermissions: Permissions = initialFlowState.flow.permissions; private currentUser: CurrentUser = initialUserState.user; + private flowConfiguration: FlowConfiguration | null = initialFlowConfigurationState.flowConfiguration; private connections: any[] = []; private readonly humanizeDuration: Humanizer; @@ -94,6 +98,13 @@ export class CanvasUtils { .subscribe((user) => { this.currentUser = user; }); + + this.store + .select(selectFlowConfiguration) + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((flowConfiguration) => { + this.flowConfiguration = flowConfiguration; + }); } public hasDownstream(selection: any): boolean { @@ -453,6 +464,40 @@ export class CanvasUtils { return selection.size() === 1 && selection.classed('funnel'); } + /** + * Determines whether the user can configure or open the policy management page. + */ + public canManagePolicies(selection: any): boolean { + // ensure 0 or 1 components selected + if (selection.size() <= 1) { + // if something is selected, ensure it's not a connection + if (!selection.empty() && this.isConnection(selection)) { + return false; + } + + // ensure access to read tenants + return this.canAccessTenants(); + } + + return false; + } + + public supportsManagedAuthorizer(): boolean { + if (this.flowConfiguration) { + return this.flowConfiguration.supportsManagedAuthorizer; + } + return false; + } + + /** + * Determines whether the current user can access tenants. + * + * @returns {boolean} + */ + public canAccessTenants(): boolean { + return this.currentUser.tenantsPermissions.canRead === true; + } + /** * Determines whether the current user can access provenance for the specified component. * @@ -1200,4 +1245,237 @@ export class CanvasUtils { } return '#ffffff'; } + + /** + * Determines if the components in the specified selection are runnable. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection is runnable + */ + public areRunnable(selection: d3.Selection): boolean { + if (selection.empty()) { + return true; + } + + let runnable = true; + selection.each((data, index, nodes) => { + if (!this.isRunnable(d3.select(nodes[index]))) { + runnable = false; + } + }); + return runnable; + } + + /** + * Determines if any of the components in the specified selection are runnable or can start transmitting. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection is runnable + */ + public areAnyRunnable(selection: d3.Selection): boolean { + if (selection.empty()) { + return true; + } + + let runnable = false; + selection.each((data, index, nodes) => { + const d = d3.select(nodes[index]); + if (this.isRunnable(d) || this.canStartTransmitting(d)) { + runnable = true; + } + }); + return runnable; + } + + /** + * Determines if the component in the specified selection is runnable. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection is runnable + */ + public isRunnable(selection: d3.Selection): boolean { + if (selection.size() !== 1) { + return false; + } + if (this.isProcessGroup(selection)) { + return true; + } + if (!this.canOperate(selection)) { + return false; + } + + let runnable = false; + const selectionData = selection.datum(); + if (this.isProcessor(selection) || this.isInputPort(selection) || this.isOutputPort(selection)) { + runnable = + this.supportsModification(selection) && selectionData.status.aggregateSnapshot.runStatus === 'Stopped'; + } + return runnable; + } + + /** + * Determines if the components in the specified selection are stoppable. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection is stoppable + */ + public areStoppable(selection: d3.Selection): boolean { + if (selection.empty()) { + return true; + } + + let stoppable = true; + selection.each((data, index, nodes) => { + if (!this.isStoppable(d3.select(nodes[index]))) { + stoppable = false; + } + }); + + return stoppable; + } + + /** + * Determines if any of the components in the specified selection are stoppable. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection is stoppable + */ + public areAnyStoppable(selection: d3.Selection): boolean { + if (selection.empty()) { + return true; + } + + let stoppable = false; + selection.each((data, index, nodes) => { + const d = d3.select(nodes[index]); + if (this.isStoppable(d) || this.canStopTransmitting(d)) { + stoppable = true; + } + }); + + return stoppable; + } + + /** + * Determines if the component in the specified selection is runnable. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection is runnable + */ + public isStoppable(selection: d3.Selection): boolean { + if (selection.size() !== 1) { + return false; + } + if (this.isProcessGroup(selection)) { + return true; + } + if (!this.canOperate(selection)) { + return false; + } + + let stoppable = false; + const selectionData = selection.datum(); + if (this.isProcessor(selection) || this.isInputPort(selection) || this.isOutputPort(selection)) { + stoppable = selectionData.status.aggregateSnapshot.runStatus === 'Running'; + } + return stoppable; + } + + public getStartable(selection: d3.Selection) { + return selection.filter((d, index, nodes) => { + const context = nodes[index]; + return this.isRunnable(d3.select(context)) || this.canStartTransmitting(d3.select(context)); + }); + } + + public getStoppable(selection: d3.Selection) { + return selection.filter((d, index, nodes) => { + const context = nodes[index]; + return this.isStoppable(d3.select(context)) || this.canStopTransmitting(d3.select(context)); + }); + } + + public canAllStartTransmitting(selection: d3.Selection): boolean { + if (selection.empty()) { + return false; + } + + let canStartTransmitting = true; + selection.each((data, index, nodes) => { + if (!this.canStartTransmitting(d3.select(nodes[index]))) { + canStartTransmitting = false; + } + }); + return canStartTransmitting; + } + + /** + * Determines if the components in the specified selection support starting transmission. + * + * @param {d3.Selection} selection + */ + public canStartTransmitting(selection: d3.Selection): boolean { + if (selection.size() !== 1) { + return false; + } + + if ((!this.canModify(selection) || !this.canRead(selection)) && !this.canOperate(selection)) { + return false; + } + + return this.isRemoteProcessGroup(selection); + } + + /** + * Determines if the components in the specified selection support stopping transmission. + * + * @param {d3.Selection} selection + */ + public canStopTransmitting(selection: d3.Selection): boolean { + if (selection.size() !== 1) { + return false; + } + + if ((!this.canModify(selection) || this.canRead(selection)) && !this.canOperate(selection)) { + return false; + } + + return this.isRemoteProcessGroup(selection); + } + + /** + * Determines if the specified selection can all stop transmitting. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection can stop transmitting + */ + public canAllStopTransmitting(selection: d3.Selection): boolean { + if (selection.empty()) { + return false; + } + + let canStopTransmitting = true; + selection.each((data, index, nodes) => { + if (!this.canStopTransmitting(d3.select(nodes[index]))) { + canStopTransmitting = false; + } + }); + return canStopTransmitting; + } + /** + * Determines whether the components in the specified selection can be operated. + * + * @argument {d3.Selection} selection The selection + * @return {boolean} Whether the selection can be operated + */ + public canOperate(selection: d3.Selection): boolean { + const selectionSize = selection.size(); + const writableSize = selection + .filter((d) => { + return d.permissions.canWrite || d.operatePermissions?.canWrite; + }) + .size(); + + return selectionSize === writableSize; + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts index 0f90774ceb164..dffdec8902bed 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../state/current-user/current-user.sele import * as fromUser from '../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../state/parameter'; import * as fromParameter from '../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../queue/state'; +import * as fromQueue from '../state/queue/queue.reducer'; describe('CanvasView', () => { let service: CanvasView; @@ -41,7 +45,8 @@ describe('CanvasView', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('CanvasView', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.ts index 73dbfd04a64b7..b65dd312b75b4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.ts @@ -188,6 +188,11 @@ export class CanvasView { public updateCanvasVisibility(): void { const self: CanvasView = this; const canvasContainer: any = document.getElementById('canvas-container'); + + if (canvasContainer == null) { + return; + } + let translate = [this.x, this.y]; const scale = this.k; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts index a547a7604c567..b2acac85805dc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts @@ -16,18 +16,25 @@ */ import { Injectable } from '@angular/core'; -import { Observable, throwError } from 'rxjs'; +import { Observable } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { CanvasUtils } from './canvas-utils.service'; import { + ComponentRunStatusRequest, CreateComponentRequest, CreateConnection, CreatePortRequest, CreateProcessGroupRequest, CreateProcessorRequest, DeleteComponentRequest, + ProcessGroupRunStatusRequest, ReplayLastProvenanceEventRequest, + RunOnceRequest, Snippet, + StartComponentRequest, + StartProcessGroupRequest, + StopComponentRequest, + StopProcessGroupRequest, UpdateComponentRequest, UploadProcessGroupRequest } from '../state/flow'; @@ -59,12 +66,12 @@ export class FlowService { return this.nifiCommon.substringAfterFirst(url, ':'); } - getFlow(processGroupId: string = 'root'): Observable { + getFlow(processGroupId = 'root'): Observable { // TODO - support uiOnly... this would mean that we need to load the entire resource prior to editing return this.httpClient.get(`${FlowService.API}/flow/process-groups/${processGroupId}`); } - getProcessGroupStatus(processGroupId: string = 'root', recursive: boolean = false): Observable { + getProcessGroupStatus(processGroupId = 'root', recursive = false): Observable { return this.httpClient.get(`${FlowService.API}/flow/process-groups/${processGroupId}/status`, { params: { recursive: recursive } }); @@ -112,7 +119,7 @@ export class FlowService { return this.httpClient.get(`${FlowService.API}/process-groups/${id}`); } - createFunnel(processGroupId: string = 'root', createFunnel: CreateComponentRequest): Observable { + createFunnel(processGroupId = 'root', createFunnel: CreateComponentRequest): Observable { return this.httpClient.post(`${FlowService.API}/process-groups/${processGroupId}/funnels`, { revision: createFunnel.revision, component: { @@ -121,7 +128,7 @@ export class FlowService { }); } - createLabel(processGroupId: string = 'root', createLabel: CreateComponentRequest): Observable { + createLabel(processGroupId = 'root', createLabel: CreateComponentRequest): Observable { return this.httpClient.post(`${FlowService.API}/process-groups/${processGroupId}/labels`, { revision: createLabel.revision, component: { @@ -130,7 +137,7 @@ export class FlowService { }); } - createProcessor(processGroupId: string = 'root', createProcessor: CreateProcessorRequest): Observable { + createProcessor(processGroupId = 'root', createProcessor: CreateProcessorRequest): Observable { return this.httpClient.post(`${FlowService.API}/process-groups/${processGroupId}/processors`, { revision: createProcessor.revision, component: { @@ -141,17 +148,14 @@ export class FlowService { }); } - createConnection(processGroupId: string = 'root', createConnection: CreateConnection): Observable { + createConnection(processGroupId = 'root', createConnection: CreateConnection): Observable { return this.httpClient.post( `${FlowService.API}/process-groups/${processGroupId}/connections`, createConnection.payload ); } - createProcessGroup( - processGroupId: string = 'root', - createProcessGroup: CreateProcessGroupRequest - ): Observable { + createProcessGroup(processGroupId = 'root', createProcessGroup: CreateProcessGroupRequest): Observable { const payload: any = { revision: createProcessGroup.revision, component: { @@ -169,10 +173,7 @@ export class FlowService { return this.httpClient.post(`${FlowService.API}/process-groups/${processGroupId}/process-groups`, payload); } - uploadProcessGroup( - processGroupId: string = 'root', - uploadProcessGroup: UploadProcessGroupRequest - ): Observable { + uploadProcessGroup(processGroupId = 'root', uploadProcessGroup: UploadProcessGroupRequest): Observable { const payload = new FormData(); payload.append('id', processGroupId); payload.append('groupName', uploadProcessGroup.name); @@ -197,7 +198,7 @@ export class FlowService { }); } - createPort(processGroupId: string = 'root', createPort: CreatePortRequest): Observable { + createPort(processGroupId = 'root', createPort: CreatePortRequest): Observable { const portType: string = ComponentType.InputPort == createPort.type ? 'input-ports' : 'output-ports'; return this.httpClient.post(`${FlowService.API}/process-groups/${processGroupId}/${portType}`, { revision: createPort.revision, @@ -242,4 +243,71 @@ export class FlowService { replayLastProvenanceEvent(request: ReplayLastProvenanceEventRequest): Observable { return this.httpClient.post(`${FlowService.API}/provenance-events/latest/replays`, request); } + + runOnce(request: RunOnceRequest): Observable { + const startRequest: ComponentRunStatusRequest = { + revision: request.revision, + disconnectedNodeAcknowledged: false, + state: 'RUN_ONCE' + }; + return this.httpClient.put(`${this.stripProtocol(request.uri)}/run-status`, startRequest); + } + + startComponent(request: StartComponentRequest): Observable { + const startRequest: ComponentRunStatusRequest = { + revision: request.revision, + disconnectedNodeAcknowledged: false, + state: request.type === ComponentType.RemoteProcessGroup ? 'TRANSMITTING' : 'RUNNING' + }; + return this.httpClient.put(`${this.stripProtocol(request.uri)}/run-status`, startRequest); + } + + stopComponent(request: StopComponentRequest): Observable { + const stopRequest: ComponentRunStatusRequest = { + revision: request.revision, + disconnectedNodeAcknowledged: false, + state: 'STOPPED' + }; + return this.httpClient.put(`${this.stripProtocol(request.uri)}/run-status`, stopRequest); + } + + startProcessGroup(request: StartProcessGroupRequest): Observable { + const startRequest: ProcessGroupRunStatusRequest = { + id: request.id, + disconnectedNodeAcknowledged: false, + state: 'RUNNING' + }; + return this.httpClient.put(`${FlowService.API}/flow/process-groups/${request.id}`, startRequest); + } + + startRemoteProcessGroupsInProcessGroup(request: StartProcessGroupRequest): Observable { + const startRequest = { + disconnectedNodeAcknowledged: false, + state: 'TRANSMITTING' + }; + return this.httpClient.put( + `${FlowService.API}/remote-process-groups/process-group/${request.id}/run-status`, + startRequest + ); + } + + stopProcessGroup(request: StopProcessGroupRequest): Observable { + const stopRequest: ProcessGroupRunStatusRequest = { + id: request.id, + disconnectedNodeAcknowledged: false, + state: 'STOPPED' + }; + return this.httpClient.put(`${FlowService.API}/flow/process-groups/${request.id}`, stopRequest); + } + + stopRemoteProcessGroupsInProcessGroup(request: StopProcessGroupRequest): Observable { + const stopRequest = { + disconnectedNodeAcknowledged: false, + state: 'STOPPED' + }; + return this.httpClient.put( + `${FlowService.API}/remote-process-groups/process-group/${request.id}/run-status`, + stopRequest + ); + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts index 991223e6d9767..f369a961d485b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('ConnectionManager', () => { let service: ConnectionManager; @@ -41,7 +45,8 @@ describe('ConnectionManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('ConnectionManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts index ae48fc3e682c2..a48d1ac593cf0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('FunnelManager', () => { let service: FunnelManager; @@ -41,7 +45,8 @@ describe('FunnelManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('FunnelManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts index 2876e24c06f95..94d58725efea1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('LabelManager', () => { let service: LabelManager; @@ -41,7 +45,8 @@ describe('LabelManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('LabelManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts index 91c78137d55d2..009f256fd70c1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('PortManager', () => { let service: PortManager; @@ -41,7 +45,8 @@ describe('PortManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('PortManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts index fd45d417d9309..cc01af6a998c0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('ProcessGroupManager', () => { let service: ProcessGroupManager; @@ -41,7 +45,8 @@ describe('ProcessGroupManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('ProcessGroupManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts index 022eb13d46200..677b4d2badd1f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('ProcessorManager', () => { let service: ProcessorManager; @@ -41,7 +45,8 @@ describe('ProcessorManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('ProcessorManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts index 5ba295003af97..0ac01b7d2be35 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts @@ -32,6 +32,10 @@ import { selectCurrentUser } from '../../../../state/current-user/current-user.s import * as fromUser from '../../../../state/current-user/current-user.reducer'; import { parameterFeatureKey } from '../../state/parameter'; import * as fromParameter from '../../state/parameter/parameter.reducer'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import * as fromFlowConfiguration from '../../../../state/flow-configuration/flow-configuration.reducer'; +import { queueFeatureKey } from '../../../queue/state'; +import * as fromQueue from '../../state/queue/queue.reducer'; describe('RemoteProcessGroupManager', () => { let service: RemoteProcessGroupManager; @@ -41,7 +45,8 @@ describe('RemoteProcessGroupManager', () => { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, [controllerServicesFeatureKey]: fromControllerServices.initialState, - [parameterFeatureKey]: fromParameter.initialState + [parameterFeatureKey]: fromParameter.initialState, + [queueFeatureKey]: fromQueue.initialState }; TestBed.configureTestingModule({ @@ -60,6 +65,10 @@ describe('RemoteProcessGroupManager', () => { { selector: selectCurrentUser, value: fromUser.initialState.user + }, + { + selector: selectFlowConfiguration, + value: fromFlowConfiguration.initialState.flowConfiguration } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/queue.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/queue.service.ts new file mode 100644 index 0000000000000..df242809f39f4 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/queue.service.ts @@ -0,0 +1,67 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { NiFiCommon } from '../../../service/nifi-common.service'; +import { DropRequest, SubmitEmptyQueueRequest, SubmitEmptyQueuesRequest } from '../state/queue'; + +@Injectable({ providedIn: 'root' }) +export class QueueService { + private static readonly API: string = '../nifi-api'; + + constructor( + private httpClient: HttpClient, + private nifiCommon: NiFiCommon + ) {} + + /** + * The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling + * does not work on absolute URLs, so we need to strip off the proto for the request header to be added. + * + * https://stackoverflow.com/a/59586462 + * + * @param url + * @private + */ + private stripProtocol(url: string): string { + return this.nifiCommon.substringAfterFirst(url, ':'); + } + + submitEmptyQueueRequest(emptyQueueRequest: SubmitEmptyQueueRequest): Observable { + return this.httpClient.post( + `${QueueService.API}/flowfile-queues/${emptyQueueRequest.connectionId}/drop-requests`, + {} + ); + } + + submitEmptyQueuesRequest(emptyQueuesRequest: SubmitEmptyQueuesRequest): Observable { + return this.httpClient.post( + `${QueueService.API}/process-groups/${emptyQueuesRequest.processGroupId}/empty-all-connections-requests`, + {} + ); + } + + pollEmptyQueueRequest(dropRequest: DropRequest): Observable { + return this.httpClient.get(this.stripProtocol(dropRequest.uri)); + } + + deleteEmptyQueueRequest(dropRequest: DropRequest): Observable { + return this.httpClient.delete(this.stripProtocol(dropRequest.uri)); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts index ecb9f3a5c65bb..4efe9641bee59 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts @@ -16,7 +16,7 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as ControllerServicesActions from './controller-services.actions'; import { catchError, @@ -30,8 +30,7 @@ import { switchMap, take, takeUntil, - tap, - withLatestFrom + tap } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -119,10 +118,10 @@ export class ControllerServicesEffects { () => this.actions$.pipe( ofType(ControllerServicesActions.openNewControllerServiceDialog), - withLatestFrom( + concatLatestFrom(() => [ this.store.select(selectControllerServiceTypes), this.store.select(selectCurrentProcessGroupId) - ), + ]), tap(([action, controllerServiceTypes, processGroupId]) => { const dialogReference = this.dialog.open(CreateControllerService, { data: { @@ -196,7 +195,7 @@ export class ControllerServicesEffects { this.actions$.pipe( ofType(ControllerServicesActions.navigateToEditService), map((action) => action.id), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([id, processGroupId]) => { this.router.navigate(['/process-groups', processGroupId, 'controller-services', id, 'edit']); }) @@ -209,10 +208,10 @@ export class ControllerServicesEffects { this.actions$.pipe( ofType(ControllerServicesActions.openConfigureControllerServiceDialog), map((action) => action.request), - withLatestFrom( + concatLatestFrom(() => [ this.store.select(selectCurrentParameterContext), this.store.select(selectCurrentProcessGroupId) - ), + ]), tap(([request, parameterContext, processGroupId]) => { const serviceId: string = request.id; @@ -555,7 +554,7 @@ export class ControllerServicesEffects { this.actions$.pipe( ofType(ControllerServicesActions.openEnableControllerServiceDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([request, currentProcessGroupId]) => { const serviceId: string = request.id; @@ -595,7 +594,7 @@ export class ControllerServicesEffects { this.actions$.pipe( ofType(ControllerServicesActions.openDisableControllerServiceDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([request, currentProcessGroupId]) => { const serviceId: string = request.id; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts index b4c47bb5fa5b9..a6c616670fd5e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.actions.ts @@ -17,24 +17,24 @@ import { createAction, props } from '@ngrx/store'; import { + ComponentEntity, CreateComponentRequest, CreateComponentResponse, CreateConnection, CreateConnectionDialogRequest, CreateConnectionRequest, CreatePortRequest, - CreateProcessGroupRequest, CreateProcessGroupDialogRequest, + CreateProcessGroupRequest, CreateProcessorRequest, DeleteComponentRequest, DeleteComponentResponse, EditComponentDialogRequest, - OpenComponentDialogRequest, EditConnectionDialogRequest, + EditCurrentProcessGroupRequest, EnterProcessGroupRequest, - GroupComponentsRequest, GroupComponentsDialogRequest, - OpenGroupComponentsDialogRequest, + GroupComponentsRequest, GroupComponentsSuccess, LoadConnectionSuccess, LoadInputPortSuccess, @@ -44,93 +44,122 @@ import { LoadRemoteProcessGroupSuccess, MoveComponentsRequest, NavigateToComponentRequest, + NavigateToControllerServicesRequest, + NavigateToManageComponentPoliciesRequest, + OpenComponentDialogRequest, + OpenGroupComponentsDialogRequest, + LoadChildProcessGroupRequest, + ReplayLastProvenanceEventRequest, + RunOnceRequest, + RunOnceResponse, SelectComponentsRequest, - UpdateComponentRequest, + StartComponentRequest, + StartComponentResponse, + StartComponentsRequest, + StartProcessGroupRequest, + StopComponentRequest, + StopComponentResponse, + StopComponentsRequest, + StopProcessGroupRequest, UpdateComponentFailure, + UpdateComponentRequest, UpdateComponentResponse, UpdateConnectionRequest, UpdateConnectionSuccess, UpdatePositionsRequest, UploadProcessGroupRequest, - EditCurrentProcessGroupRequest, - NavigateToControllerServicesRequest, - ReplayLastProvenanceEventRequest + NavigateToQueueListing } from './index'; import { StatusHistoryRequest } from '../../../../state/status-history'; +const CANVAS_PREFIX = '[Canvas]'; + /* Loading Flow */ -export const resetFlowState = createAction('[Canvas] Reset Flow State'); +export const resetFlowState = createAction(`${CANVAS_PREFIX} Reset Flow State`); -export const reloadFlow = createAction('[Canvas] Reload Flow'); +export const reloadFlow = createAction(`${CANVAS_PREFIX} Reload Flow`); -export const leaveProcessGroup = createAction('[Canvas] Leave Process Group'); +export const leaveProcessGroup = createAction(`${CANVAS_PREFIX} Leave Process Group`); export const enterProcessGroup = createAction( - '[Canvas] Enter Process Group', + `${CANVAS_PREFIX} Enter Process Group`, props<{ request: EnterProcessGroupRequest }>() ); export const loadProcessGroup = createAction( - '[Canvas] Load Process Group', + `${CANVAS_PREFIX} Load Process Group`, props<{ request: LoadProcessGroupRequest }>() ); export const loadProcessGroupSuccess = createAction( - '[Canvas] Load Process Group Success', + `${CANVAS_PREFIX} Load Process Group Success`, props<{ response: LoadProcessGroupResponse }>() ); export const loadProcessGroupComplete = createAction( - '[Canvas] Load Process Group Complete', + `${CANVAS_PREFIX} Load Process Group Complete`, props<{ response: LoadProcessGroupResponse }>() ); -export const flowApiError = createAction('[Canvas] Flow Api Error', props<{ error: string }>()); +export const loadChildProcessGroup = createAction( + `${CANVAS_PREFIX} Load Child Process Group`, + props<{ request: LoadChildProcessGroupRequest }>() +); + +export const loadChildProcessGroupSuccess = createAction( + `${CANVAS_PREFIX} Load Child Process Group Success`, + props<{ response: ComponentEntity }>() +); -export const clearFlowApiError = createAction('[Canvas] Clear Flow Api Error'); +export const flowApiError = createAction(`${CANVAS_PREFIX} Flow Api Error`, props<{ error: string }>()); -export const startProcessGroupPolling = createAction('[Canvas] Start Process Group Polling'); +export const clearFlowApiError = createAction(`${CANVAS_PREFIX} Clear Flow Api Error`); -export const stopProcessGroupPolling = createAction('[Canvas] Stop Process Group Polling'); +export const startProcessGroupPolling = createAction(`${CANVAS_PREFIX} Start Process Group Polling`); + +export const stopProcessGroupPolling = createAction(`${CANVAS_PREFIX} Stop Process Group Polling`); export const loadConnectionsForComponent = createAction( - '[Canvas] Load Connections For Component', + `${CANVAS_PREFIX} Load Connections For Component`, props<{ id: string }>() ); -export const loadConnection = createAction('[Canvas] Load Connection', props<{ id: string }>()); +export const loadConnection = createAction(`${CANVAS_PREFIX} Load Connection`, props<{ id: string }>()); export const loadConnectionSuccess = createAction( - '[Canvas] Load Connection Success', + `${CANVAS_PREFIX} Load Connection Success`, props<{ response: LoadConnectionSuccess }>() ); export const loadComponentsForConnection = createAction( - '[Canvas] Load Components For Connection', + `${CANVAS_PREFIX} Load Components For Connection`, props<{ connection: any }>() ); -export const loadProcessor = createAction('[Canvas] Load Processor', props<{ id: string }>()); +export const loadProcessor = createAction(`${CANVAS_PREFIX} Load Processor`, props<{ id: string }>()); export const loadProcessorSuccess = createAction( - '[Canvas] Load Processor Success', + `${CANVAS_PREFIX} Load Processor Success`, props<{ response: LoadProcessorSuccess }>() ); -export const loadInputPort = createAction('[Canvas] Load Input Port', props<{ id: string }>()); +export const loadInputPort = createAction(`${CANVAS_PREFIX} Load Input Port`, props<{ id: string }>()); export const loadInputPortSuccess = createAction( - '[Canvas] Load Input Port Success', + `${CANVAS_PREFIX} Load Input Port Success`, props<{ response: LoadInputPortSuccess }>() ); -export const loadRemoteProcessGroup = createAction('[Canvas] Load Remote Process Group', props<{ id: string }>()); +export const loadRemoteProcessGroup = createAction( + `${CANVAS_PREFIX} Load Remote Process Group`, + props<{ id: string }>() +); export const loadRemoteProcessGroupSuccess = createAction( - '[Canvas] Load Remote Process Group Success', + `${CANVAS_PREFIX} Load Remote Process Group Success`, props<{ response: LoadRemoteProcessGroupSuccess }>() ); @@ -139,112 +168,124 @@ export const loadRemoteProcessGroupSuccess = createAction( */ export const addSelectedComponents = createAction( - '[Canvas] Add Selected Component', + `${CANVAS_PREFIX} Add Selected Component`, props<{ request: SelectComponentsRequest }>() ); export const selectComponents = createAction( - '[Canvas] Select Components', + `${CANVAS_PREFIX} Select Components`, props<{ request: SelectComponentsRequest }>() ); -export const deselectAllComponents = createAction('[Canvas] Deselect All Components'); +export const deselectAllComponents = createAction(`${CANVAS_PREFIX} Deselect All Components`); export const removeSelectedComponents = createAction( - '[Canvas] Remove Selected Components', + `${CANVAS_PREFIX} Remove Selected Components`, props<{ request: SelectComponentsRequest }>() ); -export const centerSelectedComponent = createAction('[Canvas] Center Selected Component'); +export const centerSelectedComponent = createAction(`${CANVAS_PREFIX} Center Selected Component`); /* Create Component Actions */ export const createComponentRequest = createAction( - '[Canvas] Create Component Request', + `${CANVAS_PREFIX} Create Component Request`, props<{ request: CreateComponentRequest }>() ); -export const createFunnel = createAction('[Canvas] Create Funnel', props<{ request: CreateComponentRequest }>()); +export const createFunnel = createAction( + `${CANVAS_PREFIX} Create Funnel`, + props<{ request: CreateComponentRequest }>() +); -export const createLabel = createAction('[Canvas] Create Label', props<{ request: CreateComponentRequest }>()); +export const createLabel = createAction(`${CANVAS_PREFIX} Create Label`, props<{ request: CreateComponentRequest }>()); export const openNewProcessGroupDialog = createAction( - '[Canvas] Open New Process Group Dialog', + `${CANVAS_PREFIX} Open New Process Group Dialog`, props<{ request: CreateProcessGroupDialogRequest }>() ); export const createProcessGroup = createAction( - '[Canvas] Create Process Group', + `${CANVAS_PREFIX} Create Process Group`, props<{ request: CreateProcessGroupRequest }>() ); export const uploadProcessGroup = createAction( - '[Canvas] Upload Process Group', + `${CANVAS_PREFIX} Upload Process Group`, props<{ request: UploadProcessGroupRequest }>() ); export const getParameterContextsAndOpenGroupComponentsDialog = createAction( - '[Canvas] Get Parameter Contexts And Open Group Components Dialog', + `${CANVAS_PREFIX} Get Parameter Contexts And Open Group Components Dialog`, props<{ request: OpenGroupComponentsDialogRequest }>() ); export const openGroupComponentsDialog = createAction( - '[Canvas] Open Group Components Dialog', + `${CANVAS_PREFIX} Open Group Components Dialog`, props<{ request: GroupComponentsDialogRequest }>() ); -export const groupComponents = createAction('[Canvas] Group Components', props<{ request: GroupComponentsRequest }>()); +export const groupComponents = createAction( + `${CANVAS_PREFIX} Group Components`, + props<{ request: GroupComponentsRequest }>() +); export const groupComponentsSuccess = createAction( - '[Canvas] Group Components Success', + `${CANVAS_PREFIX} Group Components Success`, props<{ response: GroupComponentsSuccess }>() ); export const openNewProcessorDialog = createAction( - '[Canvas] Open New Processor Dialog', + `${CANVAS_PREFIX} Open New Processor Dialog`, props<{ request: CreateComponentRequest }>() ); -export const createProcessor = createAction('[Canvas] Create Processor', props<{ request: CreateProcessorRequest }>()); +export const createProcessor = createAction( + `${CANVAS_PREFIX} Create Processor`, + props<{ request: CreateProcessorRequest }>() +); export const getDefaultsAndOpenNewConnectionDialog = createAction( - '[Canvas] Get Defaults And Open New Connection Dialog', + `${CANVAS_PREFIX} Get Defaults And Open New Connection Dialog`, props<{ request: CreateConnectionRequest }>() ); export const openNewConnectionDialog = createAction( - '[Canvas] Open New Connection Dialog', + `${CANVAS_PREFIX} Open New Connection Dialog`, props<{ request: CreateConnectionDialogRequest }>() ); -export const createConnection = createAction('[Canvas] Create Connection', props<{ request: CreateConnection }>()); +export const createConnection = createAction( + `${CANVAS_PREFIX} Create Connection`, + props<{ request: CreateConnection }>() +); export const openNewPortDialog = createAction( - '[Canvas] Open New Port Dialog', + `${CANVAS_PREFIX} Open New Port Dialog`, props<{ request: CreateComponentRequest }>() ); -export const createPort = createAction('[Canvas] Create Port', props<{ request: CreatePortRequest }>()); +export const createPort = createAction(`${CANVAS_PREFIX} Create Port`, props<{ request: CreatePortRequest }>()); export const createComponentSuccess = createAction( - '[Canvas] Create Component Success', + `${CANVAS_PREFIX} Create Component Success`, props<{ response: CreateComponentResponse }>() ); export const createComponentComplete = createAction( - '[Canvas] Create Component Complete', + `${CANVAS_PREFIX} Create Component Complete`, props<{ response: CreateComponentResponse }>() ); export const navigateToViewStatusHistoryForComponent = createAction( - '[Canvas] Navigate To Status History For Component', + `${CANVAS_PREFIX} Navigate To Status History For Component`, props<{ request: OpenComponentDialogRequest }>() ); export const viewStatusHistoryForComponent = createAction( - '[Canvas] View Status History for Component', + `${CANVAS_PREFIX} View Status History for Component`, props<{ request: StatusHistoryRequest }>() ); /* @@ -252,95 +293,122 @@ export const viewStatusHistoryForComponent = createAction( */ export const navigateToEditComponent = createAction( - '[Canvas] Navigate To Edit Component', + `${CANVAS_PREFIX} Navigate To Edit Component`, props<{ request: OpenComponentDialogRequest }>() ); -export const editComponent = createAction('[Canvas] Edit Component', props<{ request: EditComponentDialogRequest }>()); +export const navigateToManageComponentPolicies = createAction( + `${CANVAS_PREFIX} Navigate To Manage Component Policies`, + props<{ request: NavigateToManageComponentPoliciesRequest }>() +); + +export const editComponent = createAction( + `${CANVAS_PREFIX} Edit Component`, + props<{ request: EditComponentDialogRequest }>() +); -export const navigateToEditCurrentProcessGroup = createAction('[Canvas] Navigate To Edit Current Process Group'); +export const navigateToEditCurrentProcessGroup = createAction( + `${CANVAS_PREFIX} Navigate To Edit Current Process Group` +); export const navigateToControllerServicesForProcessGroup = createAction( - '[Canvas] Navigate To Controller Services For Process Group', + `${CANVAS_PREFIX} Navigate To Controller Services For Process Group`, props<{ request: NavigateToControllerServicesRequest }>() ); +export const navigateToQueueListing = createAction( + `${CANVAS_PREFIX} Navigate To Queue Listing`, + props<{ request: NavigateToQueueListing }>() +); + export const editCurrentProcessGroup = createAction( - '[Canvas] Edit Current Process Group', + `${CANVAS_PREFIX} Edit Current Process Group`, props<{ request: EditCurrentProcessGroupRequest; }>() ); export const openEditPortDialog = createAction( - '[Canvas] Open Edit Port Dialog', + `${CANVAS_PREFIX} Open Edit Port Dialog`, props<{ request: EditComponentDialogRequest }>() ); export const openEditProcessorDialog = createAction( - '[Canvas] Open Edit Processor Dialog', + `${CANVAS_PREFIX} Open Edit Processor Dialog`, props<{ request: EditComponentDialogRequest }>() ); export const openEditConnectionDialog = createAction( - '[Canvas] Open Edit Connection Dialog', + `${CANVAS_PREFIX} Open Edit Connection Dialog`, props<{ request: EditConnectionDialogRequest }>() ); export const openEditProcessGroupDialog = createAction( - '[Canvas] Open Edit Process Group Dialog', + `${CANVAS_PREFIX} Open Edit Process Group Dialog`, props<{ request: EditComponentDialogRequest }>() ); -export const updateComponent = createAction('[Canvas] Update Component', props<{ request: UpdateComponentRequest }>()); +export const updateComponent = createAction( + `${CANVAS_PREFIX} Update Component`, + props<{ request: UpdateComponentRequest }>() +); export const updateComponentSuccess = createAction( - '[Canvas] Update Component Success', + `${CANVAS_PREFIX} Update Component Success`, props<{ response: UpdateComponentResponse }>() ); export const updateComponentFailure = createAction( - '[Canvas] Update Component Failure', + `${CANVAS_PREFIX} Update Component Failure`, props<{ response: UpdateComponentFailure }>() ); -export const updateProcessor = createAction('[Canvas] Update Processor', props<{ request: UpdateComponentRequest }>()); +export const updateProcessor = createAction( + `${CANVAS_PREFIX} Update Processor`, + props<{ request: UpdateComponentRequest }>() +); export const updateProcessorSuccess = createAction( - '[Canvas] Update Processor Success', + `${CANVAS_PREFIX} Update Processor Success`, props<{ response: UpdateComponentResponse }>() ); export const updateConnection = createAction( - '[Canvas] Update Connection', + `${CANVAS_PREFIX} Update Connection`, props<{ request: UpdateConnectionRequest }>() ); export const updateConnectionSuccess = createAction( - '[Canvas] Update Connection Success', + `${CANVAS_PREFIX} Update Connection Success`, props<{ response: UpdateConnectionSuccess }>() ); -export const updatePositions = createAction('[Canvas] Update Positions', props<{ request: UpdatePositionsRequest }>()); +export const updatePositions = createAction( + `${CANVAS_PREFIX} Update Positions`, + props<{ request: UpdatePositionsRequest }>() +); export const updatePositionComplete = createAction( - '[Canvas] Update Position Complete', + `${CANVAS_PREFIX} Update Position Complete`, props<{ response: UpdateComponentResponse }>() ); -export const moveComponents = createAction('[Canvas] Move Components', props<{ request: MoveComponentsRequest }>()); +export const moveComponents = createAction( + `${CANVAS_PREFIX} Move Components`, + props<{ request: MoveComponentsRequest }>() +); /* Delete Component Actions */ export const deleteComponents = createAction( - '[Canvas] Delete Components', + `${CANVAS_PREFIX} Delete Components`, props<{ request: DeleteComponentRequest[] }>() ); export const deleteComponentsSuccess = createAction( - '[Canvas] Delete Components Success', + `${CANVAS_PREFIX} Delete Components Success`, props<{ response: DeleteComponentResponse[] }>() ); @@ -348,33 +416,39 @@ export const deleteComponentsSuccess = createAction( Transition */ -export const setDragging = createAction('[Canvas] Set Dragging', props<{ dragging: boolean }>()); +export const setDragging = createAction(`${CANVAS_PREFIX} Set Dragging`, props<{ dragging: boolean }>()); export const setTransitionRequired = createAction( - '[Canvas] Set Transition Required', + `${CANVAS_PREFIX} Set Transition Required`, props<{ transitionRequired: boolean }>() ); -export const setSkipTransform = createAction('[Canvas] Set Skip Transform', props<{ skipTransform: boolean }>()); +export const setSkipTransform = createAction( + `${CANVAS_PREFIX} Set Skip Transform`, + props<{ skipTransform: boolean }>() +); export const navigateToComponent = createAction( - '[Canvas] Navigate To Component', + `${CANVAS_PREFIX} Navigate To Component`, props<{ request: NavigateToComponentRequest }>() ); -export const navigateWithoutTransform = createAction('[Canvas] Navigate Without Transform', props<{ url: string[] }>()); +export const navigateWithoutTransform = createAction( + `${CANVAS_PREFIX} Navigate Without Transform`, + props<{ url: string[] }>() +); /* Palette actions */ export const setNavigationCollapsed = createAction( - '[Canvas] Set Navigation Collapsed', + `${CANVAS_PREFIX} Set Navigation Collapsed`, props<{ navigationCollapsed: boolean }>() ); export const setOperationCollapsed = createAction( - '[Canvas] Set Operation Collapsed', + `${CANVAS_PREFIX} Set Operation Collapsed`, props<{ operationCollapsed: boolean }>() ); @@ -382,19 +456,60 @@ export const setOperationCollapsed = createAction( General */ -export const showOkDialog = createAction('[Canvas] Show Ok Dialog', props<{ title: string; message: string }>()); +export const showOkDialog = createAction( + `${CANVAS_PREFIX} Show Ok Dialog`, + props<{ title: string; message: string }>() +); export const renderConnectionsForComponent = createAction( - '[Canvas] Render Connections For Component', + `${CANVAS_PREFIX} Render Connections For Component`, props<{ id: string; updatePath: boolean; updateLabel: boolean }>() ); export const navigateToProvenanceForComponent = createAction( - '[Canvas] Navigate To Provenance For Component', + `${CANVAS_PREFIX} Navigate To Provenance For Component`, props<{ id: string }>() ); export const replayLastProvenanceEvent = createAction( - '[Canvas] Replay Last Provenance Event', + `${CANVAS_PREFIX} Replay Last Provenance Event`, props<{ request: ReplayLastProvenanceEventRequest }>() ); + +export const runOnce = createAction(`${CANVAS_PREFIX} Run Once`, props<{ request: RunOnceRequest }>()); + +export const runOnceSuccess = createAction(`${CANVAS_PREFIX} Run Once Success`, props<{ response: RunOnceResponse }>()); + +export const startComponent = createAction( + `${CANVAS_PREFIX} Start Component`, + props<{ request: StartComponentRequest | StartProcessGroupRequest }>() +); + +export const startComponents = createAction( + `${CANVAS_PREFIX} Start Components`, + props<{ request: StartComponentsRequest }>() +); + +export const startComponentSuccess = createAction( + `${CANVAS_PREFIX} Start Component Success`, + props<{ response: StartComponentResponse }>() +); + +export const stopComponent = createAction( + `${CANVAS_PREFIX} Stop Component`, + props<{ request: StopComponentRequest | StopProcessGroupRequest }>() +); + +export const stopComponents = createAction( + `${CANVAS_PREFIX} Stop Components`, + props<{ request: StopComponentsRequest }>() +); + +export const stopComponentSuccess = createAction( + `${CANVAS_PREFIX} Stop Component Success`, + props<{ response: StopComponentResponse }>() +); + +export const startCurrentProcessGroup = createAction(`${CANVAS_PREFIX} Start Current Process Group`); + +export const stopCurrentProcessGroup = createAction(`${CANVAS_PREFIX} Stop Current Process Group`); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts index edc6ec953ca49..bb2208c6db192 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts @@ -17,7 +17,7 @@ import { Injectable } from '@angular/core'; import { FlowService } from '../../service/flow.service'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as FlowActions from './flow.actions'; import * as ParameterActions from '../parameter/parameter.actions'; import * as StatusHistoryActions from '../../../../state/status-history/status-history.actions'; @@ -36,8 +36,7 @@ import { switchMap, take, takeUntil, - tap, - withLatestFrom + tap } from 'rxjs'; import { CreateProcessGroupDialogRequest, @@ -96,7 +95,6 @@ import { OkDialog } from '../../../../ui/common/ok-dialog/ok-dialog.component'; import { GroupComponents } from '../../ui/canvas/items/process-group/group-components/group-components.component'; import { EditProcessGroup } from '../../ui/canvas/items/process-group/edit-process-group/edit-process-group.component'; import { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component'; -import * as ControllerServicesActions from '../controller-services/controller-services.actions'; import { ExtensionTypesService } from '../../../../service/extension-types.service'; import { ControllerServiceService } from '../../service/controller-service.service'; import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; @@ -125,7 +123,7 @@ export class FlowEffects { reloadFlow$ = createEffect(() => this.actions$.pipe( ofType(FlowActions.reloadFlow), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([action, processGroupId]) => { return of( FlowActions.loadProcessGroup({ @@ -215,7 +213,7 @@ export class FlowEffects { return of(FlowActions.openNewProcessorDialog({ request })); case ComponentType.ProcessGroup: return from(this.flowService.getParameterContexts()).pipe( - withLatestFrom(this.store.select(selectCurrentParameterContext)), + concatLatestFrom(() => this.store.select(selectCurrentParameterContext)), map(([response, parameterContext]) => { const dialogRequest: CreateProcessGroupDialogRequest = { request, @@ -249,7 +247,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.openNewProcessorDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectProcessorTypes)), + concatLatestFrom(() => this.store.select(selectProcessorTypes)), tap(([request, processorTypes]) => { this.dialog .open(CreateProcessor, { @@ -272,7 +270,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.createProcessor), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createProcessor(processGroupId, request)).pipe( map((response) => @@ -313,7 +311,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.createProcessGroup), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createProcessGroup(processGroupId, request)).pipe( map((response) => @@ -334,7 +332,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.uploadProcessGroup), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.uploadProcessGroup(processGroupId, request)).pipe( map((response) => @@ -355,10 +353,10 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.getParameterContextsAndOpenGroupComponentsDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, currentProcessGroupId]) => from(this.flowService.getParameterContexts()).pipe( - withLatestFrom(this.store.select(selectCurrentParameterContext)), + concatLatestFrom(() => this.store.select(selectCurrentParameterContext)), map(([response, parameterContext]) => { const dialogRequest: GroupComponentsDialogRequest = { request, @@ -403,7 +401,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.groupComponents), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createProcessGroup(processGroupId, request)).pipe( map((response) => @@ -447,7 +445,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.getDefaultsAndOpenNewConnectionDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, currentProcessGroupId]) => from(this.flowService.getProcessGroup(currentProcessGroupId)).pipe( map((response) => @@ -506,7 +504,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.createConnection), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createConnection(processGroupId, request)).pipe( map((response) => @@ -548,7 +546,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.createPort), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createPort(processGroupId, request)).pipe( map((response) => @@ -569,7 +567,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.createFunnel), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createFunnel(processGroupId, request)).pipe( map((response) => @@ -590,7 +588,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.createLabel), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => from(this.flowService.createLabel(processGroupId, request)).pipe( map((response) => @@ -654,7 +652,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.navigateToEditComponent), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([request, processGroupId]) => { this.router.navigate(['/process-groups', processGroupId, request.type, request.id, 'edit']); }) @@ -666,7 +664,7 @@ export class FlowEffects { () => this.actions$.pipe( ofType(FlowActions.navigateToEditCurrentProcessGroup), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([action, processGroupId]) => { this.router.navigate(['/process-groups', processGroupId, 'edit']); }) @@ -674,12 +672,36 @@ export class FlowEffects { { dispatch: false } ); + navigateToManageComponentPolicies$ = createEffect( + () => + this.actions$.pipe( + ofType(FlowActions.navigateToManageComponentPolicies), + map((action) => action.request), + tap((request) => { + this.router.navigate(['/access-policies', 'read', 'component', request.resource, request.id]); + }) + ), + { dispatch: false } + ); + + navigateToQueueListing$ = createEffect( + () => + this.actions$.pipe( + ofType(FlowActions.navigateToQueueListing), + map((action) => action.request), + tap((request) => { + this.router.navigate(['/queue', request.connectionId]); + }) + ), + { dispatch: false } + ); + navigateToViewStatusHistoryForComponent$ = createEffect( () => this.actions$.pipe( ofType(FlowActions.navigateToViewStatusHistoryForComponent), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([request, currentProcessGroupId]) => { this.router.navigate([ '/process-groups', @@ -815,10 +837,10 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.openEditProcessorDialog), map((action) => action.request), - withLatestFrom( + concatLatestFrom(() => [ this.store.select(selectCurrentParameterContext), this.store.select(selectCurrentProcessGroupId) - ), + ]), tap(([request, parameterContext, processGroupId]) => { const processorId: string = request.entity.id; @@ -1033,17 +1055,6 @@ export class FlowEffects { .pipe( take(1), switchMap((createReponse) => { - // dispatch an inline create service success action so the new service is in the state - this.store.dispatch( - ControllerServicesActions.inlineCreateControllerServiceSuccess( - { - response: { - controllerService: createReponse - } - } - ) - ); - // fetch an updated property descriptor return this.flowService .getPropertyDescriptor(processorId, descriptor.name, false) @@ -1178,7 +1189,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.openEditProcessGroupDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, currentProcessGroupId]) => this.flowService.getParameterContexts().pipe( take(1), @@ -1604,7 +1615,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.moveComponents), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), mergeMap(([request, processGroupId]) => { const components: any[] = request.components; @@ -1678,7 +1689,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.deleteComponents), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), mergeMap(([requests, processGroupId]) => { if (requests.length === 1) { return from(this.flowService.deleteComponent(requests[0])).pipe( @@ -1816,7 +1827,7 @@ export class FlowEffects { () => this.actions$.pipe( ofType(FlowActions.leaveProcessGroup), - withLatestFrom(this.store.select(selectParentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectParentProcessGroupId)), filter(([action, parentProcessGroupId]) => parentProcessGroupId != null), tap(([action, parentProcessGroupId]) => { this.router.navigate(['/process-groups', parentProcessGroupId]); @@ -1829,10 +1840,10 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.addSelectedComponents), map((action) => action.request), - withLatestFrom( + concatLatestFrom(() => [ this.store.select(selectCurrentProcessGroupId), this.store.select(selectAnySelectedComponentIds) - ), + ]), switchMap(([request, processGroupId, selected]) => { let commands: string[] = []; if (selected.length === 0) { @@ -1861,10 +1872,10 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.removeSelectedComponents), map((action) => action.request), - withLatestFrom( + concatLatestFrom(() => [ this.store.select(selectCurrentProcessGroupId), this.store.select(selectAnySelectedComponentIds) - ), + ]), switchMap(([request, processGroupId, selected]) => { let commands: string[]; if (selected.length === 0) { @@ -1883,7 +1894,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.selectComponents), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([request, processGroupId]) => { let commands: string[] = []; if (request.components.length === 1) { @@ -1905,7 +1916,7 @@ export class FlowEffects { deselectAllComponent$ = createEffect(() => this.actions$.pipe( ofType(FlowActions.deselectAllComponents), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), switchMap(([action, processGroupId]) => { return of(FlowActions.navigateWithoutTransform({ url: ['/process-groups', processGroupId] })); }) @@ -1917,7 +1928,7 @@ export class FlowEffects { this.actions$.pipe( ofType(FlowActions.navigateToComponent), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([request, currentProcessGroupId]) => { if (request.processGroupId) { this.router.navigate(['/process-groups', request.processGroupId, request.type, request.id]); @@ -2056,4 +2067,276 @@ export class FlowEffects { ), { dispatch: false } ); + + startCurrentProcessGroup$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.startCurrentProcessGroup), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + switchMap(([, pgId]) => { + return of( + FlowActions.startComponent({ + request: { + id: pgId, + type: ComponentType.ProcessGroup + } + }) + ); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ) + ); + + startComponents$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.startComponents), + map((action) => action.request), + mergeMap((request) => [ + ...request.components.map((component) => { + return FlowActions.startComponent({ + request: component + }); + }) + ]) + ) + ); + + startComponent$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.startComponent), + map((action) => action.request), + mergeMap((request) => { + switch (request.type) { + case ComponentType.InputPort: + case ComponentType.OutputPort: + case ComponentType.Processor: + case ComponentType.RemoteProcessGroup: + if ('uri' in request && 'revision' in request) { + return from(this.flowService.startComponent(request)).pipe( + map((response) => { + return FlowActions.startComponentSuccess({ + response: { + type: request.type, + component: response + } + }); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); + } + return of( + FlowActions.flowApiError({ + error: `Starting ${request.type} requires both uri and revision properties` + }) + ); + case ComponentType.ProcessGroup: + return combineLatest([ + this.flowService.startProcessGroup(request), + this.flowService.startRemoteProcessGroupsInProcessGroup(request) + ]).pipe( + map(([startPgResponse]) => { + return FlowActions.startComponentSuccess({ + response: { + type: request.type, + component: startPgResponse + } + }); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); + default: + return of(FlowActions.flowApiError({ error: `${request.type} does not support starting` })); + } + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ) + ); + + /** + * If the component started was the current process group, reload the flow + */ + startCurrentProcessGroupSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.startComponentSuccess), + map((action) => action.response), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + filter(([response, currentPg]) => response.component.id === currentPg), + switchMap(() => of(FlowActions.reloadFlow())) + ) + ); + + /** + * If a ProcessGroup was started, it should be reloaded as the response from the start operation doesn't contain all the displayed info + */ + startProcessGroupSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.startComponentSuccess), + map((action) => action.response), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + filter(([response]) => response.type === ComponentType.ProcessGroup), + filter(([response, currentPg]) => response.component.id !== currentPg), + switchMap(([response]) => + of( + FlowActions.loadChildProcessGroup({ + request: { + id: response.component.id + } + }) + ) + ) + ) + ); + + stopCurrentProcessGroup$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.stopCurrentProcessGroup), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + switchMap(([, pgId]) => { + return of( + FlowActions.stopComponent({ + request: { + id: pgId, + type: ComponentType.ProcessGroup + } + }) + ); + }) + ) + ); + + stopComponents$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.stopComponents), + map((action) => action.request), + mergeMap((request) => [ + ...request.components.map((component) => { + return FlowActions.stopComponent({ + request: component + }); + }) + ]) + ) + ); + + stopComponent$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.stopComponent), + map((action) => action.request), + mergeMap((request) => { + switch (request.type) { + case ComponentType.InputPort: + case ComponentType.OutputPort: + case ComponentType.Processor: + case ComponentType.RemoteProcessGroup: + if ('uri' in request && 'revision' in request) { + return from(this.flowService.stopComponent(request)).pipe( + map((response) => { + return FlowActions.stopComponentSuccess({ + response: { + type: request.type, + component: response + } + }); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); + } + return of( + FlowActions.flowApiError({ + error: `Stopping ${request.type} requires both uri and revision properties` + }) + ); + case ComponentType.ProcessGroup: + return combineLatest([ + this.flowService.stopProcessGroup(request), + this.flowService.stopRemoteProcessGroupsInProcessGroup(request) + ]).pipe( + map(([stopPgResponse]) => { + return FlowActions.stopComponentSuccess({ + response: { + type: request.type, + component: stopPgResponse + } + }); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); + default: + return of(FlowActions.flowApiError({ error: `${request.type} does not support stopping` })); + } + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ) + ); + + /** + * If the component stopped was the current process group, reload the flow + */ + stopCurrentProcessGroupSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.stopComponentSuccess), + map((action) => action.response), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + filter(([response, currentPg]) => response.component.id === currentPg), + switchMap(() => of(FlowActions.reloadFlow())) + ) + ); + + /** + * If a ProcessGroup was stopped, it should be reloaded as the response from the stop operation doesn't contain all the displayed info + */ + stopProcessGroupSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.stopComponentSuccess), + map((action) => action.response), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), + filter(([response]) => response.type === ComponentType.ProcessGroup), + filter(([response, currentPg]) => response.component.id !== currentPg), + switchMap(([response]) => + of( + FlowActions.loadChildProcessGroup({ + request: { + id: response.component.id + } + }) + ) + ) + ) + ); + + runOnce$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.runOnce), + map((action) => action.request), + switchMap((request) => { + return from(this.flowService.runOnce(request)).pipe( + map((response) => + FlowActions.runOnceSuccess({ + response: { + component: response + } + }) + ), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); + }), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ) + ); + + reloadProcessGroup$ = createEffect(() => + this.actions$.pipe( + ofType(FlowActions.loadChildProcessGroup), + map((action) => action.request), + mergeMap((request) => { + return from(this.flowService.getProcessGroup(request.id)).pipe( + map((response) => + FlowActions.loadChildProcessGroupSuccess({ + response: response.component + }) + ), + catchError((error) => of(FlowActions.flowApiError({ error: error.error }))) + ); + }) + ) + ); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.reducer.ts index 15cbbabb26b18..8a1af18d2700e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.reducer.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.reducer.ts @@ -37,12 +37,18 @@ import { loadProcessorSuccess, loadRemoteProcessGroupSuccess, navigateWithoutTransform, + loadChildProcessGroupSuccess, resetFlowState, + runOnce, + runOnceSuccess, setDragging, setNavigationCollapsed, setOperationCollapsed, setSkipTransform, setTransitionRequired, + startComponent, + startComponentSuccess, + stopComponentSuccess, updateComponent, updateComponentFailure, updateComponentSuccess, @@ -225,33 +231,7 @@ export const flowReducer = createReducer( ), on(createComponentSuccess, groupComponentsSuccess, (state, { response }) => { return produce(state, (draftState) => { - let collection: any[] | null = null; - switch (response.type) { - case ComponentType.Processor: - collection = draftState.flow.processGroupFlow.flow.processors; - break; - case ComponentType.ProcessGroup: - collection = draftState.flow.processGroupFlow.flow.processGroups; - break; - case ComponentType.RemoteProcessGroup: - collection = draftState.flow.processGroupFlow.flow.remoteProcessGroups; - break; - case ComponentType.InputPort: - collection = draftState.flow.processGroupFlow.flow.inputPorts; - break; - case ComponentType.OutputPort: - collection = draftState.flow.processGroupFlow.flow.outputPorts; - break; - case ComponentType.Label: - collection = draftState.flow.processGroupFlow.flow.labels; - break; - case ComponentType.Funnel: - collection = draftState.flow.processGroupFlow.flow.funnels; - break; - case ComponentType.Connection: - collection = draftState.flow.processGroupFlow.flow.connections; - break; - } + const collection: any[] | null = getComponentCollection(draftState, response.type); if (collection) { collection.push(response.payload); @@ -263,39 +243,13 @@ export const flowReducer = createReducer( dragging: false, saving: false })), - on(updateComponent, updateProcessor, updateConnection, (state) => ({ + on(updateComponent, updateProcessor, updateConnection, startComponent, runOnce, (state) => ({ ...state, saving: true })), on(updateComponentSuccess, updateProcessorSuccess, updateConnectionSuccess, (state, { response }) => { return produce(state, (draftState) => { - let collection: any[] | null = null; - switch (response.type) { - case ComponentType.Processor: - collection = draftState.flow.processGroupFlow.flow.processors; - break; - case ComponentType.ProcessGroup: - collection = draftState.flow.processGroupFlow.flow.processGroups; - break; - case ComponentType.RemoteProcessGroup: - collection = draftState.flow.processGroupFlow.flow.remoteProcessGroups; - break; - case ComponentType.InputPort: - collection = draftState.flow.processGroupFlow.flow.inputPorts; - break; - case ComponentType.OutputPort: - collection = draftState.flow.processGroupFlow.flow.outputPorts; - break; - case ComponentType.Label: - collection = draftState.flow.processGroupFlow.flow.labels; - break; - case ComponentType.Funnel: - collection = draftState.flow.processGroupFlow.flow.funnels; - break; - case ComponentType.Connection: - collection = draftState.flow.processGroupFlow.flow.connections; - break; - } + const collection: any[] | null = getComponentCollection(draftState, response.type); if (collection) { const componentIndex: number = collection.findIndex((f: any) => response.id === f.id); @@ -310,33 +264,7 @@ export const flowReducer = createReducer( on(updateComponentFailure, (state, { response }) => { return produce(state, (draftState) => { if (response.restoreOnFailure) { - let collection: any[] | null = null; - switch (response.type) { - case ComponentType.Processor: - collection = draftState.flow.processGroupFlow.flow.processors; - break; - case ComponentType.ProcessGroup: - collection = draftState.flow.processGroupFlow.flow.processGroups; - break; - case ComponentType.RemoteProcessGroup: - collection = draftState.flow.processGroupFlow.flow.remoteProcessGroups; - break; - case ComponentType.InputPort: - collection = draftState.flow.processGroupFlow.flow.inputPorts; - break; - case ComponentType.OutputPort: - collection = draftState.flow.processGroupFlow.flow.outputPorts; - break; - case ComponentType.Label: - collection = draftState.flow.processGroupFlow.flow.labels; - break; - case ComponentType.Funnel: - collection = draftState.flow.processGroupFlow.flow.funnels; - break; - case ComponentType.Connection: - collection = draftState.flow.processGroupFlow.flow.connections; - break; - } + const collection: any[] | null = getComponentCollection(draftState, response.type); if (collection) { const componentIndex: number = collection.findIndex((f: any) => response.id === f.id); @@ -356,33 +284,7 @@ export const flowReducer = createReducer( on(deleteComponentsSuccess, (state, { response }) => { return produce(state, (draftState) => { response.forEach((deleteResponse) => { - let collection: any[] | null = null; - switch (deleteResponse.type) { - case ComponentType.Processor: - collection = draftState.flow.processGroupFlow.flow.processors; - break; - case ComponentType.ProcessGroup: - collection = draftState.flow.processGroupFlow.flow.processGroups; - break; - case ComponentType.RemoteProcessGroup: - collection = draftState.flow.processGroupFlow.flow.remoteProcessGroups; - break; - case ComponentType.InputPort: - collection = draftState.flow.processGroupFlow.flow.inputPorts; - break; - case ComponentType.OutputPort: - collection = draftState.flow.processGroupFlow.flow.outputPorts; - break; - case ComponentType.Label: - collection = draftState.flow.processGroupFlow.flow.labels; - break; - case ComponentType.Funnel: - collection = draftState.flow.processGroupFlow.flow.funnels; - break; - case ComponentType.Connection: - collection = draftState.flow.processGroupFlow.flow.connections; - break; - } + const collection: any[] | null = getComponentCollection(draftState, deleteResponse.type); if (collection) { const componentIndex: number = collection.findIndex((f: any) => deleteResponse.id === f.id); @@ -416,5 +318,88 @@ export const flowReducer = createReducer( on(setOperationCollapsed, (state, { operationCollapsed }) => ({ ...state, operationCollapsed: operationCollapsed - })) + })), + on(startComponentSuccess, stopComponentSuccess, (state, { response }) => { + return produce(state, (draftState) => { + const collection: any[] | null = getComponentCollection(draftState, response.type); + + if (collection) { + const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id); + if (componentIndex > -1) { + collection[componentIndex] = { + ...collection[componentIndex], + ...response.component + }; + } + } + + draftState.saving = false; + }); + }), + on(runOnceSuccess, (state, { response }) => { + return produce(state, (draftState) => { + const collection: any[] | null = getComponentCollection(draftState, ComponentType.Processor); + + if (collection) { + const componentIndex: number = collection.findIndex((f: any) => response.component.id === f.id); + if (componentIndex > -1) { + collection[componentIndex] = { + ...collection[componentIndex], + ...response.component + }; + } + } + + draftState.saving = false; + }); + }), + + on(loadChildProcessGroupSuccess, (state, { response }) => { + return produce(state, (draftState) => { + const collection: any[] | null = getComponentCollection(draftState, ComponentType.ProcessGroup); + + if (collection) { + const componentIndex: number = collection.findIndex((f: any) => response.id === f.id); + if (componentIndex > -1) { + collection[componentIndex] = { + ...collection[componentIndex], + ...response.component + }; + } + } + + draftState.saving = false; + }); + }) ); + +function getComponentCollection(draftState: FlowState, componentType: ComponentType): any[] | null { + let collection: any[] | null = null; + switch (componentType) { + case ComponentType.Processor: + collection = draftState.flow.processGroupFlow.flow.processors; + break; + case ComponentType.ProcessGroup: + collection = draftState.flow.processGroupFlow.flow.processGroups; + break; + case ComponentType.RemoteProcessGroup: + collection = draftState.flow.processGroupFlow.flow.remoteProcessGroups; + break; + case ComponentType.InputPort: + collection = draftState.flow.processGroupFlow.flow.inputPorts; + break; + case ComponentType.OutputPort: + collection = draftState.flow.processGroupFlow.flow.outputPorts; + break; + case ComponentType.Label: + collection = draftState.flow.processGroupFlow.flow.labels; + break; + case ComponentType.Funnel: + collection = draftState.flow.processGroupFlow.flow.funnels; + break; + case ComponentType.Connection: + collection = draftState.flow.processGroupFlow.flow.connections; + break; + } + return collection; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts index 9b1bb3106d459..8ea5f224ee3e9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts @@ -23,6 +23,7 @@ import { DocumentedType, ParameterContextReferenceEntity, Permissions, + Revision, SelectOption } from '../../../../state/shared'; import { ParameterContextEntity } from '../../../parameter-contexts/state/parameter-context-listing'; @@ -214,6 +215,11 @@ export interface OpenComponentDialogRequest { type: ComponentType; } +export interface NavigateToManageComponentPoliciesRequest { + resource: string; + id: string; +} + export interface EditComponentDialogRequest { type: ComponentType; uri: string; @@ -224,6 +230,10 @@ export interface NavigateToControllerServicesRequest { id: string; } +export interface NavigateToQueueListing { + connectionId: string; +} + export interface EditCurrentProcessGroupRequest { id: string; } @@ -469,3 +479,74 @@ export interface FlowState { error: string | null; status: 'pending' | 'loading' | 'error' | 'success'; } + +export interface RunOnceRequest { + uri: string; + revision: Revision; +} + +export interface RunOnceResponse { + component: ComponentEntity; +} + +export interface StartProcessGroupRequest { + id: string; + type: ComponentType; +} + +export interface StartComponentRequest { + id: string; + uri: string; + type: ComponentType; + revision: Revision; +} + +export interface StartComponentsRequest { + components: StartComponentRequest[]; +} + +export interface StartComponentResponse { + type: ComponentType; + component: ComponentEntity; +} + +export interface StartComponentsResponse { + components: StartComponentsResponse[]; +} + +export interface ComponentRunStatusRequest { + revision: Revision; + state: string; + disconnectedNodeAcknowledged: boolean; +} + +export interface ProcessGroupRunStatusRequest { + id: string; + state: string; + disconnectedNodeAcknowledged: boolean; +} + +export interface StopComponentRequest { + id: string; + uri: string; + type: ComponentType; + revision: Revision; +} + +export interface StopProcessGroupRequest { + id: string; + type: ComponentType; +} + +export interface StopComponentResponse { + type: ComponentType; + component: ComponentEntity; +} + +export interface StopComponentsRequest { + components: StopComponentRequest[]; +} + +export interface LoadChildProcessGroupRequest { + id: string; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts index c84ab5c13139b..077b7c92da53a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts @@ -28,6 +28,9 @@ import { controllerServicesFeatureKey, ControllerServicesState } from './control import { controllerServicesReducer } from './controller-services/controller-services.reducer'; import { parameterFeatureKey, ParameterState } from './parameter'; import { parameterReducer } from './parameter/parameter.reducer'; +import { queueFeatureKey } from '../../queue/state'; +import { QueueState } from './queue'; +import { queueReducer } from './queue/queue.reducer'; export const canvasFeatureKey = 'canvas'; @@ -36,6 +39,7 @@ export interface CanvasState { [transformFeatureKey]: CanvasTransform; [controllerServicesFeatureKey]: ControllerServicesState; [parameterFeatureKey]: ParameterState; + [queueFeatureKey]: QueueState; } export function reducers(state: CanvasState | undefined, action: Action) { @@ -43,7 +47,8 @@ export function reducers(state: CanvasState | undefined, action: Action) { [flowFeatureKey]: flowReducer, [transformFeatureKey]: transformReducer, [controllerServicesFeatureKey]: controllerServicesReducer, - [parameterFeatureKey]: parameterReducer + [parameterFeatureKey]: parameterReducer, + [queueFeatureKey]: queueReducer })(state, action); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts index 0c94a38f6664f..a9900be81f850 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts @@ -16,23 +16,11 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as ParameterActions from './parameter.actions'; import { Store } from '@ngrx/store'; import { CanvasState } from '../index'; -import { - asyncScheduler, - catchError, - from, - interval, - map, - NEVER, - of, - switchMap, - takeUntil, - tap, - withLatestFrom -} from 'rxjs'; +import { asyncScheduler, catchError, from, interval, map, NEVER, of, switchMap, takeUntil, tap } from 'rxjs'; import { ParameterContextUpdateRequest } from '../../../../state/shared'; import { selectUpdateRequest } from './parameter.selectors'; import { ParameterService } from '../../service/parameter.service'; @@ -100,7 +88,7 @@ export class ParameterEffects { pollParameterContextUpdateRequest$ = createEffect(() => this.actions$.pipe( ofType(ParameterActions.pollParameterContextUpdateRequest), - withLatestFrom(this.store.select(selectUpdateRequest)), + concatLatestFrom(() => this.store.select(selectUpdateRequest)), switchMap(([action, updateRequest]) => { if (updateRequest) { return from(this.parameterService.pollParameterContextUpdate(updateRequest.request)).pipe( @@ -151,7 +139,7 @@ export class ParameterEffects { deleteParameterContextUpdateRequest$ = createEffect(() => this.actions$.pipe( ofType(ParameterActions.deleteParameterContextUpdateRequest), - withLatestFrom(this.store.select(selectUpdateRequest)), + concatLatestFrom(() => this.store.select(selectUpdateRequest)), tap(([action, updateRequest]) => { if (updateRequest) { this.parameterService.deleteParameterContextUpdate(updateRequest.request).subscribe(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/index.ts new file mode 100644 index 0000000000000..6177c01031d51 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/index.ts @@ -0,0 +1,65 @@ +/* + * 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. + */ + +export interface DropRequest { + id: string; + uri: string; + submissionTime: string; + lastUpdated: string; + percentCompleted: number; + finished: boolean; + failureReason: string; + currentCount: number; + currentSize: number; + current: string; + originalCount: number; + originalSize: number; + original: string; + droppedCount: number; + droppedSize: number; + dropped: string; + state: string; +} + +export interface DropRequestEntity { + dropRequest: DropRequest; +} + +export interface SubmitEmptyQueueRequest { + connectionId: string; +} + +export interface SubmitEmptyQueuesRequest { + processGroupId: string; +} + +export interface PollEmptyQueueSuccess { + dropEntity: DropRequestEntity; +} + +export interface ShowEmptyQueueResults { + dropEntity: DropRequestEntity; +} + +export interface QueueState { + dropEntity: DropRequestEntity | null; + connectionId: string | null; + processGroupId: string | null; + loadedTimestamp: string; + error: string | null; + status: 'pending' | 'loading' | 'error' | 'success'; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.actions.ts new file mode 100644 index 0000000000000..1b01526dd5c17 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.actions.ts @@ -0,0 +1,73 @@ +/* + * 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. + */ + +import { createAction, props } from '@ngrx/store'; +import { + PollEmptyQueueSuccess, + ShowEmptyQueueResults, + SubmitEmptyQueueRequest, + SubmitEmptyQueuesRequest +} from './index'; + +const QUEUE_PREFIX = '[Queue]'; + +export const queueApiError = createAction(`${QUEUE_PREFIX} Queue Error`, props<{ error: string }>()); + +export const resetQueueState = createAction(`${QUEUE_PREFIX} Reset Queue State`); + +export const promptEmptyQueueRequest = createAction( + `${QUEUE_PREFIX} Prompt Empty Queue Request`, + props<{ request: SubmitEmptyQueueRequest }>() +); + +export const submitEmptyQueueRequest = createAction( + `${QUEUE_PREFIX} Submit Empty Queue Request`, + props<{ request: SubmitEmptyQueueRequest }>() +); + +export const promptEmptyQueuesRequest = createAction( + `${QUEUE_PREFIX} Prompt Empty Queues Request`, + props<{ request: SubmitEmptyQueuesRequest }>() +); + +export const submitEmptyQueuesRequest = createAction( + `${QUEUE_PREFIX} Submit Empty Queues Request`, + props<{ request: SubmitEmptyQueuesRequest }>() +); + +export const submitEmptyQueueRequestSuccess = createAction( + `${QUEUE_PREFIX} Submit Empty Queue Request Success`, + props<{ response: PollEmptyQueueSuccess }>() +); + +export const startPollingEmptyQueueRequest = createAction(`${QUEUE_PREFIX} Start Polling Empty Queue Request`); + +export const pollEmptyQueueRequest = createAction(`${QUEUE_PREFIX} Poll Empty Queue Request`); + +export const pollEmptyQueueRequestSuccess = createAction( + `${QUEUE_PREFIX} Poll Empty Queue Request Success`, + props<{ response: PollEmptyQueueSuccess }>() +); + +export const stopPollingEmptyQueueRequest = createAction(`${QUEUE_PREFIX} Stop Polling Empty Queue Request`); + +export const deleteEmptyQueueRequest = createAction(`${QUEUE_PREFIX} Delete Empty Queue Request`); + +export const showEmptyQueueResults = createAction( + `${QUEUE_PREFIX} Show Empty Queue Results`, + props<{ request: ShowEmptyQueueResults }>() +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.effects.ts new file mode 100644 index 0000000000000..4ee573022c27e --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.effects.ts @@ -0,0 +1,341 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; +import * as QueueActions from './queue.actions'; +import { Store } from '@ngrx/store'; +import { asyncScheduler, catchError, filter, from, interval, map, of, switchMap, take, takeUntil, tap } from 'rxjs'; +import { selectDropConnectionId, selectDropProcessGroupId, selectDropRequestEntity } from './queue.selectors'; +import { QueueService } from '../../service/queue.service'; +import { DropRequest } from './index'; +import { CancelDialog } from '../../../../ui/common/cancel-dialog/cancel-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { NiFiCommon } from '../../../../service/nifi-common.service'; +import { isDefinedAndNotNull } from '../../../../state/shared'; +import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; +import { OkDialog } from '../../../../ui/common/ok-dialog/ok-dialog.component'; +import { loadConnection, loadProcessGroup } from '../flow/flow.actions'; +import { resetQueueState } from './queue.actions'; + +@Injectable() +export class QueueEffects { + constructor( + private actions$: Actions, + private store: Store, + private queueService: QueueService, + private dialog: MatDialog, + private nifiCommon: NiFiCommon + ) {} + + promptEmptyQueueRequest$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueActions.promptEmptyQueueRequest), + map((action) => action.request), + tap((request) => { + const dialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Empty Queue', + message: + 'Are you sure you want to empty this queue? All FlowFiles waiting at the time of the request will be removed.' + }, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + this.store.dispatch( + QueueActions.submitEmptyQueueRequest({ + request + }) + ); + }); + }) + ), + { dispatch: false } + ); + + submitEmptyQueueRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.submitEmptyQueueRequest), + map((action) => action.request), + switchMap((request) => { + const dialogReference = this.dialog.open(CancelDialog, { + data: { + title: 'Empty Queue', + message: 'Waiting for queue to empty...' + }, + disableClose: true, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.cancel.pipe(take(1)).subscribe(() => { + this.store.dispatch(QueueActions.stopPollingEmptyQueueRequest()); + }); + + return from(this.queueService.submitEmptyQueueRequest(request)).pipe( + map((response) => + QueueActions.submitEmptyQueueRequestSuccess({ + response: { + dropEntity: response + } + }) + ), + catchError((error) => + of( + QueueActions.queueApiError({ + error: error.error + }) + ) + ) + ); + }) + ) + ); + + promptEmptyQueuesRequest$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueActions.promptEmptyQueuesRequest), + map((action) => action.request), + tap((request) => { + const dialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Empty All Queues', + message: + 'Are you sure you want to empty all queues in this Process Group? All FlowFiles from all connections waiting at the time of the request will be removed.' + }, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + this.store.dispatch( + QueueActions.submitEmptyQueuesRequest({ + request + }) + ); + }); + }) + ), + { dispatch: false } + ); + + submitEmptyQueuesRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.submitEmptyQueuesRequest), + map((action) => action.request), + switchMap((request) => { + const dialogReference = this.dialog.open(CancelDialog, { + data: { + title: 'Empty All Queues', + message: 'Waiting for all queues to empty...' + }, + disableClose: true, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.cancel.pipe(take(1)).subscribe(() => { + this.store.dispatch(QueueActions.stopPollingEmptyQueueRequest()); + }); + + return from(this.queueService.submitEmptyQueuesRequest(request)).pipe( + map((response) => + QueueActions.submitEmptyQueueRequestSuccess({ + response: { + dropEntity: response + } + }) + ), + catchError((error) => + of( + QueueActions.queueApiError({ + error: error.error + }) + ) + ) + ); + }) + ) + ); + + submitEmptyQueueRequestSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.submitEmptyQueueRequestSuccess), + map((action) => action.response), + switchMap((response) => { + const dropRequest: DropRequest = response.dropEntity.dropRequest; + if (dropRequest.finished) { + return of(QueueActions.deleteEmptyQueueRequest()); + } else { + return of(QueueActions.startPollingEmptyQueueRequest()); + } + }) + ) + ); + + startPollingEmptyQueueRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.startPollingEmptyQueueRequest), + switchMap(() => + interval(2000, asyncScheduler).pipe( + takeUntil(this.actions$.pipe(ofType(QueueActions.stopPollingEmptyQueueRequest))) + ) + ), + switchMap(() => of(QueueActions.pollEmptyQueueRequest())) + ) + ); + + pollEmptyQueueRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.pollEmptyQueueRequest), + concatLatestFrom(() => this.store.select(selectDropRequestEntity).pipe(isDefinedAndNotNull())), + switchMap(([action, dropEntity]) => { + return from(this.queueService.pollEmptyQueueRequest(dropEntity.dropRequest)).pipe( + map((response) => + QueueActions.pollEmptyQueueRequestSuccess({ + response: { + dropEntity: response + } + }) + ), + catchError((error) => + of( + QueueActions.queueApiError({ + error: error.error + }) + ) + ) + ); + }) + ) + ); + + pollEmptyQueueRequestSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.pollEmptyQueueRequestSuccess), + map((action) => action.response), + filter((response) => response.dropEntity.dropRequest.finished), + switchMap((response) => of(QueueActions.stopPollingEmptyQueueRequest())) + ) + ); + + stopPollingEmptyQueueRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.stopPollingEmptyQueueRequest), + switchMap((response) => of(QueueActions.deleteEmptyQueueRequest())) + ) + ); + + deleteEmptyQueueRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueActions.deleteEmptyQueueRequest), + concatLatestFrom(() => this.store.select(selectDropRequestEntity).pipe(isDefinedAndNotNull())), + switchMap(([action, dropEntity]) => { + this.dialog.closeAll(); + + return from(this.queueService.deleteEmptyQueueRequest(dropEntity.dropRequest)).pipe( + map((response) => + QueueActions.showEmptyQueueResults({ + request: { + dropEntity: response + } + }) + ), + catchError((error) => + of( + QueueActions.showEmptyQueueResults({ + request: { + dropEntity + } + }) + ) + ) + ); + }) + ) + ); + + showEmptyQueueResults$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueActions.showEmptyQueueResults), + map((action) => action.request), + concatLatestFrom(() => [ + this.store.select(selectDropConnectionId), + this.store.select(selectDropProcessGroupId) + ]), + tap(([request, connectionId, processGroupId]) => { + const dropRequest: DropRequest = request.dropEntity.dropRequest; + const droppedTokens: string[] = dropRequest.dropped.split(/ \/ /); + + let message: string = `${droppedTokens[0]} FlowFiles (${droppedTokens[1]})`; + + if (dropRequest.percentCompleted < 100) { + const originalTokens: string[] = dropRequest.original.split(/ \/ /); + message = `${message} out of ${originalTokens[0]} (${originalTokens[1]})`; + } + + if (connectionId) { + message = `${message} were removed from the queue.`; + + this.store.dispatch( + loadConnection({ + id: connectionId + }) + ); + } else if (processGroupId) { + message = `${message} were removed from the queues.`; + + this.store.dispatch( + loadProcessGroup({ + request: { + id: processGroupId, + transitionRequired: false + } + }) + ); + } + + if (dropRequest.failureReason) { + message = `${message} ${dropRequest.failureReason}`; + } + + const dialogReference = this.dialog.open(OkDialog, { + data: { + title: 'Empty Queue', + message + }, + panelClass: 'small-dialog' + }); + + dialogReference.afterClosed().subscribe(() => { + this.store.dispatch(resetQueueState()); + }); + }) + ), + { dispatch: false } + ); + + queueApiError$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueActions.queueApiError), + tap((action) => this.dialog.closeAll()) + ), + { dispatch: false } + ); +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.reducer.ts new file mode 100644 index 0000000000000..7a2fb7c9c4297 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.reducer.ts @@ -0,0 +1,65 @@ +/* + * 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. + */ + +import { createReducer, on } from '@ngrx/store'; +import { QueueState } from './index'; +import { + pollEmptyQueueRequestSuccess, + submitEmptyQueueRequest, + submitEmptyQueueRequestSuccess, + resetQueueState, + queueApiError, + submitEmptyQueuesRequest +} from './queue.actions'; + +export const initialState: QueueState = { + dropEntity: null, + processGroupId: null, + connectionId: null, + loadedTimestamp: 'N/A', + error: null, + status: 'pending' +}; + +export const queueReducer = createReducer( + initialState, + on(submitEmptyQueueRequest, (state, { request }) => ({ + ...state, + connectionId: request.connectionId, + status: 'loading' as const + })), + on(submitEmptyQueuesRequest, (state, { request }) => ({ + ...state, + processGroupId: request.processGroupId, + status: 'loading' as const + })), + on(submitEmptyQueueRequestSuccess, pollEmptyQueueRequestSuccess, (state, { response }) => ({ + ...state, + dropEntity: response.dropEntity, + loadedTimestamp: response.dropEntity.dropRequest.lastUpdated, + error: null, + status: 'success' as const + })), + on(queueApiError, (state, { error }) => ({ + ...state, + error, + status: 'error' as const + })), + on(resetQueueState, (state) => ({ + ...initialState + })) +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.selectors.ts new file mode 100644 index 0000000000000..5c648eade9152 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/queue/queue.selectors.ts @@ -0,0 +1,29 @@ +/* + * 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. + */ + +import { createSelector } from '@ngrx/store'; +import { queueFeatureKey } from '../../../queue/state'; +import { QueueState } from './index'; +import { CanvasState, selectCanvasState } from '../index'; + +export const selectQueueState = createSelector(selectCanvasState, (state: CanvasState) => state[queueFeatureKey]); + +export const selectDropRequestEntity = createSelector(selectQueueState, (state: QueueState) => state.dropEntity); + +export const selectDropConnectionId = createSelector(selectQueueState, (state: QueueState) => state.connectionId); + +export const selectDropProcessGroupId = createSelector(selectQueueState, (state: QueueState) => state.processGroupId); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/transform/transform.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/transform/transform.effects.ts index 030d6dfec8f5b..7b6b3024fd1d6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/transform/transform.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/transform/transform.effects.ts @@ -16,9 +16,9 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as TransformActions from './transform.actions'; -import { map, tap, withLatestFrom } from 'rxjs'; +import { map, tap } from 'rxjs'; import { Storage } from '../../../../service/storage.service'; import { selectCurrentProcessGroupId } from '../flow/flow.selectors'; import { Store } from '@ngrx/store'; @@ -43,7 +43,7 @@ export class TransformEffects { this.actions$.pipe( ofType(TransformActions.transformComplete), map((action) => action.transform), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([transform, processGroupId]) => { const name: string = TransformEffects.VIEW_PREFIX + processGroupId; @@ -65,7 +65,7 @@ export class TransformEffects { () => this.actions$.pipe( ofType(TransformActions.restoreViewport), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), + concatLatestFrom(() => this.store.select(selectCurrentProcessGroupId)), tap(([action, processGroupId]) => { try { // see if we can restore the view position from storage diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/canvas.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/canvas.component.ts index 46402f5df607d..186f68ae6e68a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/canvas.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/canvas.component.ts @@ -56,13 +56,14 @@ import { selectSkipTransform, selectViewStatusHistoryComponent } from '../../state/flow/flow.selectors'; -import { filter, map, switchMap, take, withLatestFrom } from 'rxjs'; +import { filter, map, switchMap, take } from 'rxjs'; import { restoreViewport, zoomFit } from '../../state/transform/transform.actions'; -import { ComponentType } from '../../../../state/shared'; +import { ComponentType, isDefinedAndNotNull } from '../../../../state/shared'; import { initialState } from '../../state/flow/flow.reducer'; -import { ContextMenuDefinitionProvider } from '../../../../ui/common/context-menu/context-menu.component'; import { CanvasContextMenu } from '../../service/canvas-context-menu.service'; import { getStatusHistoryAndOpenDialog } from '../../../../state/status-history/status-history.actions'; +import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions'; +import { concatLatestFrom } from '@ngrx/effects'; @Component({ selector: 'fd-canvas', @@ -114,7 +115,7 @@ export class Canvas implements OnInit, OnDestroy { filter((processGroupId) => processGroupId != initialState.id), switchMap(() => this.store.select(selectProcessGroupRoute)), filter((processGroupRoute) => processGroupRoute != null), - withLatestFrom(this.store.select(selectSkipTransform)), + concatLatestFrom(() => this.store.select(selectSkipTransform)), takeUntilDestroyed() ) .subscribe(([status, skipTransform]) => { @@ -132,7 +133,7 @@ export class Canvas implements OnInit, OnDestroy { filter((processGroupId) => processGroupId != initialState.id), switchMap(() => this.store.select(selectSingleSelectedComponent)), filter((selectedComponent) => selectedComponent != null), - withLatestFrom(this.store.select(selectSkipTransform)), + concatLatestFrom(() => this.store.select(selectSkipTransform)), takeUntilDestroyed() ) .subscribe(([selectedComponent, skipTransform]) => { @@ -150,7 +151,7 @@ export class Canvas implements OnInit, OnDestroy { filter((processGroupId) => processGroupId != initialState.id), switchMap(() => this.store.select(selectBulkSelectedComponentIds)), filter((ids) => ids.length > 0), - withLatestFrom(this.store.select(selectSkipTransform)), + concatLatestFrom(() => this.store.select(selectSkipTransform)), takeUntilDestroyed() ) .subscribe(([ids, skipTransform]) => { @@ -167,37 +168,33 @@ export class Canvas implements OnInit, OnDestroy { .pipe( filter((processGroupId) => processGroupId != initialState.id), switchMap(() => this.store.select(selectSingleEditedComponent)), - // ensure there is a selected component - filter((selectedComponent) => selectedComponent != null), + isDefinedAndNotNull(), switchMap((selectedComponent) => { - // @ts-ignore - const component: SelectedComponent = selectedComponent; - let component$; - switch (component.componentType) { + switch (selectedComponent.componentType) { case ComponentType.Processor: - component$ = this.store.select(selectProcessor(component.id)); + component$ = this.store.select(selectProcessor(selectedComponent.id)); break; case ComponentType.InputPort: - component$ = this.store.select(selectInputPort(component.id)); + component$ = this.store.select(selectInputPort(selectedComponent.id)); break; case ComponentType.OutputPort: - component$ = this.store.select(selectOutputPort(component.id)); + component$ = this.store.select(selectOutputPort(selectedComponent.id)); break; case ComponentType.ProcessGroup: - component$ = this.store.select(selectProcessGroup(component.id)); + component$ = this.store.select(selectProcessGroup(selectedComponent.id)); break; case ComponentType.RemoteProcessGroup: - component$ = this.store.select(selectRemoteProcessGroup(component.id)); + component$ = this.store.select(selectRemoteProcessGroup(selectedComponent.id)); break; case ComponentType.Connection: - component$ = this.store.select(selectConnection(component.id)); + component$ = this.store.select(selectConnection(selectedComponent.id)); break; case ComponentType.Funnel: - component$ = this.store.select(selectFunnel(component.id)); + component$ = this.store.select(selectFunnel(selectedComponent.id)); break; case ComponentType.Label: - component$ = this.store.select(selectLabel(component.id)); + component$ = this.store.select(selectLabel(selectedComponent.id)); break; default: throw 'Unrecognized Component Type'; @@ -270,6 +267,7 @@ export class Canvas implements OnInit, OnDestroy { this.createSvg(); this.canvasView.init(this.viewContainerRef, this.svg, this.canvas); + this.store.dispatch(loadFlowConfiguration()); this.store.dispatch(startProcessGroupPolling()); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/graph-controls.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/graph-controls.component.ts index f1c794ad59286..6247bcfb25648 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/graph-controls.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/graph-controls.component.ts @@ -26,6 +26,11 @@ import { import { NavigationControl } from './navigation-control/navigation-control.component'; import { OperationControl } from './operation-control/operation-control.component'; import { AsyncPipe } from '@angular/common'; +import { NiFiState } from '../../../../../state'; +import { + selectFlowConfiguration, + selectSupportsManagedAuthorizer +} from '../../../../../state/flow-configuration/flow-configuration.selectors'; @Component({ selector: 'graph-controls', @@ -38,6 +43,7 @@ export class GraphControls { navigationCollapsed$ = this.store.select(selectNavigationCollapsed); operationCollapsed$ = this.store.select(selectOperationCollapsed); breadcrumbEntity$ = this.store.select(selectBreadcrumbs); + supportsManagedAuthorizer$ = this.store.select(selectSupportsManagedAuthorizer); - constructor(private store: Store) {} + constructor(private store: Store) {} } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.html index 5967f49213c09..a32c93bae2f1f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.html @@ -53,6 +53,7 @@ - - - - - - - - - - - - - - - - - - - - -
    -
    - +
    + + + + + + + + + { let component: HeaderComponent; let fixture: ComponentFixture; + @Component({ + selector: 'navigation', + standalone: true, + template: '' + }) + class MockNavigation {} + + @Component({ + selector: 'flow-status', + standalone: true, + template: '' + }) + class MockFlowStatus {} + const clusterSummary: ClusterSummary = { clustered: false, connectedToCluster: false, @@ -74,17 +84,16 @@ describe('HeaderComponent', () => { imports: [ HeaderComponent, NewCanvasItem, - FlowStatus, - Search, HttpClientTestingModule, + MockFlowStatus, MatMenuModule, MatDividerModule, - RouterModule, RouterTestingModule, CdkOverlayOrigin, CdkConnectedOverlay, FormsModule, - ReactiveFormsModule + ReactiveFormsModule, + MockNavigation ], providers: [ provideMockStore({ @@ -101,10 +110,6 @@ describe('HeaderComponent', () => { { selector: selectControllerBulletins, value: [] - }, - { - selector: selectCurrentUser, - value: fromUser.initialState.user } ] }) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/header.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/header.component.ts index 839896fc2d9ee..5af040a7aa0fc 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/header.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/header.component.ts @@ -26,10 +26,6 @@ import { selectCurrentProcessGroupId, selectLastRefreshed } from '../../../state/flow/flow.selectors'; -import { selectCurrentUser } from '../../../../../state/current-user/current-user.selectors'; -import { CurrentUser } from '../../../../../state/current-user'; -import { AuthStorage } from '../../../../../service/auth-storage.service'; -import { AuthService } from '../../../../../service/auth.service'; import { LoadingService } from '../../../../../service/loading.service'; import { NewCanvasItem } from './new-canvas-item/new-canvas-item.component'; import { MatButtonModule } from '@angular/material/button'; @@ -38,8 +34,7 @@ import { AsyncPipe, NgIf, NgOptimizedImage } from '@angular/common'; import { MatDividerModule } from '@angular/material/divider'; import { RouterLink } from '@angular/router'; import { FlowStatus } from './flow-status/flow-status.component'; -import { getNodeStatusHistoryAndOpenDialog } from '../../../../../state/status-history/status-history.actions'; -import { getSystemDiagnosticsAndOpenDialog } from '../../../../../state/system-diagnostics/system-diagnostics.actions'; +import { Navigation } from '../../../../../ui/common/navigation/navigation.component'; @Component({ selector: 'fd-header', @@ -54,7 +49,8 @@ import { getSystemDiagnosticsAndOpenDialog } from '../../../../../state/system-d RouterLink, NgIf, FlowStatus, - NgOptimizedImage + NgOptimizedImage, + Navigation ], styleUrls: ['./header.component.scss'] }) @@ -65,45 +61,10 @@ export class HeaderComponent { lastRefreshed$ = this.store.select(selectLastRefreshed); clusterSummary$ = this.store.select(selectClusterSummary); controllerBulletins$ = this.store.select(selectControllerBulletins); - currentUser$ = this.store.select(selectCurrentUser); currentProcessGroupId$ = this.store.select(selectCurrentProcessGroupId); constructor( private store: Store, - private authStorage: AuthStorage, - private authService: AuthService, public loadingService: LoadingService ) {} - - allowLogin(user: CurrentUser): boolean { - return user.anonymous && location.protocol === 'https:'; - } - - hasToken(): boolean { - return this.authStorage.hasToken(); - } - - logout(): void { - this.authService.logout(); - } - - viewNodeStatusHistory(): void { - this.store.dispatch( - getNodeStatusHistoryAndOpenDialog({ - request: { - source: 'menu' - } - }) - ); - } - - viewSystemDiagnostics() { - this.store.dispatch( - getSystemDiagnosticsAndOpenDialog({ - request: { - nodewise: false - } - }) - ); - } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.ts index 40336aca09de5..77d841fc29b90 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/header/new-canvas-item/new-canvas-item.component.ts @@ -36,8 +36,7 @@ import { ComponentType } from '../../../../../../state/shared'; styleUrls: ['./new-canvas-item.component.scss'] }) export class NewCanvasItem implements OnInit { - // @ts-ignore - @Input() type: ComponentType; + @Input() type!: ComponentType; @Input() iconClass: string = ''; @Input() iconHoverClass: string = ''; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.html index 6be66ec836f9a..b950e7567cd77 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.html @@ -15,14 +15,12 @@ ~ limitations under the License. --> -
    -
    +
    +
    + +
    +

    Controller Services

    - -
    -
    @@ -43,6 +41,9 @@

    Controller Services

    [controllerServices]="serviceState.controllerServices" [formatScope]="formatScope(serviceState.breadcrumb)" [definedByCurrentGroup]="definedByCurrentGroup(serviceState.breadcrumb)" + [currentUser]="(currentUser$ | async)!" + [flowConfiguration]="(flowConfiguration$ | async)!" + [canModifyParent]="canModifyParent(serviceState.breadcrumb)" (selectControllerService)="selectControllerService($event)" (configureControllerService)="configureControllerService($event)" (enableControllerService)="enableControllerService($event)" diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.ts index 7149a4e9c2584..0f2b78db145a1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.component.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Component, OnDestroy } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; import { filter, switchMap, take, tap } from 'rxjs'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; @@ -41,19 +41,25 @@ import { import { initialState } from '../../state/controller-services/controller-services.reducer'; import { ControllerServiceEntity } from '../../../../state/shared'; import { BreadcrumbEntity } from '../../state/shared'; +import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import { NiFiState } from '../../../../state'; +import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions'; @Component({ selector: 'controller-services', templateUrl: './controller-services.component.html', styleUrls: ['./controller-services.component.scss'] }) -export class ControllerServices implements OnDestroy { +export class ControllerServices implements OnInit, OnDestroy { serviceState$ = this.store.select(selectControllerServicesState); selectedServiceId$ = this.store.select(selectControllerServiceIdFromRoute); + currentUser$ = this.store.select(selectCurrentUser); + flowConfiguration$ = this.store.select(selectFlowConfiguration); private currentProcessGroupId!: string; - constructor(private store: Store) { + constructor(private store: Store) { // load the controller services using the process group id from the route this.store .select(selectProcessGroupIdFromRoute) @@ -98,6 +104,10 @@ export class ControllerServices implements OnDestroy { }); } + ngOnInit(): void { + this.store.dispatch(loadFlowConfiguration()); + } + isInitialLoading(state: ControllerServicesState): boolean { // using the current timestamp to detect the initial load event return state.loadedTimestamp == initialState.loadedTimestamp; @@ -189,6 +199,28 @@ export class ControllerServices implements OnDestroy { ); } + canModifyParent(breadcrumb: BreadcrumbEntity): (entity: ControllerServiceEntity) => boolean { + const breadcrumbs: BreadcrumbEntity[] = []; + + let currentBreadcrumb: BreadcrumbEntity | undefined = breadcrumb; + while (currentBreadcrumb != null) { + breadcrumbs.push(currentBreadcrumb); + currentBreadcrumb = currentBreadcrumb.parentBreadcrumb; + } + + return (entity: ControllerServiceEntity): boolean => { + const entityBreadcrumb: BreadcrumbEntity | undefined = breadcrumbs.find( + (bc) => bc.id === entity.parentGroupId + ); + + if (entityBreadcrumb) { + return entityBreadcrumb.permissions.canWrite; + } + + return false; + }; + } + selectControllerService(entity: ControllerServiceEntity): void { // this service listing shows all services in the current group and any // ancestor group. in this context we don't want the user to navigate away diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.module.ts index a3ecb01bb3eba..1184d8d1d1357 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/controller-service/controller-services.module.ts @@ -22,6 +22,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { ControllerServiceTable } from '../../../../ui/common/controller-service/controller-service-table/controller-service-table.component'; import { ControllerServicesRoutingModule } from './controller-services-routing.module'; import { Breadcrumbs } from '../common/breadcrumbs/breadcrumbs.component'; +import { Navigation } from '../../../../ui/common/navigation/navigation.component'; @NgModule({ declarations: [ControllerServices], @@ -31,7 +32,8 @@ import { Breadcrumbs } from '../common/breadcrumbs/breadcrumbs.component'; NgxSkeletonLoaderModule, ControllerServicesRoutingModule, ControllerServiceTable, - Breadcrumbs + Breadcrumbs, + Navigation ] }) export class ControllerServicesModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.html index 21abf532d3fc7..63474c1a0bd70 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.html @@ -15,14 +15,12 @@ ~ limitations under the License. --> -
    -
    +
    +
    + +
    +

    Parameter Contexts

    - -
    -
    - +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.spec.ts index 967273619bd41..36122c14526c0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.component.spec.ts @@ -23,15 +23,23 @@ import { initialState } from '../state/parameter-context-listing/parameter-conte import { ParameterContextListing } from '../ui/parameter-context-listing/parameter-context-listing.component'; import { RouterModule } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; +import { Component } from '@angular/core'; describe('ParameterContexts', () => { let component: ParameterContexts; let fixture: ComponentFixture; + @Component({ + selector: 'navigation', + standalone: true, + template: '' + }) + class MockNavigation {} + beforeEach(() => { TestBed.configureTestingModule({ declarations: [ParameterContexts, ParameterContextListing], - imports: [RouterModule, RouterTestingModule], + imports: [RouterModule, RouterTestingModule, MockNavigation], providers: [ provideMockStore({ initialState diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.module.ts index f5216d10daafe..6d07b9dfbda3d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/feature/parameter-contexts.module.ts @@ -24,6 +24,7 @@ import { ParameterContextsRoutingModule } from './parameter-contexts-routing.mod import { parameterContextsFeatureKey, reducers } from '../state'; import { ParameterContextListingEffects } from '../state/parameter-context-listing/parameter-context-listing.effects'; import { ParameterContextListingModule } from '../ui/parameter-context-listing/parameter-context-listing.module'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; @NgModule({ declarations: [ParameterContexts], @@ -33,7 +34,8 @@ import { ParameterContextListingModule } from '../ui/parameter-context-listing/p ParameterContextsRoutingModule, StoreModule.forFeature(parameterContextsFeatureKey, reducers), EffectsModule.forFeature(ParameterContextListingEffects), - ParameterContextListingModule + ParameterContextListingModule, + Navigation ] }) export class ParameterContextsModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts index 1c574d9aeb27d..51ad177f74299 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts @@ -16,7 +16,7 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as ParameterContextListingActions from './parameter-context-listing.actions'; import { asyncScheduler, @@ -30,8 +30,7 @@ import { switchMap, take, takeUntil, - tap, - withLatestFrom + tap } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -370,7 +369,7 @@ export class ParameterContextListingEffects { pollParameterContextUpdateRequest$ = createEffect(() => this.actions$.pipe( ofType(ParameterContextListingActions.pollParameterContextUpdateRequest), - withLatestFrom(this.store.select(selectUpdateRequest)), + concatLatestFrom(() => this.store.select(selectUpdateRequest)), switchMap(([action, updateRequest]) => { if (updateRequest) { return from(this.parameterContextService.pollParameterContextUpdate(updateRequest.request)).pipe( @@ -422,7 +421,7 @@ export class ParameterContextListingEffects { () => this.actions$.pipe( ofType(ParameterContextListingActions.deleteParameterContextUpdateRequest), - withLatestFrom(this.store.select(selectUpdateRequest)), + concatLatestFrom(() => this.store.select(selectUpdateRequest)), tap(([action, updateRequest]) => { if (updateRequest) { this.parameterContextService.deleteParameterContextUpdate(updateRequest.request).subscribe(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.html index b8933feb7500e..4b3b41f21cdc1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.html @@ -30,6 +30,8 @@ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.ts index 077e391aabe62..a6adf510e0d98 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.component.ts @@ -35,6 +35,9 @@ import { import { initialState } from '../../state/parameter-context-listing/parameter-context-listing.reducer'; import { filter, switchMap, take } from 'rxjs'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; +import { selectFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.selectors'; +import { loadFlowConfiguration } from '../../../../state/flow-configuration/flow-configuration.actions'; @Component({ selector: 'parameter-context-listing', @@ -44,6 +47,8 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; export class ParameterContextListing implements OnInit { parameterContextListingState$ = this.store.select(selectParameterContextListingState); selectedParameterContextId$ = this.store.select(selectParameterContextIdFromRoute); + currentUser$ = this.store.select(selectCurrentUser); + flowConfiguration$ = this.store.select(selectFlowConfiguration); constructor(private store: Store) { this.store @@ -72,6 +77,7 @@ export class ParameterContextListing implements OnInit { } ngOnInit(): void { + this.store.dispatch(loadFlowConfiguration()); this.store.dispatch(loadParameterContexts()); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.module.ts index a533c43c0e294..69787cc17ecc9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-listing.module.ts @@ -24,6 +24,7 @@ import { MatTableModule } from '@angular/material/table'; import { NifiTooltipDirective } from '../../../../ui/common/tooltips/nifi-tooltip.directive'; import { ParameterContextTable } from './parameter-context-table/parameter-context-table.component'; import { MatDialogModule } from '@angular/material/dialog'; +import { RouterLink } from '@angular/router'; @NgModule({ declarations: [ParameterContextListing, ParameterContextTable], @@ -34,7 +35,8 @@ import { MatDialogModule } from '@angular/material/dialog'; MatSortModule, MatTableModule, MatDialogModule, - NifiTooltipDirective + NifiTooltipDirective, + RouterLink ] }) export class ParameterContextListingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.html index 0af15cd41dd42..5b42331e6cdb3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.html @@ -17,7 +17,14 @@
    - +
    @@ -35,12 +42,7 @@ @@ -48,9 +50,7 @@ @@ -58,9 +58,7 @@ @@ -82,7 +80,8 @@
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.spec.ts index 818b51303af2c..1a610a7493129 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.spec.ts @@ -19,6 +19,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ParameterContextTable } from './parameter-context-table.component'; import { MatTableModule } from '@angular/material/table'; +import { MatSortModule } from '@angular/material/sort'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; describe('ParameterContextTable', () => { let component: ParameterContextTable; @@ -27,7 +29,7 @@ describe('ParameterContextTable', () => { beforeEach(() => { TestBed.configureTestingModule({ declarations: [ParameterContextTable], - imports: [MatTableModule] + imports: [MatTableModule, MatSortModule, NoopAnimationsModule] }); fixture = TestBed.createComponent(ParameterContextTable); component = fixture.componentInstance; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.ts index ea0f8deac403b..6925f25f9b251 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/parameter-context-table/parameter-context-table.component.ts @@ -15,35 +15,33 @@ * limitations under the License. */ -import { AfterViewInit, Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { MatTableDataSource } from '@angular/material/table'; -import { MatSort } from '@angular/material/sort'; +import { Sort } from '@angular/material/sort'; import { NiFiCommon } from '../../../../../service/nifi-common.service'; import { ParameterContextEntity } from '../../../state/parameter-context-listing'; +import { FlowConfiguration } from '../../../../../state/flow-configuration'; +import { CurrentUser } from '../../../../../state/current-user'; @Component({ selector: 'parameter-context-table', templateUrl: './parameter-context-table.component.html', styleUrls: ['./parameter-context-table.component.scss', '../../../../../../assets/styles/listing-table.scss'] }) -export class ParameterContextTable implements AfterViewInit { +export class ParameterContextTable { + @Input() initialSortColumn: 'name' | 'provider' | 'description' = 'name'; + @Input() initialSortDirection: 'asc' | 'desc' = 'asc'; + @Input() set parameterContexts(parameterContextEntities: ParameterContextEntity[]) { - this.dataSource = new MatTableDataSource(parameterContextEntities); - this.dataSource.sort = this.sort; - this.dataSource.sortingDataAccessor = (data: ParameterContextEntity, displayColumn: string) => { - if (this.canRead(data)) { - if (displayColumn === 'name') { - return this.formatName(data); - } else if (displayColumn === 'type') { - return this.formatProvider(data); - } else if (displayColumn === 'bundle') { - return this.formatDescription(data); - } - } - return ''; - }; + this.dataSource.data = this.sortEntities(parameterContextEntities, { + active: this.initialSortColumn, + direction: this.initialSortDirection + }); } + @Input() selectedParameterContextId!: string; + @Input() flowConfiguration!: FlowConfiguration; + @Input() currentUser!: CurrentUser; @Output() selectParameterContext: EventEmitter = new EventEmitter(); @Output() editParameterContext: EventEmitter = new EventEmitter(); @@ -52,14 +50,8 @@ export class ParameterContextTable implements AfterViewInit { displayedColumns: string[] = ['moreDetails', 'name', 'provider', 'description', 'actions']; dataSource: MatTableDataSource = new MatTableDataSource(); - @ViewChild(MatSort) sort!: MatSort; - constructor(private nifiCommon: NiFiCommon) {} - ngAfterViewInit(): void { - this.dataSource.sort = this.sort; - } - canRead(entity: ParameterContextEntity): boolean { return entity.permissions.canRead; } @@ -69,7 +61,7 @@ export class ParameterContextTable implements AfterViewInit { } formatName(entity: ParameterContextEntity): string { - return entity.component.name; + return this.canRead(entity) ? entity.component.name : entity.id; } formatProvider(entity: ParameterContextEntity): string { @@ -77,7 +69,7 @@ export class ParameterContextTable implements AfterViewInit { } formatDescription(entity: ParameterContextEntity): string { - return entity.component.description; + return this.canRead(entity) ? entity.component.description : ''; } editClicked(entity: ParameterContextEntity, event: MouseEvent): void { @@ -86,8 +78,10 @@ export class ParameterContextTable implements AfterViewInit { } canDelete(entity: ParameterContextEntity): boolean { - // TODO canModifyParameterContexts - return this.canRead(entity) && this.canWrite(entity); + const canModifyParameterContexts: boolean = + this.currentUser.parameterContextPermissions.canRead && + this.currentUser.parameterContextPermissions.canWrite; + return canModifyParameterContexts && this.canRead(entity) && this.canWrite(entity); } deleteClicked(entity: ParameterContextEntity, event: MouseEvent): void { @@ -96,12 +90,11 @@ export class ParameterContextTable implements AfterViewInit { } canManageAccessPolicies(): boolean { - // TODO nfCanvasUtils.isManagedAuthorizer() && nfCommon.canAccessTenants() - return false; + return this.flowConfiguration.supportsManagedAuthorizer && this.currentUser.tenantsPermissions.canRead; } - managePoliciesClicked(entity: ParameterContextEntity, event: MouseEvent): void { - event.stopPropagation(); + getPolicyLink(entity: ParameterContextEntity): string[] { + return ['/access-policies', 'read', 'component', 'parameter-contexts', entity.id]; } select(entity: ParameterContextEntity): void { @@ -114,4 +107,33 @@ export class ParameterContextTable implements AfterViewInit { } return false; } + + sortData(sort: Sort) { + this.dataSource.data = this.sortEntities(this.dataSource.data, sort); + } + + private sortEntities(data: ParameterContextEntity[], sort: Sort): ParameterContextEntity[] { + if (!data) { + return []; + } + return data.slice().sort((a, b) => { + const isAsc = sort.direction === 'asc'; + let retVal = 0; + + switch (sort.active) { + case 'name': + retVal = this.nifiCommon.compareString(this.formatName(a), this.formatName(b)); + break; + case 'provider': + retVal = this.nifiCommon.compareString(this.formatProvider(a), this.formatProvider(b)); + break; + case 'description': + retVal = this.nifiCommon.compareString(this.formatDescription(a), this.formatDescription(b)); + break; + default: + return 0; + } + return retVal * (isAsc ? 1 : -1); + }); + } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.html index f14af50f77724..718af5c6b59b3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.html @@ -15,14 +15,12 @@ ~ limitations under the License. --> -
    -
    -

    Provenance

    - -
    -
    +
    +
    + +
    +

    Provenance

    +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.spec.ts index 200affe6d8a85..ab5bc363f0bb5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.component.spec.ts @@ -22,15 +22,25 @@ import { provideMockStore } from '@ngrx/store/testing'; import { RouterModule } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { initialState } from '../state/provenance-event-listing/provenance-event-listing.reducer'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { Component } from '@angular/core'; describe('Provenance', () => { let component: Provenance; let fixture: ComponentFixture; + @Component({ + selector: 'navigation', + standalone: true, + template: '' + }) + class MockNavigation {} + beforeEach(() => { TestBed.configureTestingModule({ declarations: [Provenance], - imports: [RouterModule, RouterTestingModule], + imports: [RouterModule, RouterTestingModule, MockNavigation], providers: [ provideMockStore({ initialState diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.module.ts index 6943a4db9fe2c..c6b7c5ac761e3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/feature/provenance.module.ts @@ -25,6 +25,7 @@ import { provenanceFeatureKey, reducers } from '../state'; import { ProvenanceEventListingEffects } from '../state/provenance-event-listing/provenance-event-listing.effects'; import { MatDialogModule } from '@angular/material/dialog'; import { LineageEffects } from '../state/lineage/lineage.effects'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; @NgModule({ declarations: [Provenance], @@ -34,7 +35,8 @@ import { LineageEffects } from '../state/lineage/lineage.effects'; MatDialogModule, ProvenanceRoutingModule, StoreModule.forFeature(provenanceFeatureKey, reducers), - EffectsModule.forFeature(ProvenanceEventListingEffects, LineageEffects) + EffectsModule.forFeature(ProvenanceEventListingEffects, LineageEffects), + Navigation ] }) export class ProvenanceModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/index.ts index 2fd8eb3b5380e..b88bb12ee4ef0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/index.ts @@ -16,7 +16,7 @@ */ /* - Parameter Contexts + Provenance */ import { Action, combineReducers, createFeatureSelector } from '@ngrx/store'; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/lineage/lineage.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/lineage/lineage.effects.ts index ba013cd3a0872..9d68f1d3b7e89 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/lineage/lineage.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/lineage/lineage.effects.ts @@ -16,23 +16,10 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as LineageActions from './lineage.actions'; import * as ProvenanceActions from '../provenance-event-listing/provenance-event-listing.actions'; -import { - asyncScheduler, - catchError, - from, - interval, - map, - NEVER, - of, - switchMap, - take, - takeUntil, - tap, - withLatestFrom -} from 'rxjs'; +import { asyncScheduler, catchError, from, interval, map, NEVER, of, switchMap, takeUntil, tap } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { NiFiState } from '../../../../state'; @@ -113,7 +100,7 @@ export class LineageEffects { pollLineageQuery$ = createEffect(() => this.actions$.pipe( ofType(LineageActions.pollLineageQuery), - withLatestFrom(this.store.select(selectLineageId), this.store.select(selectClusterNodeId)), + concatLatestFrom(() => [this.store.select(selectLineageId), this.store.select(selectClusterNodeId)]), switchMap(([action, id, clusterNodeId]) => { if (id) { return from(this.provenanceService.getLineageQuery(id, clusterNodeId)).pipe( @@ -166,7 +153,7 @@ export class LineageEffects { () => this.actions$.pipe( ofType(LineageActions.deleteLineageQuery), - withLatestFrom(this.store.select(selectLineageId), this.store.select(selectClusterNodeId)), + concatLatestFrom(() => [this.store.select(selectLineageId), this.store.select(selectClusterNodeId)]), tap(([action, id, clusterNodeId]) => { if (id) { this.provenanceService.deleteLineageQuery(id, clusterNodeId).subscribe(); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/provenance-event-listing/provenance-event-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/provenance-event-listing/provenance-event-listing.effects.ts index 10e21b90f48b6..4c2b4b5013c50 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/provenance-event-listing/provenance-event-listing.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/provenance/state/provenance-event-listing/provenance-event-listing.effects.ts @@ -16,22 +16,9 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import * as ProvenanceEventListingActions from './provenance-event-listing.actions'; -import { - asyncScheduler, - catchError, - from, - interval, - map, - NEVER, - of, - switchMap, - take, - takeUntil, - tap, - withLatestFrom -} from 'rxjs'; +import { asyncScheduler, catchError, from, interval, map, NEVER, of, switchMap, take, takeUntil, tap } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { NiFiState } from '../../../../state'; @@ -169,7 +156,7 @@ export class ProvenanceEventListingEffects { pollProvenanceQuery$ = createEffect(() => this.actions$.pipe( ofType(ProvenanceEventListingActions.pollProvenanceQuery), - withLatestFrom(this.store.select(selectProvenanceId), this.store.select(selectClusterNodeId)), + concatLatestFrom(() => [this.store.select(selectProvenanceId), this.store.select(selectClusterNodeId)]), switchMap(([action, id, clusterNodeId]) => { if (id) { return from(this.provenanceService.getProvenanceQuery(id, clusterNodeId)).pipe( @@ -222,7 +209,7 @@ export class ProvenanceEventListingEffects { () => this.actions$.pipe( ofType(ProvenanceEventListingActions.deleteProvenanceQuery), - withLatestFrom(this.store.select(selectProvenanceId), this.store.select(selectClusterNodeId)), + concatLatestFrom(() => [this.store.select(selectProvenanceId), this.store.select(selectClusterNodeId)]), tap(([action, id, clusterNodeId]) => { if (id) { this.provenanceService.deleteProvenanceQuery(id, clusterNodeId).subscribe(); @@ -236,12 +223,12 @@ export class ProvenanceEventListingEffects { () => this.actions$.pipe( ofType(ProvenanceEventListingActions.openSearchDialog), - withLatestFrom( + concatLatestFrom(() => [ this.store.select(selectTimeOffset), this.store.select(selectProvenanceOptions), this.store.select(selectProvenanceRequest), this.store.select(selectAbout) - ), + ]), tap(([request, timeOffset, options, currentRequest, about]) => { if (about) { const dialogReference = this.dialog.open(ProvenanceSearchDialog, { @@ -288,7 +275,7 @@ export class ProvenanceEventListingEffects { this.actions$.pipe( ofType(ProvenanceEventListingActions.openProvenanceEventDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectAbout)), + concatLatestFrom(() => this.store.select(selectAbout)), tap(([request, about]) => { this.provenanceService.getProvenanceEvent(request.id).subscribe({ next: (response) => { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue-routing.module.ts new file mode 100644 index 0000000000000..9063539da331b --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue-routing.module.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { Queue } from './queue.component'; +import { QueueListingRoutingModule } from '../ui/queue-listing/queue-listing-routing.module'; + +const routes: Routes = [ + { + path: '', + component: Queue, + children: [ + { + path: '', + loadChildren: () => import('../ui/queue-listing/queue-listing.module').then((m) => m.QueueListingModule) + } + ] + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class QueueRoutingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.html new file mode 100644 index 0000000000000..ee813dae395f3 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.html @@ -0,0 +1,25 @@ + + +
    +
    + +
    +
    + +
    +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.scss new file mode 100644 index 0000000000000..2944f98194743 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.scss @@ -0,0 +1,16 @@ +/* + * 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. + */ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.spec.ts new file mode 100644 index 0000000000000..9a2cb5ce7acd0 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.spec.ts @@ -0,0 +1,56 @@ +/* + * 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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Queue } from './queue.component'; +import { provideMockStore } from '@ngrx/store/testing'; +import { RouterModule } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; +import { initialState } from '../state/queue-listing/queue-listing.reducer'; +import { Component } from '@angular/core'; + +describe('Queue', () => { + let component: Queue; + let fixture: ComponentFixture; + + @Component({ + selector: 'navigation', + standalone: true, + template: '' + }) + class MockNavigation {} + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [Queue], + imports: [RouterModule, RouterTestingModule, MockNavigation], + providers: [ + provideMockStore({ + initialState + }) + ] + }); + fixture = TestBed.createComponent(Queue); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapProperties.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.ts similarity index 52% rename from minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapProperties.java rename to nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.ts index 6484706689754..1c00fd0415a4d 100644 --- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/service/BootstrapProperties.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.component.ts @@ -14,31 +14,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.nifi.minifi.bootstrap.service; -import static org.apache.nifi.minifi.commons.utils.PropertyUtil.resolvePropertyValue; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { NiFiState } from '../../../state'; +import { startCurrentUserPolling, stopCurrentUserPolling } from '../../../state/current-user/current-user.actions'; +import { loadAbout } from '../../../state/about/about.actions'; -import java.util.Properties; +@Component({ + selector: 'queue', + templateUrl: './queue.component.html', + styleUrls: ['./queue.component.scss'] +}) +export class Queue implements OnInit, OnDestroy { + constructor(private store: Store) {} -/** - * Extends Properties functionality with System and Environment property override possibility. The property resolution also works with - * dots and hyphens that are not supported in some shells. - */ -public class BootstrapProperties extends Properties { - - private BootstrapProperties() { - super(); + ngOnInit(): void { + this.store.dispatch(startCurrentUserPolling()); + this.store.dispatch(loadAbout()); } - public static BootstrapProperties getInstance() { - return new BootstrapProperties(); + ngOnDestroy(): void { + this.store.dispatch(stopCurrentUserPolling()); } - - @Override - public String getProperty(String key) { - return resolvePropertyValue(key, System.getProperties()) - .or(() -> resolvePropertyValue(key, System.getenv())) - .orElseGet(() -> super.getProperty(key)); - } - } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.module.ts new file mode 100644 index 0000000000000..b8d398036aa64 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/feature/queue.module.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Queue } from './queue.component'; +import { QueueRoutingModule } from './queue-routing.module'; +import { MatDialogModule } from '@angular/material/dialog'; +import { Navigation } from '../../../ui/common/navigation/navigation.component'; + +@NgModule({ + declarations: [Queue], + exports: [Queue], + imports: [CommonModule, MatDialogModule, QueueRoutingModule, Navigation] +}) +export class QueueModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/service/queue.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/service/queue.service.ts new file mode 100644 index 0000000000000..afdd3e763a7f7 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/service/queue.service.ts @@ -0,0 +1,116 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { NiFiCommon } from '../../../service/nifi-common.service'; +import { FlowFileSummary, ListingRequest, SubmitQueueListingRequest } from '../state/queue-listing'; + +@Injectable({ providedIn: 'root' }) +export class QueueService { + private static readonly API: string = '../nifi-api'; + + constructor( + private httpClient: HttpClient, + private nifiCommon: NiFiCommon + ) {} + + /** + * The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling + * does not work on absolute URLs, so we need to strip off the proto for the request header to be added. + * + * https://stackoverflow.com/a/59586462 + * + * @param url + * @private + */ + private stripProtocol(url: string): string { + return this.nifiCommon.substringAfterFirst(url, ':'); + } + + getConnection(connectionId: string): Observable { + return this.httpClient.get(`${QueueService.API}/connections/${connectionId}`); + } + + getFlowFile(flowfileSummary: FlowFileSummary): Observable { + return this.httpClient.get(this.stripProtocol(flowfileSummary.uri)); + } + + submitQueueListingRequest(queueListingRequest: SubmitQueueListingRequest): Observable { + return this.httpClient.post( + `${QueueService.API}/flowfile-queues/${queueListingRequest.connectionId}/listing-requests`, + {} + ); + } + + pollQueueListingRequest(listingRequest: ListingRequest): Observable { + return this.httpClient.get(this.stripProtocol(listingRequest.uri)); + } + + deleteQueueListingRequest(listingRequest: ListingRequest): Observable { + return this.httpClient.delete(this.stripProtocol(listingRequest.uri)); + } + + downloadContent(flowfileSummary: FlowFileSummary): void { + let dataUri: string = `${this.stripProtocol(flowfileSummary.uri)}/content`; + + const queryParameters: any = {}; + + // TODO - flowFileSummary.clusterNodeId in query parameters + + if (Object.keys(queryParameters).length > 0) { + const query: string = new URLSearchParams(queryParameters).toString(); + dataUri = `${dataUri}?${query}`; + } + + window.open(dataUri); + } + + viewContent(flowfileSummary: FlowFileSummary, contentViewerUrl: string): void { + // build the uri to the data + let dataUri: string = `${this.stripProtocol(flowfileSummary.uri)}/content`; + + const dataUriParameters: any = {}; + + // TODO - flowFileSummary.clusterNodeId in query parameters + + // include parameters if necessary + if (Object.keys(dataUriParameters).length > 0) { + const dataUriQuery: string = new URLSearchParams(dataUriParameters).toString(); + dataUri = `${dataUri}?${dataUriQuery}`; + } + + // if there's already a query string don't add another ?... this assumes valid + // input meaning that if the url has already included a ? it also contains at + // least one query parameter + let contentViewer: string = contentViewerUrl; + if (contentViewer.indexOf('?') === -1) { + contentViewer += '?'; + } else { + contentViewer += '&'; + } + + const contentViewerParameters: any = { + ref: dataUri + }; + + // open the content viewer + const contentViewerQuery: string = new URLSearchParams(contentViewerParameters).toString(); + window.open(`${contentViewer}${contentViewerQuery}`); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/index.ts new file mode 100644 index 0000000000000..5809b3efe2efa --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/index.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ + +/* + Queue Listing + */ + +import { Action, combineReducers, createFeatureSelector } from '@ngrx/store'; +import { queueListingFeatureKey, QueueListingState } from './queue-listing'; +import { queueListingReducer } from './queue-listing/queue-listing.reducer'; + +export const queueFeatureKey = 'queue'; + +export interface QueueState { + [queueListingFeatureKey]: QueueListingState; +} + +export function reducers(state: QueueState | undefined, action: Action) { + return combineReducers({ + [queueListingFeatureKey]: queueListingReducer + })(state, action); +} + +export const selectQueueState = createFeatureSelector(queueFeatureKey); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts new file mode 100644 index 0000000000000..0ce0492f8110e --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts @@ -0,0 +1,109 @@ +/* + * 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. + */ + +export const queueListingFeatureKey = 'queueListing'; + +export interface FlowFile extends FlowFileSummary { + attributes: { + [key: string]: string; + }; + contentClaimContainer?: string; + contentClaimSection?: string; + contentClaimIdentifier?: string; + contentClaimOffset?: number; + contentClaimFileSize?: string; + contentClaimFileSizeBytes?: number; +} + +export interface FlowFileSummary { + uri: string; + uuid: string; + filename: string; + position?: number; + size: number; + queuedDuration: number; + lineageDuration: number; + penaltyExpiresIn: number; + penalized: boolean; + clusterNodeId?: string; + clusterNodeAddress?: string; +} + +export interface QueueSize { + byteCount: number; + objectCount: number; +} + +export interface ListingRequest { + id: string; + uri: string; + submissionTime: string; + lastUpdated: string; + percentCompleted: number; + finished: boolean; + failureReason: string; + maxResults: number; + sourceRunning: boolean; + destinationRunning: boolean; + state: string; + queueSize: QueueSize; + flowFileSummaries: FlowFileSummary[]; +} + +export interface ListingRequestEntity { + listingRequest: ListingRequest; +} + +export interface LoadConnectionLabelRequest { + connectionId: string; +} + +export interface LoadConnectionLabelResponse { + connectionLabel: string; +} + +export interface SubmitQueueListingRequest { + connectionId: string; +} + +export interface PollQueueListingSuccess { + requestEntity: ListingRequestEntity; +} + +export interface ViewFlowFileRequest { + flowfileSummary: FlowFileSummary; +} + +export interface DownloadFlowFileContentRequest { + flowfileSummary: FlowFileSummary; +} + +export interface ViewFlowFileContentRequest { + flowfileSummary: FlowFileSummary; +} + +export interface FlowFileDialogRequest { + flowfile: FlowFile; +} + +export interface QueueListingState { + requestEntity: ListingRequestEntity | null; + connectionLabel: string; + loadedTimestamp: string; + error: string | null; + status: 'pending' | 'loading' | 'error' | 'success'; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts new file mode 100644 index 0000000000000..52c4200dba55e --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts @@ -0,0 +1,86 @@ +/* + * 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. + */ + +import { createAction, props } from '@ngrx/store'; +import { + DownloadFlowFileContentRequest, + FlowFileDialogRequest, + LoadConnectionLabelRequest, + LoadConnectionLabelResponse, + PollQueueListingSuccess, + SubmitQueueListingRequest, + ViewFlowFileContentRequest, + ViewFlowFileRequest +} from './index'; + +const QUEUE_PREFIX = '[Queue Listing]'; + +export const loadConnectionLabel = createAction( + `${QUEUE_PREFIX} Load Connection Label`, + props<{ request: LoadConnectionLabelRequest }>() +); + +export const loadConnectionLabelSuccess = createAction( + `${QUEUE_PREFIX} Load Connection Label Success`, + props<{ response: LoadConnectionLabelResponse }>() +); + +export const queueListingApiError = createAction(`${QUEUE_PREFIX} Queue Error`, props<{ error: string }>()); + +export const resetQueueListingState = createAction(`${QUEUE_PREFIX} Reset Queue Listing State`); + +export const submitQueueListingRequest = createAction( + `${QUEUE_PREFIX} Submit Queue Listing Request`, + props<{ request: SubmitQueueListingRequest }>() +); + +export const resubmitQueueListingRequest = createAction(`${QUEUE_PREFIX} Resubmit Queue Listing Request`); + +export const submitQueueListingRequestSuccess = createAction( + `${QUEUE_PREFIX} Submit Queue Listing Request Success`, + props<{ response: PollQueueListingSuccess }>() +); + +export const startPollingQueueListingRequest = createAction(`${QUEUE_PREFIX} Start Polling Queue Listing Request`); + +export const pollQueueListingRequest = createAction(`${QUEUE_PREFIX} Poll Queue Listing Request`); + +export const pollQueueListingRequestSuccess = createAction( + `${QUEUE_PREFIX} Poll Queue Listing Request Success`, + props<{ response: PollQueueListingSuccess }>() +); + +export const stopPollingQueueListingRequest = createAction(`${QUEUE_PREFIX} Stop Polling Queue Listing Request`); + +export const deleteQueueListingRequest = createAction(`${QUEUE_PREFIX} Delete Queue Listing Request`); + +export const viewFlowFile = createAction(`${QUEUE_PREFIX} View FlowFile`, props<{ request: ViewFlowFileRequest }>()); + +export const openFlowFileDialog = createAction( + `${QUEUE_PREFIX} Open FlowFile Dialog`, + props<{ request: FlowFileDialogRequest }>() +); + +export const downloadFlowFileContent = createAction( + `${QUEUE_PREFIX} Download FlowFile Content`, + props<{ request: DownloadFlowFileContentRequest }>() +); + +export const viewFlowFileContent = createAction( + `${QUEUE_PREFIX} View FlowFile Content`, + props<{ request: ViewFlowFileContentRequest }>() +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts new file mode 100644 index 0000000000000..3b29d84e469ab --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts @@ -0,0 +1,309 @@ +/* + * 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. + */ + +import { Injectable } from '@angular/core'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; +import * as QueueListingActions from './queue-listing.actions'; +import { Store } from '@ngrx/store'; +import { CanvasState } from '../../../flow-designer/state'; +import { asyncScheduler, catchError, filter, from, interval, map, of, switchMap, take, takeUntil, tap } from 'rxjs'; +import { selectConnectionIdFromRoute, selectListingRequestEntity } from './queue-listing.selectors'; +import { QueueService } from '../../service/queue.service'; +import { ListingRequest } from './index'; +import { CancelDialog } from '../../../../ui/common/cancel-dialog/cancel-dialog.component'; +import { MatDialog } from '@angular/material/dialog'; +import { selectAbout } from '../../../../state/about/about.selectors'; +import { FlowFileDialog } from '../../ui/queue-listing/flowfile-dialog/flowfile-dialog.component'; +import { NiFiCommon } from '../../../../service/nifi-common.service'; +import { isDefinedAndNotNull } from '../../../../state/shared'; + +@Injectable() +export class QueueListingEffects { + constructor( + private actions$: Actions, + private store: Store, + private queueService: QueueService, + private dialog: MatDialog, + private nifiCommon: NiFiCommon + ) {} + + loadConnectionLabel$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.loadConnectionLabel), + map((action) => action.request), + switchMap((request) => + from(this.queueService.getConnection(request.connectionId)).pipe( + map((response) => { + const connection: any = response.component; + + let connectionLabel: string = 'Connection'; + if (!this.nifiCommon.isBlank(connection.name)) { + connectionLabel = connection.name; + } else if (connection.selectedRelationships) { + connectionLabel = connection.selectedRelationships.join(', '); + } + + return QueueListingActions.loadConnectionLabelSuccess({ + response: { + connectionLabel + } + }); + }), + catchError((error) => + of( + QueueListingActions.loadConnectionLabelSuccess({ + response: { + connectionLabel: 'Connection' + } + }) + ) + ) + ) + ) + ) + ); + + submitQueueListingRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.submitQueueListingRequest), + map((action) => action.request), + switchMap((request) => { + const dialogReference = this.dialog.open(CancelDialog, { + data: { + title: 'Queue Listing', + message: 'Waiting for queue listing to complete...' + }, + disableClose: true, + panelClass: 'small-dialog' + }); + + dialogReference.componentInstance.cancel.pipe(take(1)).subscribe(() => { + this.store.dispatch(QueueListingActions.stopPollingQueueListingRequest()); + }); + + return from(this.queueService.submitQueueListingRequest(request)).pipe( + map((response) => + QueueListingActions.submitQueueListingRequestSuccess({ + response: { + requestEntity: response + } + }) + ), + catchError((error) => + of( + QueueListingActions.queueListingApiError({ + error: error.error + }) + ) + ) + ); + }) + ) + ); + + resubmitQueueListingRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.resubmitQueueListingRequest), + concatLatestFrom(() => this.store.select(selectConnectionIdFromRoute)), + switchMap(([action, connectionId]) => + of(QueueListingActions.submitQueueListingRequest({ request: { connectionId } })) + ) + ) + ); + + submitQueueListingRequestSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.submitQueueListingRequestSuccess), + map((action) => action.response), + switchMap((response) => { + const listingRequest: ListingRequest = response.requestEntity.listingRequest; + if (listingRequest.finished) { + return of(QueueListingActions.deleteQueueListingRequest()); + } else { + return of(QueueListingActions.startPollingQueueListingRequest()); + } + }) + ) + ); + + startPollingQueueListingRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.startPollingQueueListingRequest), + switchMap(() => + interval(2000, asyncScheduler).pipe( + takeUntil(this.actions$.pipe(ofType(QueueListingActions.stopPollingQueueListingRequest))) + ) + ), + switchMap(() => of(QueueListingActions.pollQueueListingRequest())) + ) + ); + + pollQueueListingRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.pollQueueListingRequest), + concatLatestFrom(() => this.store.select(selectListingRequestEntity).pipe(isDefinedAndNotNull())), + switchMap(([action, requestEntity]) => { + return from(this.queueService.pollQueueListingRequest(requestEntity.listingRequest)).pipe( + map((response) => + QueueListingActions.pollQueueListingRequestSuccess({ + response: { + requestEntity: response + } + }) + ), + catchError((error) => + of( + QueueListingActions.queueListingApiError({ + error: error.error + }) + ) + ) + ); + }) + ) + ); + + pollQueueListingRequestSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.pollQueueListingRequestSuccess), + map((action) => action.response), + filter((response) => response.requestEntity.listingRequest.finished), + switchMap((response) => of(QueueListingActions.stopPollingQueueListingRequest())) + ) + ); + + stopPollingQueueListingRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.stopPollingQueueListingRequest), + switchMap((response) => of(QueueListingActions.deleteQueueListingRequest())) + ) + ); + + deleteQueueListingRequest$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueListingActions.deleteQueueListingRequest), + concatLatestFrom(() => this.store.select(selectListingRequestEntity)), + tap(([action, requestEntity]) => { + this.dialog.closeAll(); + + if (requestEntity) { + this.queueService.deleteQueueListingRequest(requestEntity.listingRequest).subscribe(); + } + }) + ), + { dispatch: false } + ); + + viewFlowFile$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.viewFlowFile), + map((action) => action.request), + switchMap((request) => + from(this.queueService.getFlowFile(request.flowfileSummary)).pipe( + map((response) => + QueueListingActions.openFlowFileDialog({ + request: { + flowfile: response.flowFile + } + }) + ), + catchError((error) => + of( + QueueListingActions.queueListingApiError({ + error: error.error + }) + ) + ) + ) + ) + ) + ); + + openFlowFileDialog$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueListingActions.openFlowFileDialog), + map((action) => action.request), + concatLatestFrom(() => this.store.select(selectAbout)), + filter((about) => about != null), + tap(([request, about]) => { + const dialogReference = this.dialog.open(FlowFileDialog, { + data: request, + panelClass: 'large-dialog' + }); + + dialogReference.componentInstance.contentViewerAvailable = about?.contentViewerUrl != null ?? false; + + dialogReference.componentInstance.downloadContent + .pipe(takeUntil(dialogReference.afterClosed())) + .subscribe(() => { + this.store.dispatch( + QueueListingActions.downloadFlowFileContent({ + request: { flowfileSummary: request.flowfile } + }) + ); + }); + + if (about) { + dialogReference.componentInstance.viewContent + .pipe(takeUntil(dialogReference.afterClosed())) + .subscribe(() => { + this.store.dispatch( + QueueListingActions.viewFlowFileContent({ + request: { flowfileSummary: request.flowfile } + }) + ); + }); + } + }) + ), + { dispatch: false } + ); + + downloadFlowFileContent$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueListingActions.downloadFlowFileContent), + map((action) => action.request), + tap((request) => this.queueService.downloadContent(request.flowfileSummary)) + ), + { dispatch: false } + ); + + viewFlowFileContent$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueListingActions.viewFlowFileContent), + map((action) => action.request), + concatLatestFrom(() => this.store.select(selectAbout).pipe(isDefinedAndNotNull())), + tap(([request, about]) => { + this.queueService.viewContent(request.flowfileSummary, about.contentViewerUrl); + }) + ), + { dispatch: false } + ); + + queueListingApiError$ = createEffect( + () => + this.actions$.pipe( + ofType(QueueListingActions.queueListingApiError), + tap(() => this.dialog.closeAll()) + ), + { dispatch: false } + ); +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts new file mode 100644 index 0000000000000..e45e94f6b7694 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ + +import { createReducer, on } from '@ngrx/store'; +import { QueueListingState } from './index'; +import { + pollQueueListingRequestSuccess, + submitQueueListingRequest, + submitQueueListingRequestSuccess, + resetQueueListingState, + queueListingApiError, + loadConnectionLabelSuccess +} from './queue-listing.actions'; + +export const initialState: QueueListingState = { + requestEntity: null, + connectionLabel: 'Connection', + loadedTimestamp: 'N/A', + error: null, + status: 'pending' +}; + +export const queueListingReducer = createReducer( + initialState, + on(loadConnectionLabelSuccess, (state, { response }) => ({ + ...state, + connectionLabel: response.connectionLabel + })), + on(submitQueueListingRequest, (state, { request }) => ({ + ...state, + status: 'loading' as const + })), + on(submitQueueListingRequestSuccess, pollQueueListingRequestSuccess, (state, { response }) => ({ + ...state, + requestEntity: response.requestEntity, + loadedTimestamp: response.requestEntity.listingRequest.lastUpdated, + error: null, + status: 'success' as const + })), + on(queueListingApiError, (state, { error }) => ({ + ...state, + error, + status: 'error' as const + })), + on(resetQueueListingState, (state) => ({ + ...initialState + })) +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts new file mode 100644 index 0000000000000..01f3e8af39073 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ + +import { createSelector } from '@ngrx/store'; +import { queueListingFeatureKey, QueueListingState } from './index'; +import { QueueState, selectQueueState } from '../index'; +import { selectCurrentRoute } from '../../../../state/router/router.selectors'; + +export const selectQueueListingState = createSelector( + selectQueueState, + (state: QueueState) => state[queueListingFeatureKey] +); + +export const selectListingRequestEntity = createSelector( + selectQueueListingState, + (state: QueueListingState) => state.requestEntity +); + +export const selectStatus = createSelector(selectQueueListingState, (state: QueueListingState) => state.status); + +export const selectError = createSelector(selectQueueListingState, (state: QueueListingState) => state.error); + +export const selectConnectionLabel = createSelector( + selectQueueListingState, + (state: QueueListingState) => state.connectionLabel +); + +export const selectLoadedTimestamp = createSelector( + selectQueueListingState, + (state: QueueListingState) => state.loadedTimestamp +); + +export const selectConnectionIdFromRoute = createSelector(selectCurrentRoute, (route) => { + if (route?.params.connectionId != null) { + return route.params.connectionId; + } + return null; +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.html new file mode 100644 index 0000000000000..2e17a72811652 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.html @@ -0,0 +1,229 @@ + + +

    FlowFile

    +
    + + + +
    +
    +
    +
    +
    FlowFile Details
    +
    +
    +
    UUID
    + +
    +
    +
    Filename
    + +
    +
    +
    File Size
    + +
    +
    +
    Queue Position
    + +
    +
    +
    Queued Duration
    + +
    +
    +
    Lineage Duration
    + +
    +
    +
    Penalized
    +
    {{ request.flowfile.penalized ? 'Yes' : 'No' }}
    +
    + +
    +
    Node Address
    + +
    +
    + + +
    {{ formatDurationValue(duration) }}
    +
    + +
    No value set
    +
    +
    +
    +
    +
    +
    Content Claim
    +
    +
    +
    +
    Container
    + +
    +
    +
    Section
    + +
    +
    +
    Identifier
    + +
    +
    +
    Offset
    + +
    +
    +
    Size
    + +
    +
    + + +
    +
    + +
    No Content Available
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    Attribute Values
    +
    +
    +
    +
    +
    {{ attribute.key }}
    + +
    +
    +
    +
    +
    +
    +
    + + + +
    Empty string set
    +
    + +
    {{ value }}
    + +
    {{ value }}
    +
    +
    +
    + +
    No value set
    +
    +
    + + +
    {{ value }}
    + +
    {{ value }}
    +
    +
    + +
    No value previously set
    +
    +
    +
    + + + +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.scss new file mode 100644 index 0000000000000..665cb9f0292bd --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.scss @@ -0,0 +1,41 @@ +/* + * 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. + */ + +@use '@angular/material' as mat; + +.flowfile { + @include mat.button-density(-1); + + .mdc-dialog__content { + padding: 0 16px; + font-size: 14px; + + .tab-content { + position: relative; + height: 475px; + overflow-y: auto; + + .flowfile-header { + color: #728e9b; + font-size: 15px; + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: bold; + } + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.spec.ts new file mode 100644 index 0000000000000..9e8a68be3b9d7 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.spec.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FlowFileDialog } from './flowfile-dialog.component'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { FlowFileDialogRequest } from '../../../state/queue-listing'; + +describe('FlowFileDialog', () => { + let component: FlowFileDialog; + let fixture: ComponentFixture; + + const data: FlowFileDialogRequest = { + flowfile: { + uri: 'https://localhost:4200/nifi-api/flowfile-queues/eea858d0-018c-1000-57fe-66ba110b3bcb/flowfiles/fc165889-3493-404c-9895-62d49a06801b', + uuid: 'fc165889-3493-404c-9895-62d49a06801b', + filename: '93a06a31-6b50-4d04-9b45-6a2a4a5e2dd1', + size: 0, + queuedDuration: 172947006, + lineageDuration: 172947006, + penaltyExpiresIn: 0, + attributes: { + path: './', + filename: '93a06a31-6b50-4d04-9b45-6a2a4a5e2dd1', + uuid: 'fc165889-3493-404c-9895-62d49a06801b' + }, + penalized: false + } + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [FlowFileDialog, BrowserAnimationsModule], + providers: [{ provide: MAT_DIALOG_DATA, useValue: data }] + }); + fixture = TestBed.createComponent(FlowFileDialog); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.ts new file mode 100644 index 0000000000000..23fdd7472f0ce --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-dialog/flowfile-dialog.component.ts @@ -0,0 +1,77 @@ +/* + * 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. + */ + +import { Component, EventEmitter, Inject, Input, Output } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatInputModule } from '@angular/material/input'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatButtonModule } from '@angular/material/button'; +import { AsyncPipe, KeyValuePipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common'; +import { MatDatepickerModule } from '@angular/material/datepicker'; +import { MatTabsModule } from '@angular/material/tabs'; +import { FlowFileDialogRequest } from '../../../state/queue-listing'; +import { NiFiCommon } from '../../../../../service/nifi-common.service'; + +@Component({ + selector: 'flowfile-dialog', + standalone: true, + templateUrl: './flowfile-dialog.component.html', + imports: [ + ReactiveFormsModule, + MatDialogModule, + MatInputModule, + MatCheckboxModule, + MatButtonModule, + NgIf, + AsyncPipe, + NgForOf, + MatDatepickerModule, + MatTabsModule, + NgTemplateOutlet, + FormsModule, + KeyValuePipe + ], + styleUrls: ['./flowfile-dialog.component.scss'] +}) +export class FlowFileDialog { + @Input() contentViewerAvailable!: boolean; + + @Output() downloadContent: EventEmitter = new EventEmitter(); + @Output() viewContent: EventEmitter = new EventEmitter(); + + constructor( + @Inject(MAT_DIALOG_DATA) public request: FlowFileDialogRequest, + private nifiCommon: NiFiCommon + ) {} + + formatDurationValue(duration: number): string { + if (duration === 0) { + return '< 1 sec'; + } + + return this.nifiCommon.formatDuration(duration); + } + + downloadContentClicked(): void { + this.downloadContent.next(); + } + + viewContentClicked(): void { + this.viewContent.next(); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html new file mode 100644 index 0000000000000..2b0f76c87022a --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html @@ -0,0 +1,147 @@ + + +
    +

    {{ connectionLabel }}

    +
    +
    + Display {{ displayObjectCount }} of {{ formatCount(queueSizeObjectCount) }} ({{ + formatBytes(queueSizeByteCount) + }}) bytes +
    +
    + + The source and destination of this queue are currently running. This listing may no longer be accurate. + + + + The source of this queue is currently running. This listing may no longer be accurate. + + + + + The destination of this queue is currently running. This listing may no longer be accurate. + + +
    +
    +
    +
    +
    Name - - {{ formatName(item) }} - - -
    {{ item.id }}
    -
    +
    {{ formatName(item) }}
    Provider - - {{ formatProvider(item) }} - + {{ formatProvider(item) }} Description - - {{ formatDescription(item) }} - + {{ formatDescription(item) }}
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    +
    Position + {{ item.position }} + UUID + {{ item.uuid }} + Filename + {{ item.filename }} + File Size + {{ formatBytes(item.size) }} + Queued Duration + {{ formatDuration(item.queuedDuration) }} + Lineage Duration + {{ formatDuration(item.lineageDuration) }} + Penalized + {{ item.penalized ? 'Yes' : 'No' }} + +
    +
    +
    +
    +
    +
    +
    +
    +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.scss new file mode 100644 index 0000000000000..158206f8a7a8f --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.scss @@ -0,0 +1,50 @@ +/* + * 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. + */ + +.flowfile-table { + .queue-listing-header { + color: #728e9b; + } + + .listing-message { + color: #ba554a; + } + + .listing-table { + table { + .mat-column-moreDetails { + min-width: 50px; + width: 50px; + } + + .mat-column-position { + min-width: 75px; + width: 75px; + } + + .mat-column-penalized { + min-width: 85px; + width: 85px; + } + + .mat-column-actions { + min-width: 100px; + width: 100px; + } + } + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts new file mode 100644 index 0000000000000..fd491f6d65d3e --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FlowFileTable } from './flowfile-table.component'; +import { MatTableModule } from '@angular/material/table'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +describe('FlowFileTable', () => { + let component: FlowFileTable; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [FlowFileTable, MatTableModule, BrowserAnimationsModule] + }); + fixture = TestBed.createComponent(FlowFileTable); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts new file mode 100644 index 0000000000000..2fdc7d5b76060 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts @@ -0,0 +1,140 @@ +/* + * 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. + */ + +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; +import { MatTableDataSource, MatTableModule } from '@angular/material/table'; +import { TextTip } from '../../../../../ui/common/tooltips/text-tip/text-tip.component'; +import { BulletinsTip } from '../../../../../ui/common/tooltips/bulletins-tip/bulletins-tip.component'; +import { ValidationErrorsTip } from '../../../../../ui/common/tooltips/validation-errors-tip/validation-errors-tip.component'; +import { NiFiCommon } from '../../../../../service/nifi-common.service'; +import { NgForOf, NgIf } from '@angular/common'; +import { RouterLink } from '@angular/router'; +import { FlowFileSummary, ListingRequest } from '../../../state/queue-listing'; +import { CurrentUser } from '../../../../../state/current-user'; + +@Component({ + selector: 'flowfile-table', + standalone: true, + templateUrl: './flowfile-table.component.html', + imports: [MatTableModule, NgForOf, NgIf, RouterLink], + styleUrls: ['./flowfile-table.component.scss', '../../../../../../assets/styles/listing-table.scss'] +}) +export class FlowFileTable implements AfterViewInit { + @Input() connectionLabel!: string; + @Input() set listingRequest(listingRequest: ListingRequest) { + if (listingRequest.flowFileSummaries) { + this.dataSource.data = this.sortFlowFiles(listingRequest.flowFileSummaries); + + this.displayObjectCount = this.dataSource.data.length; + this.queueSizeObjectCount = listingRequest.queueSize.objectCount; + this.queueSizeByteCount = listingRequest.queueSize.byteCount; + + this.sourceRunning = listingRequest.sourceRunning; + this.destinationRunning = listingRequest.destinationRunning; + } + } + @Input() currentUser!: CurrentUser; + @Input() contentViewerAvailable!: boolean; + + @Output() viewFlowFile: EventEmitter = new EventEmitter(); + @Output() downloadContent: EventEmitter = new EventEmitter(); + @Output() viewContent: EventEmitter = new EventEmitter(); + + protected readonly TextTip = TextTip; + protected readonly BulletinsTip = BulletinsTip; + protected readonly ValidationErrorsTip = ValidationErrorsTip; + + // TODO - conditionally include the cluster column + displayedColumns: string[] = [ + 'moreDetails', + 'position', + 'flowFileUuid', + 'fileName', + 'fileSize', + 'queuedDuration', + 'lineageDuration', + 'penalized', + 'actions' + ]; + dataSource: MatTableDataSource = new MatTableDataSource(); + selectedUuid: string | null = null; + + sourceRunning: boolean = false; + destinationRunning: boolean = false; + + displayObjectCount: number = 0; + queueSizeObjectCount: number = 0; + queueSizeByteCount: number = 0; + + constructor(private nifiCommon: NiFiCommon) {} + + ngAfterViewInit(): void {} + + sortFlowFiles(summaries: FlowFileSummary[]): FlowFileSummary[] { + const data: FlowFileSummary[] = summaries.slice(); + return data.sort((a: FlowFileSummary, b: FlowFileSummary) => { + const aIsUndefined: boolean = typeof a.position === 'undefined'; + const bIsUndefined: boolean = typeof b.position === 'undefined'; + + if (aIsUndefined && bIsUndefined) { + return 0; + } else if (aIsUndefined) { + return 1; + } else if (bIsUndefined) { + return -1; + } + + // @ts-ignore + return this.nifiCommon.compareNumber(a.position, b.position); + }); + } + + formatBytes(size: number): string { + return this.nifiCommon.formatDataSize(size); + } + + formatCount(count: number): string { + return this.nifiCommon.formatInteger(count); + } + + formatDuration(duration: number): string { + return this.nifiCommon.formatDuration(duration); + } + + select(summary: FlowFileSummary): void { + this.selectedUuid = summary.uuid; + } + + isSelected(summary: FlowFileSummary): boolean { + if (this.selectedUuid) { + return summary.uuid == this.selectedUuid; + } + return false; + } + + viewFlowFileClicked(summary: FlowFileSummary): void { + this.viewFlowFile.next(summary); + } + + downloadContentClicked(summary: FlowFileSummary): void { + this.downloadContent.next(summary); + } + + viewContentClicked(summary: FlowFileSummary): void { + this.viewContent.next(summary); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing-routing.module.ts new file mode 100644 index 0000000000000..a59d048f50eb6 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing-routing.module.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { QueueListing } from './queue-listing.component'; + +const routes: Routes = [ + { + path: ':connectionId', + component: QueueListing + } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class QueueListingRoutingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html new file mode 100644 index 0000000000000..c5824e47dcf99 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html @@ -0,0 +1,48 @@ + + +
    +
    +
    + {{ error$ | async }} +
    + + + + + + + + +
    +
    +
    + +
    Last updated:
    +
    {{ loadedTimestamp$ | async }}
    +
    +
    +
    diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.scss b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.scss new file mode 100644 index 0000000000000..2944f98194743 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.scss @@ -0,0 +1,16 @@ +/* + * 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. + */ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.spec.ts new file mode 100644 index 0000000000000..041ef817fe5f4 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.spec.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { QueueListing } from './queue-listing.component'; +import { provideMockStore } from '@ngrx/store/testing'; +import { initialState } from '../../state/queue-listing/queue-listing.reducer'; + +describe('QueueListing', () => { + let component: QueueListing; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + declarations: [QueueListing], + providers: [provideMockStore({ initialState })] + }); + fixture = TestBed.createComponent(QueueListing); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts new file mode 100644 index 0000000000000..2f48c84425b78 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts @@ -0,0 +1,108 @@ +/* + * 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. + */ + +import { Component, OnDestroy } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { distinctUntilChanged, filter } from 'rxjs'; +import { + selectConnectionIdFromRoute, + selectConnectionLabel, + selectError, + selectListingRequestEntity, + selectLoadedTimestamp, + selectStatus +} from '../../state/queue-listing/queue-listing.selectors'; +import { FlowFileSummary } from '../../state/queue-listing'; +import { + downloadFlowFileContent, + loadConnectionLabel, + resetQueueListingState, + resubmitQueueListingRequest, + submitQueueListingRequest, + viewFlowFile, + viewFlowFileContent +} from '../../state/queue-listing/queue-listing.actions'; +import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; +import { NiFiState } from '../../../../state'; +import { selectAbout } from '../../../../state/about/about.selectors'; +import { About } from '../../../../state/about'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; + +@Component({ + selector: 'queue-listing', + templateUrl: './queue-listing.component.html', + styleUrls: ['./queue-listing.component.scss'] +}) +export class QueueListing implements OnDestroy { + status$ = this.store.select(selectStatus); + error$ = this.store.select(selectError); + connectionLabel$ = this.store.select(selectConnectionLabel); + loadedTimestamp$ = this.store.select(selectLoadedTimestamp); + listingRequestEntity$ = this.store.select(selectListingRequestEntity); + currentUser$ = this.store.select(selectCurrentUser); + about$ = this.store.select(selectAbout); + + constructor(private store: Store) { + this.store + .select(selectConnectionIdFromRoute) + .pipe( + filter((connectionId) => connectionId != null), + distinctUntilChanged(), + takeUntilDestroyed() + ) + .subscribe((connectionId) => { + this.store.dispatch( + loadConnectionLabel({ + request: { + connectionId + } + }) + ); + this.store.dispatch( + submitQueueListingRequest({ + request: { + connectionId + } + }) + ); + }); + } + + refreshClicked(): void { + this.store.dispatch(resubmitQueueListingRequest()); + } + + contentViewerAvailable(about: About): boolean { + return about.contentViewerUrl != null; + } + + viewFlowFile(flowfileSummary: FlowFileSummary): void { + this.store.dispatch(viewFlowFile({ request: { flowfileSummary } })); + } + + downloadContent(flowfileSummary: FlowFileSummary): void { + this.store.dispatch(downloadFlowFileContent({ request: { flowfileSummary } })); + } + + viewContent(flowfileSummary: FlowFileSummary): void { + this.store.dispatch(viewFlowFileContent({ request: { flowfileSummary } })); + } + + ngOnDestroy(): void { + this.store.dispatch(resetQueueListingState()); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.module.ts new file mode 100644 index 0000000000000..a35f591f7f7ef --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.module.ts @@ -0,0 +1,43 @@ +/* + * 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. + */ + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { QueueListing } from './queue-listing.component'; +import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; +import { NifiTooltipDirective } from '../../../../ui/common/tooltips/nifi-tooltip.directive'; +import { QueueListingRoutingModule } from './queue-listing-routing.module'; +import { FlowFileTable } from './flowfile-table/flowfile-table.component'; +import { StoreModule } from '@ngrx/store'; +import { EffectsModule } from '@ngrx/effects'; +import { queueFeatureKey, reducers } from '../../state'; +import { QueueListingEffects } from '../../state/queue-listing/queue-listing.effects'; + +@NgModule({ + declarations: [QueueListing], + exports: [QueueListing], + imports: [ + CommonModule, + QueueListingRoutingModule, + NgxSkeletonLoaderModule, + NifiTooltipDirective, + FlowFileTable, + StoreModule.forFeature(queueFeatureKey, reducers), + EffectsModule.forFeature(QueueListingEffects) + ] +}) +export class QueueListingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts index 85a5965a8766d..441a5bd06cd91 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings-routing.module.ts @@ -67,7 +67,22 @@ const routes: Routes = [ } ] }, - { path: 'flow-analysis-rules', component: FlowAnalysisRules }, + { + path: 'flow-analysis-rules', + component: FlowAnalysisRules, + children: [ + { + path: ':id', + component: FlowAnalysisRules, + children: [ + { + path: 'edit', + component: FlowAnalysisRules + } + ] + } + ] + }, { path: 'registry-clients', component: RegistryClients, diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings.component.html index 7b9a734ec021a..c1a6c9cf57220 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/feature/settings.component.html @@ -15,14 +15,12 @@ ~ limitations under the License. --> -
    -
    +
    +
    + +
    +

    NiFi Settings

    - -
    -