This is an automated email from the ASF dual-hosted git repository.

rfellows pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 7fd406d9a87 NIFI-16024: Added endpoints for obtaining Status History 
of Processors, Connections, Process Groups, RPGs within a Connector; added 
corresponding methods to the ConnectorClient and added system tests to verify 
(#11348)
7fd406d9a87 is described below

commit 7fd406d9a87b6f18f0cc06e9c813e96e10b33047
Author: Mark Payne <[email protected]>
AuthorDate: Thu Jun 18 13:46:53 2026 -0400

    NIFI-16024: Added endpoints for obtaining Status History of Processors, 
Connections, Process Groups, RPGs within a Connector; added corresponding 
methods to the ConnectorClient and added system tests to verify (#11348)
---
 .../endpoints/StatusHistoryEndpointMerger.java     |  13 +-
 .../endpoints/TestStatusHistoryEndpointMerger.java |  23 ++
 .../org/apache/nifi/web/NiFiServiceFacade.java     |  40 ++++
 .../apache/nifi/web/StandardNiFiServiceFacade.java |  53 +++++
 .../org/apache/nifi/web/api/ConnectorResource.java | 189 +++++++++++++++++
 .../nifi/web/controller/ControllerFacade.java      |  48 +++++
 .../connectors/ConnectorStatusHistoryIT.java       | 232 +++++++++++++++++++++
 .../nifi/toolkit/client/ConnectorClient.java       |  45 ++++
 .../toolkit/client/impl/JerseyConnectorClient.java |  77 +++++++
 9 files changed, 716 insertions(+), 4 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/StatusHistoryEndpointMerger.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/StatusHistoryEndpointMerger.java
index f1befc3b5dc..729d662cbd1 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/StatusHistoryEndpointMerger.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/coordination/http/endpoints/StatusHistoryEndpointMerger.java
@@ -57,6 +57,11 @@ public class StatusHistoryEndpointMerger implements 
EndpointResponseMerger {
     public static final Pattern 
REMOTE_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN = 
Pattern.compile("/nifi-api/flow/remote-process-groups/[a-f0-9\\-]{36}/status/history");
     public static final Pattern CONNECTION_STATUS_HISTORY_URI_PATTERN = 
Pattern.compile("/nifi-api/flow/connections/[a-f0-9\\-]{36}/status/history");
     public static final Pattern NODE_STATUS_HISTORY_URI_PATTERN = 
Pattern.compile("/nifi-api/controller/status/history");
+    public static final Pattern CONNECTOR_PROCESSOR_STATUS_HISTORY_URI_PATTERN 
= 
Pattern.compile("/nifi-api/connectors/[a-f0-9\\-]{36}/processors/[a-f0-9\\-]{36}/status/history");
+    public static final Pattern 
CONNECTOR_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN = 
Pattern.compile("/nifi-api/connectors/[a-f0-9\\-]{36}/process-groups/[a-f0-9\\-]{36}/status/history");
+    public static final Pattern 
CONNECTOR_REMOTE_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN =
+            
Pattern.compile("/nifi-api/connectors/[a-f0-9\\-]{36}/remote-process-groups/[a-f0-9\\-]{36}/status/history");
+    public static final Pattern 
CONNECTOR_CONNECTION_STATUS_HISTORY_URI_PATTERN = 
Pattern.compile("/nifi-api/connectors/[a-f0-9\\-]{36}/connections/[a-f0-9\\-]{36}/status/history");
 
     private final long componentStatusSnapshotMillis;
 
@@ -69,19 +74,19 @@ public class StatusHistoryEndpointMerger implements 
EndpointResponseMerger {
 
         final Map<String, MetricDescriptor<?>> metricDescriptors = new 
HashMap<>();
 
-        if (PROCESSOR_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
+        if (PROCESSOR_STATUS_HISTORY_URI_PATTERN.matcher(path).matches() || 
CONNECTOR_PROCESSOR_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
             for (final ProcessorStatusDescriptor descriptor : 
ProcessorStatusDescriptor.values()) {
                 metricDescriptors.put(descriptor.getField(), 
descriptor.getDescriptor());
             }
-        } else if 
(PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
+        } else if 
(PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN.matcher(path).matches() || 
CONNECTOR_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
             for (final ProcessGroupStatusDescriptor descriptor : 
ProcessGroupStatusDescriptor.values()) {
                 metricDescriptors.put(descriptor.getField(), 
descriptor.getDescriptor());
             }
-        } else if 
(REMOTE_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
+        } else if 
(REMOTE_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN.matcher(path).matches() || 
CONNECTOR_REMOTE_PROCESS_GROUP_STATUS_HISTORY_URI_PATTERN.matcher(path).matches())
 {
             for (final RemoteProcessGroupStatusDescriptor descriptor : 
RemoteProcessGroupStatusDescriptor.values()) {
                 metricDescriptors.put(descriptor.getField(), 
descriptor.getDescriptor());
             }
-        } else if 
(CONNECTION_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
+        } else if 
(CONNECTION_STATUS_HISTORY_URI_PATTERN.matcher(path).matches() || 
CONNECTOR_CONNECTION_STATUS_HISTORY_URI_PATTERN.matcher(path).matches()) {
             for (final ConnectionStatusDescriptor descriptor : 
ConnectionStatusDescriptor.values()) {
                 metricDescriptors.put(descriptor.getField(), 
descriptor.getDescriptor());
             }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java
index 3423b12194a..f1d85555f51 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/test/java/org/apache/nifi/cluster/coordination/http/endpoints/TestStatusHistoryEndpointMerger.java
@@ -19,11 +19,34 @@ package org.apache.nifi.cluster.coordination.http.endpoints;
 
 import org.junit.jupiter.api.Test;
 
+import java.net.URI;
 import java.util.Date;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class TestStatusHistoryEndpointMerger {
+
+    private static final String UUID = "12345678-1234-1234-1234-123456789012";
+
+    @Test
+    public void testCanHandleConnectorStatusHistory() {
+        final StatusHistoryEndpointMerger merger = new 
StatusHistoryEndpointMerger(300000);
+
+        assertTrue(merger.canHandle(URI.create("/nifi-api/connectors/" + UUID 
+ "/processors/" + UUID + "/status/history"), "GET"));
+        assertTrue(merger.canHandle(URI.create("/nifi-api/connectors/" + UUID 
+ "/connections/" + UUID + "/status/history"), "GET"));
+        assertTrue(merger.canHandle(URI.create("/nifi-api/connectors/" + UUID 
+ "/process-groups/" + UUID + "/status/history"), "GET"));
+        assertTrue(merger.canHandle(URI.create("/nifi-api/connectors/" + UUID 
+ "/remote-process-groups/" + UUID + "/status/history"), "GET"));
+
+        // The top-level flow endpoints continue to be handled alongside the 
connector endpoints.
+        assertTrue(merger.canHandle(URI.create("/nifi-api/flow/processors/" + 
UUID + "/status/history"), "GET"));
+
+        // Non-GET methods and unrelated connector paths are not handled.
+        assertFalse(merger.canHandle(URI.create("/nifi-api/connectors/" + UUID 
+ "/processors/" + UUID + "/status/history"), "POST"));
+        assertFalse(merger.canHandle(URI.create("/nifi-api/connectors/" + UUID 
+ "/status"), "GET"));
+    }
+
     @Test
     public void testNormalizedStatusSnapshotDate() {
         final Date date1 = new Date(1388538000000L);
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index 99d5992083d..df1be3ce68c 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -242,6 +242,46 @@ public interface NiFiServiceFacade {
 
     ProcessGroupStatusEntity getConnectorProcessGroupStatus(String id, Boolean 
recursive);
 
+    /**
+     * Gets the status history for a Processor inside the Connector's managed 
flow. The status history is available
+     * regardless of whether the Connector is in Troubleshooting mode.
+     *
+     * @param connectorId the connector id
+     * @param processorId the processor id within the connector's managed flow
+     * @return the status history
+     */
+    StatusHistoryEntity getConnectorProcessorStatusHistory(String connectorId, 
String processorId);
+
+    /**
+     * Gets the status history for a Connection inside the Connector's managed 
flow. The status history is available
+     * regardless of whether the Connector is in Troubleshooting mode.
+     *
+     * @param connectorId the connector id
+     * @param connectionId the connection id within the connector's managed 
flow
+     * @return the status history
+     */
+    StatusHistoryEntity getConnectorConnectionStatusHistory(String 
connectorId, String connectionId);
+
+    /**
+     * Gets the status history for a Process Group inside the Connector's 
managed flow. The status history is available
+     * regardless of whether the Connector is in Troubleshooting mode.
+     *
+     * @param connectorId the connector id
+     * @param processGroupId the process group id within the connector's 
managed flow
+     * @return the status history
+     */
+    StatusHistoryEntity getConnectorProcessGroupStatusHistory(String 
connectorId, String processGroupId);
+
+    /**
+     * Gets the status history for a Remote Process Group inside the 
Connector's managed flow. The status history is
+     * available regardless of whether the Connector is in Troubleshooting 
mode.
+     *
+     * @param connectorId the connector id
+     * @param remoteProcessGroupId the remote process group id within the 
connector's managed flow
+     * @return the status history
+     */
+    StatusHistoryEntity getConnectorRemoteProcessGroupStatusHistory(String 
connectorId, String remoteProcessGroupId);
+
     Set<ControllerServiceEntity> getConnectorControllerServices(String 
connectorId, String processGroupId, boolean includeAncestorGroups,
                                                                 boolean 
includeDescendantGroups, boolean includeReferencingComponents);
 
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index 77b18e862d0..f92d6c6aad3 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -4043,6 +4043,59 @@ public class StandardNiFiServiceFacade implements 
NiFiServiceFacade {
         return entityFactory.createProcessGroupStatusEntity(dto, permissions);
     }
 
+    @Override
+    public StatusHistoryEntity getConnectorProcessorStatusHistory(final String 
connectorId, final String processorId) {
+        final ConnectorNode connectorNode = 
connectorDAO.getConnector(connectorId, ConnectorSyncMode.LOCAL_ONLY);
+        final ProcessGroup managedGroup = 
connectorNode.getActiveFlowContext().getManagedProcessGroup();
+        if (managedGroup.findProcessor(processorId) == null) {
+            throw new ResourceNotFoundException("Unable to find processor with 
id '%s' within connector '%s'.".formatted(processorId, connectorId));
+        }
+
+        final PermissionsDTO permissions = 
dtoFactory.createPermissionsDto(connectorNode);
+        final StatusHistoryDTO dto = 
controllerFacade.getConnectorProcessorStatusHistory(processorId);
+        return entityFactory.createStatusHistoryEntity(dto, permissions);
+    }
+
+    @Override
+    public StatusHistoryEntity getConnectorConnectionStatusHistory(final 
String connectorId, final String connectionId) {
+        final ConnectorNode connectorNode = 
connectorDAO.getConnector(connectorId, ConnectorSyncMode.LOCAL_ONLY);
+        final ProcessGroup managedGroup = 
connectorNode.getActiveFlowContext().getManagedProcessGroup();
+        if (managedGroup.findConnection(connectionId) == null) {
+            throw new ResourceNotFoundException("Unable to find connection 
with id '%s' within connector '%s'.".formatted(connectionId, connectorId));
+        }
+
+        final PermissionsDTO permissions = 
dtoFactory.createPermissionsDto(connectorNode);
+        final StatusHistoryDTO dto = 
controllerFacade.getConnectorConnectionStatusHistory(connectionId);
+        return entityFactory.createStatusHistoryEntity(dto, permissions);
+    }
+
+    @Override
+    public StatusHistoryEntity getConnectorProcessGroupStatusHistory(final 
String connectorId, final String processGroupId) {
+        final ConnectorNode connectorNode = 
connectorDAO.getConnector(connectorId, ConnectorSyncMode.LOCAL_ONLY);
+        final ProcessGroup managedGroup = 
connectorNode.getActiveFlowContext().getManagedProcessGroup();
+        final ProcessGroup processGroup = 
managedGroup.getIdentifier().equals(processGroupId) ? managedGroup : 
managedGroup.findProcessGroup(processGroupId);
+        if (processGroup == null) {
+            throw new ResourceNotFoundException("Unable to find process group 
with id '%s' within connector '%s'.".formatted(processGroupId, connectorId));
+        }
+
+        final PermissionsDTO permissions = 
dtoFactory.createPermissionsDto(connectorNode);
+        final StatusHistoryDTO dto = 
controllerFacade.getConnectorProcessGroupStatusHistory(processGroupId);
+        return entityFactory.createStatusHistoryEntity(dto, permissions);
+    }
+
+    @Override
+    public StatusHistoryEntity 
getConnectorRemoteProcessGroupStatusHistory(final String connectorId, final 
String remoteProcessGroupId) {
+        final ConnectorNode connectorNode = 
connectorDAO.getConnector(connectorId, ConnectorSyncMode.LOCAL_ONLY);
+        final ProcessGroup managedGroup = 
connectorNode.getActiveFlowContext().getManagedProcessGroup();
+        if (managedGroup.findRemoteProcessGroup(remoteProcessGroupId) == null) 
{
+            throw new ResourceNotFoundException("Unable to find remote process 
group with id '%s' within connector '%s'.".formatted(remoteProcessGroupId, 
connectorId));
+        }
+
+        final PermissionsDTO permissions = 
dtoFactory.createPermissionsDto(connectorNode);
+        final StatusHistoryDTO dto = 
controllerFacade.getConnectorRemoteProcessGroupStatusHistory(remoteProcessGroupId);
+        return entityFactory.createStatusHistoryEntity(dto, permissions);
+    }
+
     @Override
     public Set<ControllerServiceEntity> getConnectorControllerServices(final 
String connectorId, final String processGroupId,
             final boolean includeAncestorGroups, final boolean 
includeDescendantGroups, final boolean includeReferencingComponents) {
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
index 1b3685a72f9..dd8cd557597 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
@@ -98,6 +98,7 @@ import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
 import org.apache.nifi.web.api.entity.SearchResultsEntity;
 import org.apache.nifi.web.api.entity.SecretsEntity;
+import org.apache.nifi.web.api.entity.StatusHistoryEntity;
 import org.apache.nifi.web.api.entity.VerifyConnectorConfigStepRequestEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.LongParameter;
@@ -2164,6 +2165,194 @@ public class ConnectorResource extends 
ApplicationResource {
         return generateOkResponse(entity).build();
     }
 
+    // -----------------
+    // Status History
+    // -----------------
+
+    /**
+     * Gets the status history for a Processor inside the Connector's managed 
flow. The status history is available
+     * regardless of whether the Connector is in Troubleshooting mode.
+     *
+     * @param connectorId the connector id
+     * @param processorId the processor id within the connector's managed flow
+     * @return A statusHistoryEntity.
+     * @throws InterruptedException if interrupted
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("{id}/processors/{processorId}/status/history")
+    @Operation(
+            summary = "Gets the status history for a processor within a 
connector",
+            responses = {
+                    @ApiResponse(responseCode = "200", content = 
@Content(schema = @Schema(implementation = StatusHistoryEntity.class))),
+                    @ApiResponse(responseCode = "400", description = "NiFi was 
unable to complete the request because it was invalid. The request should not 
be retried without modification."),
+                    @ApiResponse(responseCode = "401", description = "Client 
could not be authenticated."),
+                    @ApiResponse(responseCode = "403", description = "Client 
is not authorized to make this request."),
+                    @ApiResponse(responseCode = "404", description = "The 
specified resource could not be found."),
+                    @ApiResponse(responseCode = "409", description = "The 
request was valid but NiFi was not in the appropriate state to process it.")
+            },
+            security = {
+                    @SecurityRequirement(name = "Read - /connectors/{uuid}")
+            }
+    )
+    public Response getConnectorProcessorStatusHistory(
+            @Parameter(description = "The connector id.", required = true)
+            @PathParam("id") final String connectorId,
+            @Parameter(description = "The processor id.", required = true)
+            @PathParam("processorId") final String processorId) throws 
InterruptedException {
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable connector = lookup.getConnector(connectorId);
+            connector.authorize(authorizer, RequestAction.READ, 
NiFiUserUtils.getNiFiUser());
+        });
+
+        final StatusHistoryEntity entity = 
serviceFacade.getConnectorProcessorStatusHistory(connectorId, processorId);
+        return generateOkResponse(entity).build();
+    }
+
+    /**
+     * Gets the status history for a Connection inside the Connector's managed 
flow. The status history is available
+     * regardless of whether the Connector is in Troubleshooting mode.
+     *
+     * @param connectorId the connector id
+     * @param connectionId the connection id within the connector's managed 
flow
+     * @return A statusHistoryEntity.
+     * @throws InterruptedException if interrupted
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("{id}/connections/{connectionId}/status/history")
+    @Operation(
+            summary = "Gets the status history for a connection within a 
connector",
+            responses = {
+                    @ApiResponse(responseCode = "200", content = 
@Content(schema = @Schema(implementation = StatusHistoryEntity.class))),
+                    @ApiResponse(responseCode = "400", description = "NiFi was 
unable to complete the request because it was invalid. The request should not 
be retried without modification."),
+                    @ApiResponse(responseCode = "401", description = "Client 
could not be authenticated."),
+                    @ApiResponse(responseCode = "403", description = "Client 
is not authorized to make this request."),
+                    @ApiResponse(responseCode = "404", description = "The 
specified resource could not be found."),
+                    @ApiResponse(responseCode = "409", description = "The 
request was valid but NiFi was not in the appropriate state to process it.")
+            },
+            security = {
+                    @SecurityRequirement(name = "Read - /connectors/{uuid}")
+            }
+    )
+    public Response getConnectorConnectionStatusHistory(
+            @Parameter(description = "The connector id.", required = true)
+            @PathParam("id") final String connectorId,
+            @Parameter(description = "The connection id.", required = true)
+            @PathParam("connectionId") final String connectionId) throws 
InterruptedException {
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable connector = lookup.getConnector(connectorId);
+            connector.authorize(authorizer, RequestAction.READ, 
NiFiUserUtils.getNiFiUser());
+        });
+
+        final StatusHistoryEntity entity = 
serviceFacade.getConnectorConnectionStatusHistory(connectorId, connectionId);
+        return generateOkResponse(entity).build();
+    }
+
+    /**
+     * Gets the status history for a Process Group inside the Connector's 
managed flow. The status history is available
+     * regardless of whether the Connector is in Troubleshooting mode.
+     *
+     * @param connectorId the connector id
+     * @param processGroupId the process group id within the connector's 
managed flow
+     * @return A statusHistoryEntity.
+     * @throws InterruptedException if interrupted
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("{id}/process-groups/{processGroupId}/status/history")
+    @Operation(
+            summary = "Gets the status history for a process group within a 
connector",
+            responses = {
+                    @ApiResponse(responseCode = "200", content = 
@Content(schema = @Schema(implementation = StatusHistoryEntity.class))),
+                    @ApiResponse(responseCode = "400", description = "NiFi was 
unable to complete the request because it was invalid. The request should not 
be retried without modification."),
+                    @ApiResponse(responseCode = "401", description = "Client 
could not be authenticated."),
+                    @ApiResponse(responseCode = "403", description = "Client 
is not authorized to make this request."),
+                    @ApiResponse(responseCode = "404", description = "The 
specified resource could not be found."),
+                    @ApiResponse(responseCode = "409", description = "The 
request was valid but NiFi was not in the appropriate state to process it.")
+            },
+            security = {
+                    @SecurityRequirement(name = "Read - /connectors/{uuid}")
+            }
+    )
+    public Response getConnectorProcessGroupStatusHistory(
+            @Parameter(description = "The connector id.", required = true)
+            @PathParam("id") final String connectorId,
+            @Parameter(description = "The process group id.", required = true)
+            @PathParam("processGroupId") final String processGroupId) throws 
InterruptedException {
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable connector = lookup.getConnector(connectorId);
+            connector.authorize(authorizer, RequestAction.READ, 
NiFiUserUtils.getNiFiUser());
+        });
+
+        final StatusHistoryEntity entity = 
serviceFacade.getConnectorProcessGroupStatusHistory(connectorId, 
processGroupId);
+        return generateOkResponse(entity).build();
+    }
+
+    /**
+     * Gets the status history for a Remote Process Group inside the 
Connector's managed flow. The status history is
+     * available regardless of whether the Connector is in Troubleshooting 
mode.
+     *
+     * @param connectorId the connector id
+     * @param remoteProcessGroupId the remote process group id within the 
connector's managed flow
+     * @return A statusHistoryEntity.
+     * @throws InterruptedException if interrupted
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("{id}/remote-process-groups/{remoteProcessGroupId}/status/history")
+    @Operation(
+            summary = "Gets the status history for a remote process group 
within a connector",
+            responses = {
+                    @ApiResponse(responseCode = "200", content = 
@Content(schema = @Schema(implementation = StatusHistoryEntity.class))),
+                    @ApiResponse(responseCode = "400", description = "NiFi was 
unable to complete the request because it was invalid. The request should not 
be retried without modification."),
+                    @ApiResponse(responseCode = "401", description = "Client 
could not be authenticated."),
+                    @ApiResponse(responseCode = "403", description = "Client 
is not authorized to make this request."),
+                    @ApiResponse(responseCode = "404", description = "The 
specified resource could not be found."),
+                    @ApiResponse(responseCode = "409", description = "The 
request was valid but NiFi was not in the appropriate state to process it.")
+            },
+            security = {
+                    @SecurityRequirement(name = "Read - /connectors/{uuid}")
+            }
+    )
+    public Response getConnectorRemoteProcessGroupStatusHistory(
+            @Parameter(description = "The connector id.", required = true)
+            @PathParam("id") final String connectorId,
+            @Parameter(description = "The remote process group id.", required 
= true)
+            @PathParam("remoteProcessGroupId") final String 
remoteProcessGroupId) throws InterruptedException {
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable connector = lookup.getConnector(connectorId);
+            connector.authorize(authorizer, RequestAction.READ, 
NiFiUserUtils.getNiFiUser());
+        });
+
+        final StatusHistoryEntity entity = 
serviceFacade.getConnectorRemoteProcessGroupStatusHistory(connectorId, 
remoteProcessGroupId);
+        return generateOkResponse(entity).build();
+    }
+
     @POST
     @Consumes(MediaType.APPLICATION_OCTET_STREAM)
     @Produces(MediaType.APPLICATION_JSON)
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
index 080b9fb3ae2..3cd15e3219d 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
@@ -433,6 +433,54 @@ public class ControllerFacade implements Authorizable {
         return statusHistory;
     }
 
+    /**
+     * Returns the status history for a Processor inside a Connector's managed 
flow. The component is resolved and
+     * authorized at the Connector level before this method is invoked, so the 
status history is read directly from the
+     * repository by id without consulting the root flow hierarchy or applying 
per-component authorization masking.
+     *
+     * @param processorId processor id
+     * @return status history
+     */
+    public StatusHistoryDTO getConnectorProcessorStatusHistory(final String 
processorId) {
+        return flowController.getProcessorStatusHistory(processorId, true);
+    }
+
+    /**
+     * Returns the status history for a Connection inside a Connector's 
managed flow. The component is resolved and
+     * authorized at the Connector level before this method is invoked, so the 
status history is read directly from the
+     * repository by id without consulting the root flow hierarchy or applying 
per-component authorization masking.
+     *
+     * @param connectionId connection id
+     * @return status history
+     */
+    public StatusHistoryDTO getConnectorConnectionStatusHistory(final String 
connectionId) {
+        return flowController.getConnectionStatusHistory(connectionId);
+    }
+
+    /**
+     * Returns the status history for a Process Group inside a Connector's 
managed flow. The component is resolved and
+     * authorized at the Connector level before this method is invoked, so the 
status history is read directly from the
+     * repository by id without consulting the root flow hierarchy or applying 
per-component authorization masking.
+     *
+     * @param processGroupId process group id
+     * @return status history
+     */
+    public StatusHistoryDTO getConnectorProcessGroupStatusHistory(final String 
processGroupId) {
+        return flowController.getProcessGroupStatusHistory(processGroupId);
+    }
+
+    /**
+     * Returns the status history for a Remote Process Group inside a 
Connector's managed flow. The component is resolved
+     * and authorized at the Connector level before this method is invoked, so 
the status history is read directly from
+     * the repository by id without consulting the root flow hierarchy or 
applying per-component authorization masking.
+     *
+     * @param remoteProcessGroupId remote process group id
+     * @return status history
+     */
+    public StatusHistoryDTO getConnectorRemoteProcessGroupStatusHistory(final 
String remoteProcessGroupId) {
+        return 
flowController.getRemoteProcessGroupStatusHistory(remoteProcessGroupId);
+    }
+
     /**
      * Get the node id of this controller.
      *
diff --git 
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorStatusHistoryIT.java
 
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorStatusHistoryIT.java
new file mode 100644
index 00000000000..6e4ab99899e
--- /dev/null
+++ 
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorStatusHistoryIT.java
@@ -0,0 +1,232 @@
+/*
+ * 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.tests.system.connectors;
+
+import jakarta.ws.rs.WebApplicationException;
+import org.apache.nifi.components.connector.ConnectorState;
+import org.apache.nifi.controller.status.history.StatusHistoryRepository;
+import org.apache.nifi.tests.system.NiFiSystemIT;
+import org.apache.nifi.toolkit.client.ConnectorClient;
+import org.apache.nifi.toolkit.client.NiFiClientException;
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
+import org.apache.nifi.web.api.entity.ConnectionEntity;
+import org.apache.nifi.web.api.entity.ConnectorEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.web.api.entity.StatusHistoryEntity;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.atomic.AtomicReference;
+
+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;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * System tests that verify the Status History REST endpoints for components 
inside a Connector's managed flow.
+ */
+public class ConnectorStatusHistoryIT extends NiFiSystemIT {
+
+    @Override
+    protected Map<String, String> getNifiPropertiesOverrides() {
+        // Capture component status snapshots once per second so the test does 
not have to wait the default one minute
+        // for the first snapshot to be recorded.
+        return Map.of("nifi.components.status.snapshot.frequency", "1 sec");
+    }
+
+    /**
+     * Status history for components inside a Connector's managed flow must be 
retrievable whether the Connector is
+     * RUNNING or in Troubleshooting mode. The standard component endpoints 
reject requests with a 409 when the
+     * Connector is not in Troubleshooting; the Connector status history 
endpoints must not be subject to that gate.
+     */
+    @Test
+    public void testStatusHistoryAvailableRegardlessOfTroubleshooting() throws 
NiFiClientException, IOException, InterruptedException {
+        final ConnectorEntity connector = 
getClientUtil().createConnector("ComponentLifecycleConnector");
+        final String connectorId = connector.getId();
+
+        getClientUtil().applyConnectorUpdate(connector);
+        getClientUtil().waitForValidConnector(connectorId);
+
+        final String managedGroupId = 
getNifiClient().getConnectorClient().getConnector(connectorId).getComponent().getManagedProcessGroupId();
+        assertNotNull(managedGroupId);
+
+        final String processorId = findFirstProcessorId(connectorId);
+        final String connectionId = findFirstConnectionId(connectorId);
+        assertNotNull(processorId);
+        assertNotNull(connectionId);
+
+        getClientUtil().startConnector(connectorId);
+        assertConnectorState(connectorId, ConnectorState.RUNNING);
+
+        // While the Connector is RUNNING (not in Troubleshooting), the 
standard component endpoint is gated with a 409,
+        // but the Connector status history endpoints must still return data.
+        assertConflict("GET processor outside Troubleshooting", () -> 
getNifiClient().getProcessorClient().getProcessor(processorId));
+
+        assertStatusHistoryAvailable(connectorId, processorId, connectionId, 
managedGroupId);
+
+        getClientUtil().enterTroubleshooting(connectorId);
+        assertConnectorState(connectorId, ConnectorState.TROUBLESHOOTING);
+
+        // The same component status history must remain available once the 
Connector enters Troubleshooting.
+        assertStatusHistoryAvailable(connectorId, processorId, connectionId, 
managedGroupId);
+    }
+
+    /**
+     * Unknown component ids, and component ids that exist elsewhere in NiFi 
but not inside the target Connector's
+     * managed flow, must produce a 404 Not Found for each component type. The 
latter verifies that the endpoints are
+     * scoped to the Connector rather than resolving any component id from the 
repository.
+     */
+    @Test
+    public void testStatusHistoryNotFoundForUnknownComponent() throws 
NiFiClientException, IOException, InterruptedException {
+        final ConnectorEntity connector = 
getClientUtil().createConnector("ComponentLifecycleConnector");
+        final String connectorId = connector.getId();
+
+        getClientUtil().applyConnectorUpdate(connector);
+        getClientUtil().waitForValidConnector(connectorId);
+
+        final ConnectorClient connectorClient = 
getNifiClient().getConnectorClient();
+        final String unknownId = UUID.randomUUID().toString();
+
+        assertNotFound("processor status history", () -> 
connectorClient.getProcessorStatusHistory(connectorId, unknownId));
+        assertNotFound("connection status history", () -> 
connectorClient.getConnectionStatusHistory(connectorId, unknownId));
+        assertNotFound("process group status history", () -> 
connectorClient.getProcessGroupStatusHistory(connectorId, unknownId));
+        assertNotFound("remote process group status history", () -> 
connectorClient.getRemoteProcessGroupStatusHistory(connectorId, unknownId));
+
+        // A Processor that exists in the root flow, outside any Connector, 
must not be resolvable through the Connector
+        // status history endpoint.
+        final String rootProcessorId = 
getClientUtil().createProcessor("CountEvents").getId();
+        assertNotFound("processor status history for component outside the 
connector",
+                () -> connectorClient.getProcessorStatusHistory(connectorId, 
rootProcessorId));
+    }
+
+    private void assertStatusHistoryAvailable(final String connectorId, final 
String processorId, final String connectionId, final String processGroupId)
+            throws InterruptedException {
+
+        final ConnectorClient connectorClient = 
getNifiClient().getConnectorClient();
+
+        final StatusHistoryEntity processorHistory = waitForStatusHistory(() 
-> connectorClient.getProcessorStatusHistory(connectorId, processorId));
+        assertComponentHistory(processorHistory, processorId);
+
+        final StatusHistoryEntity connectionHistory = waitForStatusHistory(() 
-> connectorClient.getConnectionStatusHistory(connectorId, connectionId));
+        assertComponentHistory(connectionHistory, connectionId);
+
+        final StatusHistoryEntity processGroupHistory = 
waitForStatusHistory(() -> 
connectorClient.getProcessGroupStatusHistory(connectorId, processGroupId));
+        assertComponentHistory(processGroupHistory, processGroupId);
+    }
+
+    private void assertComponentHistory(final StatusHistoryEntity entity, 
final String componentId) {
+        assertNotNull(entity);
+        assertTrue(entity.getCanRead());
+        assertNotNull(entity.getStatusHistory());
+        
assertFalse(entity.getStatusHistory().getAggregateSnapshots().isEmpty());
+        assertEquals(componentId, 
entity.getStatusHistory().getComponentDetails().get(StatusHistoryRepository.COMPONENT_DETAIL_ID));
+    }
+
+    private StatusHistoryEntity waitForStatusHistory(final 
Callable<StatusHistoryEntity> supplier) throws InterruptedException {
+        final AtomicReference<StatusHistoryEntity> holder = new 
AtomicReference<>();
+        waitFor(() -> {
+            final StatusHistoryEntity entity = supplier.call();
+            if (entity != null && entity.getStatusHistory() != null && 
!entity.getStatusHistory().getAggregateSnapshots().isEmpty()) {
+                holder.set(entity);
+                return true;
+            }
+
+            return false;
+        });
+        return holder.get();
+    }
+
+    private String findFirstProcessorId(final String connectorId) throws 
NiFiClientException, IOException {
+        final List<ProcessorEntity> processors = new ArrayList<>();
+        collectProcessors(connectorId, null, processors);
+        return processors.isEmpty() ? null : processors.getFirst().getId();
+    }
+
+    private void collectProcessors(final String connectorId, final String 
groupId, final List<ProcessorEntity> collected) throws NiFiClientException, 
IOException {
+        final ProcessGroupFlowEntity entity = (groupId == null)
+                ? getNifiClient().getConnectorClient().getFlow(connectorId)
+                : getNifiClient().getConnectorClient().getFlow(connectorId, 
groupId);
+        final FlowDTO flow = entity.getProcessGroupFlow().getFlow();
+        collected.addAll(flow.getProcessors());
+
+        for (final ProcessGroupEntity child : flow.getProcessGroups()) {
+            collectProcessors(connectorId, child.getId(), collected);
+        }
+    }
+
+    private String findFirstConnectionId(final String connectorId) throws 
NiFiClientException, IOException {
+        return collectFirstConnectionId(connectorId, null);
+    }
+
+    private String collectFirstConnectionId(final String connectorId, final 
String groupId) throws NiFiClientException, IOException {
+        final ProcessGroupFlowEntity entity = (groupId == null)
+                ? getNifiClient().getConnectorClient().getFlow(connectorId)
+                : getNifiClient().getConnectorClient().getFlow(connectorId, 
groupId);
+        final FlowDTO flow = entity.getProcessGroupFlow().getFlow();
+        for (final ConnectionEntity connection : flow.getConnections()) {
+            return connection.getId();
+        }
+
+        for (final ProcessGroupEntity child : flow.getProcessGroups()) {
+            final String childConnectionId = 
collectFirstConnectionId(connectorId, child.getId());
+            if (childConnectionId != null) {
+                return childConnectionId;
+            }
+        }
+
+        return null;
+    }
+
+    private void assertConnectorState(final String connectorId, final 
ConnectorState expected) throws NiFiClientException, IOException {
+        final ConnectorEntity entity = 
getNifiClient().getConnectorClient().getConnector(connectorId);
+        assertEquals(expected.name(), entity.getComponent().getState());
+    }
+
+    private void assertNotFound(final String description, final Callable<?> 
call) {
+        assertExpectedStatus(description, call, 404);
+    }
+
+    private void assertConflict(final String description, final Callable<?> 
call) {
+        assertExpectedStatus(description, call, 409);
+    }
+
+    private void assertExpectedStatus(final String description, final 
Callable<?> call, final int expectedStatus) {
+        try {
+            call.call();
+            fail("Expected HTTP " + expectedStatus + " for " + description + " 
but request succeeded");
+        } catch (final NiFiClientException e) {
+            final Throwable cause = e.getCause();
+            if (cause instanceof WebApplicationException wae) {
+                assertEquals(expectedStatus, wae.getResponse().getStatus(), 
"Unexpected status for " + description);
+            } else {
+                fail("Expected WebApplicationException " + expectedStatus + " 
for " + description + ", got: " + cause);
+            }
+        } catch (final Exception e) {
+            fail("Unexpected exception while invoking " + description + ": " + 
e.getMessage());
+        }
+    }
+}
diff --git 
a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java
 
b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java
index 14a909fc3bc..76f49df4b07 100644
--- 
a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java
+++ 
b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/ConnectorClient.java
@@ -26,6 +26,7 @@ import 
org.apache.nifi.web.api.entity.ConnectorPropertyAllowableValuesEntity;
 import org.apache.nifi.web.api.entity.DropRequestEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
+import org.apache.nifi.web.api.entity.StatusHistoryEntity;
 import org.apache.nifi.web.api.entity.VerifyConnectorConfigStepRequestEntity;
 
 import java.io.File;
@@ -323,6 +324,50 @@ public interface ConnectorClient {
      */
     ProcessGroupStatusEntity getStatus(String connectorId, boolean recursive) 
throws NiFiClientException, IOException;
 
+    /**
+     * Gets the status history for a processor within a connector's managed 
flow.
+     *
+     * @param connectorId the connector ID
+     * @param processorId the processor ID within the connector's managed flow
+     * @return the status history entity
+     * @throws NiFiClientException if an error occurs during the request
+     * @throws IOException if an I/O error occurs
+     */
+    StatusHistoryEntity getProcessorStatusHistory(String connectorId, String 
processorId) throws NiFiClientException, IOException;
+
+    /**
+     * Gets the status history for a connection within a connector's managed 
flow.
+     *
+     * @param connectorId the connector ID
+     * @param connectionId the connection ID within the connector's managed 
flow
+     * @return the status history entity
+     * @throws NiFiClientException if an error occurs during the request
+     * @throws IOException if an I/O error occurs
+     */
+    StatusHistoryEntity getConnectionStatusHistory(String connectorId, String 
connectionId) throws NiFiClientException, IOException;
+
+    /**
+     * Gets the status history for a process group within a connector's 
managed flow.
+     *
+     * @param connectorId the connector ID
+     * @param processGroupId the process group ID within the connector's 
managed flow
+     * @return the status history entity
+     * @throws NiFiClientException if an error occurs during the request
+     * @throws IOException if an I/O error occurs
+     */
+    StatusHistoryEntity getProcessGroupStatusHistory(String connectorId, 
String processGroupId) throws NiFiClientException, IOException;
+
+    /**
+     * Gets the status history for a remote process group within a connector's 
managed flow.
+     *
+     * @param connectorId the connector ID
+     * @param remoteProcessGroupId the remote process group ID within the 
connector's managed flow
+     * @return the status history entity
+     * @throws NiFiClientException if an error occurs during the request
+     * @throws IOException if an I/O error occurs
+     */
+    StatusHistoryEntity getRemoteProcessGroupStatusHistory(String connectorId, 
String remoteProcessGroupId) throws NiFiClientException, IOException;
+
     /**
      * Creates an asset in the given connector.
      *
diff --git 
a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java
 
b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java
index d972f489159..915091d08e5 100644
--- 
a/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java
+++ 
b/nifi-toolkit/nifi-toolkit-client/src/main/java/org/apache/nifi/toolkit/client/impl/JerseyConnectorClient.java
@@ -36,6 +36,7 @@ import 
org.apache.nifi.web.api.entity.ConnectorRunStatusEntity;
 import org.apache.nifi.web.api.entity.DropRequestEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
+import org.apache.nifi.web.api.entity.StatusHistoryEntity;
 import org.apache.nifi.web.api.entity.VerifyConnectorConfigStepRequestEntity;
 
 import java.io.File;
@@ -527,6 +528,82 @@ public class JerseyConnectorClient extends 
AbstractJerseyClient implements Conne
         });
     }
 
+    @Override
+    public StatusHistoryEntity getProcessorStatusHistory(final String 
connectorId, final String processorId) throws NiFiClientException, IOException {
+        if (StringUtils.isBlank(connectorId)) {
+            throw new IllegalArgumentException("Connector id cannot be null or 
blank");
+        }
+        if (StringUtils.isBlank(processorId)) {
+            throw new IllegalArgumentException("Processor id cannot be null or 
blank");
+        }
+
+        return executeAction("Error retrieving processor status history for 
Connector " + connectorId, () -> {
+            final WebTarget target = connectorTarget
+                    .path("/processors/{processorId}/status/history")
+                    .resolveTemplate("id", connectorId)
+                    .resolveTemplate("processorId", processorId);
+
+            return getRequestBuilder(target).get(StatusHistoryEntity.class);
+        });
+    }
+
+    @Override
+    public StatusHistoryEntity getConnectionStatusHistory(final String 
connectorId, final String connectionId) throws NiFiClientException, IOException 
{
+        if (StringUtils.isBlank(connectorId)) {
+            throw new IllegalArgumentException("Connector id cannot be null or 
blank");
+        }
+        if (StringUtils.isBlank(connectionId)) {
+            throw new IllegalArgumentException("Connection id cannot be null 
or blank");
+        }
+
+        return executeAction("Error retrieving connection status history for 
Connector " + connectorId, () -> {
+            final WebTarget target = connectorTarget
+                    .path("/connections/{connectionId}/status/history")
+                    .resolveTemplate("id", connectorId)
+                    .resolveTemplate("connectionId", connectionId);
+
+            return getRequestBuilder(target).get(StatusHistoryEntity.class);
+        });
+    }
+
+    @Override
+    public StatusHistoryEntity getProcessGroupStatusHistory(final String 
connectorId, final String processGroupId) throws NiFiClientException, 
IOException {
+        if (StringUtils.isBlank(connectorId)) {
+            throw new IllegalArgumentException("Connector id cannot be null or 
blank");
+        }
+        if (StringUtils.isBlank(processGroupId)) {
+            throw new IllegalArgumentException("Process group id cannot be 
null or blank");
+        }
+
+        return executeAction("Error retrieving process group status history 
for Connector " + connectorId, () -> {
+            final WebTarget target = connectorTarget
+                    .path("/process-groups/{processGroupId}/status/history")
+                    .resolveTemplate("id", connectorId)
+                    .resolveTemplate("processGroupId", processGroupId);
+
+            return getRequestBuilder(target).get(StatusHistoryEntity.class);
+        });
+    }
+
+    @Override
+    public StatusHistoryEntity getRemoteProcessGroupStatusHistory(final String 
connectorId, final String remoteProcessGroupId) throws NiFiClientException, 
IOException {
+        if (StringUtils.isBlank(connectorId)) {
+            throw new IllegalArgumentException("Connector id cannot be null or 
blank");
+        }
+        if (StringUtils.isBlank(remoteProcessGroupId)) {
+            throw new IllegalArgumentException("Remote process group id cannot 
be null or blank");
+        }
+
+        return executeAction("Error retrieving remote process group status 
history for Connector " + connectorId, () -> {
+            final WebTarget target = connectorTarget
+                    
.path("/remote-process-groups/{remoteProcessGroupId}/status/history")
+                    .resolveTemplate("id", connectorId)
+                    .resolveTemplate("remoteProcessGroupId", 
remoteProcessGroupId);
+
+            return getRequestBuilder(target).get(StatusHistoryEntity.class);
+        });
+    }
+
     @Override
     public AssetEntity createAsset(final String connectorId, final String 
assetName, final File file) throws NiFiClientException, IOException {
         if (StringUtils.isBlank(connectorId)) {

Reply via email to