This is an automated email from the ASF dual-hosted git repository.
markap14 pushed a commit to branch NIFI-15258
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/NIFI-15258 by this push:
new 2b72f7a588 NIFI-15465 Allow client-specified connector component ids
(#10768)
2b72f7a588 is described below
commit 2b72f7a5882831a72eb97aaf2791a703beb71d38
Author: Kevin Doran <[email protected]>
AuthorDate: Fri Jan 23 10:21:13 2026 -0500
NIFI-15465 Allow client-specified connector component ids (#10768)
Add verifyCreate to ConnectorDAO and test cases
---
.../apache/nifi/web/StandardNiFiServiceFacade.java | 2 +-
.../org/apache/nifi/web/api/ConnectorResource.java | 29 +++++++-
.../java/org/apache/nifi/web/dao/ConnectorDAO.java | 3 +
.../nifi/web/dao/impl/StandardConnectorDAO.java | 9 +++
.../apache/nifi/web/api/TestConnectorResource.java | 85 ++++++++++++++++++++++
.../web/dao/impl/StandardConnectorDAOTest.java | 39 ++++++++++
6 files changed, 162 insertions(+), 5 deletions(-)
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 bee52d0446..aa76c19a37 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
@@ -801,7 +801,7 @@ public class StandardNiFiServiceFacade implements
NiFiServiceFacade {
@Override
public void verifyCreateConnector(final ConnectorDTO connectorDTO) {
- // For now, no additional verification on DTO here; creation will fail
in DAO if invalid
+ connectorDAO.verifyCreate(connectorDTO);
}
@Override
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 f7cd6c50f0..52ee7867f0 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
@@ -258,9 +258,6 @@ public class ConnectorResource extends ApplicationResource {
}
final ConnectorDTO requestConnector =
requestConnectorEntity.getComponent();
- if (requestConnector.getId() != null) {
- throw new IllegalArgumentException("Connector ID cannot be
specified.");
- }
if (StringUtils.isBlank(requestConnector.getType())) {
throw new IllegalArgumentException("The type of connector to
create must be specified.");
@@ -284,7 +281,13 @@ public class ConnectorResource extends ApplicationResource
{
final ConnectorDTO connector =
connectorEntity.getComponent();
// set the connector id as appropriate
- connector.setId(generateUuid());
+ final String clientSpecifiedId = connector.getId();
+ if (clientSpecifiedId != null) {
+ // validate the client-specified connector id.
uniqueness is verified by verifyCreateConnector()
+ connector.setId(normalizeUuid(clientSpecifiedId));
+ } else {
+ connector.setId(generateUuid());
+ }
// create the new connector
final Revision revision = getRevision(connectorEntity,
connector.getId());
@@ -298,6 +301,24 @@ public class ConnectorResource extends ApplicationResource
{
);
}
+ /**
+ * Validates client-specified id is a UUID and normalizes its string
format to the lowercase digest used by NiFi.
+ *
+ * @param clientSpecifiedId the client-passed ID, which should be a valid
UUID
+ * @return the normalized string representation of the validated UUID
+ * @throws IllegalArgumentException if the clientSpecifiedId is not a
valid UUID
+ */
+ private String normalizeUuid(final String clientSpecifiedId) {
+ try {
+ final UUID uuid = UUID.fromString(clientSpecifiedId);
+ logger.debug("ID [{}] is a valid UUID", clientSpecifiedId);
+ return uuid.toString();
+ } catch (final Exception e) {
+ logger.error("ID [{}] is not a valid UUID", clientSpecifiedId, e);
+ throw new IllegalArgumentException("ID [" + clientSpecifiedId + "]
is not a valid UUID.");
+ }
+ }
+
/**
* Retrieves the specified connector.
*
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectorDAO.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectorDAO.java
index d094f18ca9..6e2ff0f0c3 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectorDAO.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/ConnectorDAO.java
@@ -23,6 +23,7 @@ import org.apache.nifi.components.ConfigVerificationResult;
import org.apache.nifi.components.connector.ConnectorNode;
import org.apache.nifi.components.connector.ConnectorUpdateContext;
import org.apache.nifi.web.api.dto.ConfigurationStepConfigurationDTO;
+import org.apache.nifi.web.api.dto.ConnectorDTO;
import java.io.IOException;
import java.io.InputStream;
@@ -31,6 +32,8 @@ import java.util.Optional;
public interface ConnectorDAO {
+ void verifyCreate(ConnectorDTO connectorDTO);
+
boolean hasConnector(String id);
ConnectorNode getConnector(String id);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectorDAO.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectorDAO.java
index 8d18a5dff9..a2d0b17705 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectorDAO.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectorDAO.java
@@ -36,6 +36,7 @@ import org.apache.nifi.web.NiFiCoreException;
import org.apache.nifi.web.ResourceNotFoundException;
import org.apache.nifi.web.api.dto.AssetReferenceDTO;
import org.apache.nifi.web.api.dto.ConfigurationStepConfigurationDTO;
+import org.apache.nifi.web.api.dto.ConnectorDTO;
import org.apache.nifi.web.api.dto.ConnectorValueReferenceDTO;
import org.apache.nifi.web.api.dto.PropertyGroupConfigurationDTO;
import org.apache.nifi.web.dao.ConnectorDAO;
@@ -78,6 +79,14 @@ public class StandardConnectorDAO implements ConnectorDAO {
return flowController.getConnectorRepository().getAssetRepository();
}
+ @Override
+ public void verifyCreate(final ConnectorDTO connectorDTO) {
+ final String id = connectorDTO.getId();
+ if (id != null && hasConnector(id)) {
+ throw new IllegalStateException("A Connector already exists with
ID %s".formatted(id));
+ }
+ }
+
@Override
public boolean hasConnector(final String id) {
return getConnectorRepository().getConnector(id) != null;
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
index 60702b8b23..9ec1afb42c 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
@@ -544,4 +544,89 @@ public class TestConnectorResource {
entity.setProcessGroupFlow(flowDTO);
return entity;
}
+
+ @Test
+ public void testCreateConnectorWithValidClientSpecifiedUuid() {
+ final String uppercaseUuid = "A1B2C3D4-E5F6-7890-ABCD-EF1234567890";
+ final String normalizedUuid = uppercaseUuid.toLowerCase();
+
+ final ConnectorEntity requestEntity = createConnectorEntity();
+ requestEntity.getComponent().setId(uppercaseUuid);
+ requestEntity.getComponent().setType(CONNECTOR_TYPE);
+ requestEntity.getRevision().setVersion(0L);
+
+ final ConnectorEntity responseEntity = createConnectorEntity();
+ responseEntity.getComponent().setId(normalizedUuid);
+
+ when(serviceFacade.createConnector(any(Revision.class),
any(ConnectorDTO.class))).thenReturn(responseEntity);
+
+ try (Response response =
connectorResource.createConnector(requestEntity)) {
+ assertEquals(201, response.getStatus());
+ final ConnectorEntity entity = (ConnectorEntity)
response.getEntity();
+ assertEquals(normalizedUuid, entity.getComponent().getId());
+ }
+
+ verify(serviceFacade).verifyCreateConnector(any(ConnectorDTO.class));
+ verify(serviceFacade).createConnector(any(Revision.class),
any(ConnectorDTO.class));
+ }
+
+ @Test
+ public void testCreateConnectorWithInvalidClientSpecifiedUuid() {
+ final String invalidId = "not-a-valid-uuid";
+
+ final ConnectorEntity requestEntity = createConnectorEntity();
+ requestEntity.getComponent().setId(invalidId);
+ requestEntity.getComponent().setType(CONNECTOR_TYPE);
+ requestEntity.getRevision().setVersion(0L);
+
+ final IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class, () ->
+ connectorResource.createConnector(requestEntity));
+
+ assertEquals("ID [" + invalidId + "] is not a valid UUID.",
exception.getMessage());
+
+ verify(serviceFacade, never()).createConnector(any(Revision.class),
any(ConnectorDTO.class));
+ }
+
+ @Test
+ public void testCreateConnectorWithNullEntity() {
+ assertThrows(IllegalArgumentException.class, () ->
+ connectorResource.createConnector(null));
+
+ verify(serviceFacade, never()).createConnector(any(Revision.class),
any(ConnectorDTO.class));
+ }
+
+ @Test
+ public void testCreateConnectorWithNullComponent() {
+ final ConnectorEntity requestEntity = new ConnectorEntity();
+ requestEntity.setComponent(null);
+
+ assertThrows(IllegalArgumentException.class, () ->
+ connectorResource.createConnector(requestEntity));
+
+ verify(serviceFacade, never()).createConnector(any(Revision.class),
any(ConnectorDTO.class));
+ }
+
+ @Test
+ public void testCreateConnectorWithInvalidRevision() {
+ final ConnectorEntity requestEntity = createConnectorEntity();
+ requestEntity.getComponent().setType(CONNECTOR_TYPE);
+ requestEntity.getRevision().setVersion(1L);
+
+ assertThrows(IllegalArgumentException.class, () ->
+ connectorResource.createConnector(requestEntity));
+
+ verify(serviceFacade, never()).createConnector(any(Revision.class),
any(ConnectorDTO.class));
+ }
+
+ @Test
+ public void testCreateConnectorWithBlankType() {
+ final ConnectorEntity requestEntity = createConnectorEntity();
+ requestEntity.getComponent().setType("");
+ requestEntity.getRevision().setVersion(0L);
+
+ assertThrows(IllegalArgumentException.class, () ->
+ connectorResource.createConnector(requestEntity));
+
+ verify(serviceFacade, never()).createConnector(any(Revision.class),
any(ConnectorDTO.class));
+ }
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardConnectorDAOTest.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardConnectorDAOTest.java
index 3f13d8f569..f18c011b96 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardConnectorDAOTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/dao/impl/StandardConnectorDAOTest.java
@@ -28,6 +28,7 @@ import
org.apache.nifi.components.connector.MutableConnectorConfigurationContext
import org.apache.nifi.controller.FlowController;
import org.apache.nifi.web.NiFiCoreException;
import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.api.dto.ConnectorDTO;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -269,5 +270,43 @@ class StandardConnectorDAOTest {
verify(connectorRepository).removeConnector(CONNECTOR_ID);
verify(connectorAssetRepository, never()).deleteAssets(any());
}
+
+ @Test
+ void testVerifyCreateWithExistingConnectorId() {
+ final ConnectorDTO connectorDTO = new ConnectorDTO();
+ connectorDTO.setId(CONNECTOR_ID);
+ connectorDTO.setType("org.apache.nifi.connector.TestConnector");
+
+
when(connectorRepository.getConnector(CONNECTOR_ID)).thenReturn(connectorNode);
+
+ final IllegalStateException exception =
assertThrows(IllegalStateException.class, () ->
+ connectorDAO.verifyCreate(connectorDTO)
+ );
+
+ assertEquals("A Connector already exists with ID
%s".formatted(CONNECTOR_ID), exception.getMessage());
+ }
+
+ @Test
+ void testVerifyCreateWithNewId() {
+ final ConnectorDTO connectorDTO = new ConnectorDTO();
+ connectorDTO.setId(CONNECTOR_ID);
+
+ when(connectorRepository.getConnector(CONNECTOR_ID)).thenReturn(null);
+
+ connectorDAO.verifyCreate(connectorDTO);
+
+ verify(connectorRepository).getConnector(CONNECTOR_ID);
+ }
+
+ @Test
+ void testVerifyCreateWithNullId() {
+ final ConnectorDTO connectorDTO = new ConnectorDTO();
+ connectorDTO.setId(null);
+
+ connectorDAO.verifyCreate(connectorDTO);
+
+ verify(connectorRepository, never()).getConnector(any());
+ }
+
}