This is an automated email from the ASF dual-hosted git repository.
exceptionfactory 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 67ec0bb9dc NIFI-14412 Added Flow Action Reporter Interface to
Framework API (#9837)
67ec0bb9dc is described below
commit 67ec0bb9dc542ed383471f7d7270c6129f6362d2
Author: arturchyzy <[email protected]>
AuthorDate: Mon Apr 14 19:09:56 2025 +0200
NIFI-14412 Added Flow Action Reporter Interface to Framework API (#9837)
Co-authored-by: David Handermann <[email protected]>
Signed-off-by: David Handermann <[email protected]>
---
.../java/org/apache/nifi/action/FlowAction.java | 30 +++++++
.../apache/nifi/action/FlowActionAttribute.java | 54 +++++++++++++
.../org/apache/nifi/action/FlowActionReporter.java | 48 +++++++++++
.../FlowActionReporterConfigurationContext.java | 38 +++++++++
.../FlowActionReporterCreationException.java | 32 ++++++++
.../apache/nifi/admin/action/ActionConverter.java | 34 ++++++++
.../admin/action/ActionToFlowActionConverter.java | 93 ++++++++++++++++++++++
.../nifi/admin/action/StandardFlowAction.java | 32 ++++++++
.../admin/service/EntityStoreAuditService.java | 24 +++++-
.../admin/service/EntityStoreAuditServiceTest.java | 37 ++++++++-
...dardFlowActionReporterConfigurationContext.java | 44 ++++++++++
.../configuration/FlowControllerConfiguration.java | 30 +++++++
.../nar/StandardExtensionDiscoveringManager.java | 2 +
.../apache/nifi/web/NiFiWebApiConfiguration.java | 18 +++--
14 files changed, 505 insertions(+), 11 deletions(-)
diff --git
a/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowAction.java
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowAction.java
new file mode 100644
index 0000000000..4344e07644
--- /dev/null
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowAction.java
@@ -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.
+ */
+package org.apache.nifi.action;
+
+import java.util.Map;
+
+/**
+ * An interface that represents an action that can be taken on a flow. Please
check {@link FlowActionAttributes} for the common names of the attributes that
can be used in the action.
+ */
+public interface FlowAction {
+ /**
+ * Return the action attributes
+ * @return the action attributes
+ */
+ Map<String, String> getAttributes();
+}
diff --git
a/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionAttribute.java
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionAttribute.java
new file mode 100644
index 0000000000..b74a035920
--- /dev/null
+++
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionAttribute.java
@@ -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.
+ */
+package org.apache.nifi.action;
+
+/**
+ * Flow Action attributes for consistent naming
+ */
+public enum FlowActionAttribute {
+
+ ACTION_ID("action.id"),
+ ACTION_TIMESTAMP("action.timestamp"),
+ ACTION_USER_IDENTITY("action.userIdentity"),
+ ACTION_SOURCE_ID("action.sourceId"),
+ ACTION_SOURCE_TYPE("action.sourceType"),
+ ACTION_OPERATION("action.operation"),
+
+ ACTION_DETAILS_NAME("actionDetails.name"),
+ ACTION_DETAILS_SOURCE_ID("actionDetails.sourceId"),
+ ACTION_DETAILS_SOURCE_TYPE("actionDetails.sourceType"),
+ ACTION_DETAILS_DESTINATION_ID("actionDetails.destinationId"),
+ ACTION_DETAILS_DESTINATION_TYPE("actionDetails.destinationType"),
+ ACTION_DETAILS_RELATIONSHIP("actionDetails.relationship"),
+ ACTION_DETAILS_GROUP_ID("actionDetails.groupId"),
+ ACTION_DETAILS_PREVIOUS_GROUP_ID("actionDetails.previousGroupId"),
+ ACTION_DETAILS_END_DATE("actionDetails.endDate"),
+
+ COMPONENT_DETAILS_TYPE("componentDetails.type"),
+ COMPONENT_DETAILS_URI("componentDetails.uri");
+
+ private final String key;
+
+ FlowActionAttribute(String key) {
+ this.key = key;
+ }
+
+ public String key() {
+ return key;
+ }
+
+}
diff --git
a/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporter.java
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporter.java
new file mode 100644
index 0000000000..d650202026
--- /dev/null
+++
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporter.java
@@ -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.
+ */
+package org.apache.nifi.action;
+
+import java.io.Closeable;
+import java.util.Collection;
+
+/**
+ * A {@link FlowActionReporter} is responsible for reporting {@link
FlowAction}s.
+ * Provides {@link FlowActionReporterConfigurationContext} to allow for
configuration and initialization.
+ * Uses {@link #close()} to allow for cleanup.
+ */
+public interface FlowActionReporter extends Closeable {
+ /**
+ * Initialization method for the reporter. This method is called just
after reporter is created.
+ * @param context reporter configuration context
+ * @throws FlowActionReporterCreationException if case of any error during
initialization
+ */
+ default void onConfigured(FlowActionReporterConfigurationContext context)
throws FlowActionReporterCreationException {
+ }
+
+ /**
+ * Reports a collection of {@link FlowAction}s.
+ * @param actions the collection of {@link FlowAction}s to report
+ */
+ void reportFlowActions(Collection<FlowAction> actions);
+
+ /**
+ * Close method for releasing resources when shutting down the
application. This method is called just before the reporter is destroyed.
+ */
+ @Override
+ default void close() {
+ }
+}
diff --git
a/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporterConfigurationContext.java
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporterConfigurationContext.java
new file mode 100644
index 0000000000..832d15e85b
--- /dev/null
+++
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporterConfigurationContext.java
@@ -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.
+ */
+package org.apache.nifi.action;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509TrustManager;
+import java.util.Optional;
+
+/**
+ * A context that will be passed to the reporter in order to obtain
configuration.
+ */
+public interface FlowActionReporterConfigurationContext {
+ /**
+ * Retrieves SSLContext if configured in application properties
+ * @return SSLContext
+ */
+ Optional<SSLContext> getSSLContext();
+
+ /**
+ * Retrieves the trust manager if configured in application properties
+ * @return X509TrustManager
+ */
+ Optional<X509TrustManager> getTrustManager();
+}
diff --git
a/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporterCreationException.java
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporterCreationException.java
new file mode 100644
index 0000000000..3bf2aa7f2c
--- /dev/null
+++
b/nifi-framework-api/src/main/java/org/apache/nifi/action/FlowActionReporterCreationException.java
@@ -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.
+ */
+package org.apache.nifi.action;
+
+/**
+ * An exception that will be thrown if a reporter can not be created.
+ */
+public class FlowActionReporterCreationException extends RuntimeException {
+
+ public FlowActionReporterCreationException(String message) {
+ super(message);
+ }
+
+ public FlowActionReporterCreationException(String message, Throwable
cause) {
+ super(message, cause);
+ }
+
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/ActionConverter.java
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/ActionConverter.java
new file mode 100644
index 0000000000..bae3be4573
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/ActionConverter.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.admin.action;
+
+import org.apache.nifi.action.Action;
+import org.apache.nifi.action.FlowAction;
+
+/**
+ * Converter for converting an action to a flow action. Used in the reporting
flow actions process.
+ */
+@FunctionalInterface
+public interface ActionConverter {
+ /**
+ * Convert Action to Flow Action with attributes
+ *
+ * @param action Action to be converted
+ * @return Flow Action
+ */
+ FlowAction convert(Action action);
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/ActionToFlowActionConverter.java
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/ActionToFlowActionConverter.java
new file mode 100644
index 0000000000..ab5e12e1cd
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/ActionToFlowActionConverter.java
@@ -0,0 +1,93 @@
+/*
+ * 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.admin.action;
+
+import org.apache.nifi.action.Action;
+import org.apache.nifi.action.FlowAction;
+import org.apache.nifi.action.FlowActionAttribute;
+import org.apache.nifi.action.component.details.ComponentDetails;
+import org.apache.nifi.action.component.details.ExtensionDetails;
+import org.apache.nifi.action.component.details.RemoteProcessGroupDetails;
+import org.apache.nifi.action.details.ActionDetails;
+import org.apache.nifi.action.details.ConfigureDetails;
+import org.apache.nifi.action.details.ConnectDetails;
+import org.apache.nifi.action.details.MoveDetails;
+import org.apache.nifi.action.details.PurgeDetails;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Converts an {@link Action} to a {@link FlowAction} using {@link
FlowActionAttribute} attributes.
+ */
+public class ActionToFlowActionConverter implements ActionConverter {
+
+ @Override
+ public FlowAction convert(final Action action) {
+ final Map<String, String> attributes = new HashMap<>();
+ populateActionAttributes(action, attributes);
+ populateActionDetailsAttributes(action.getActionDetails(), attributes);
+ populateComponentDetailsProperties(action.getComponentDetails(),
attributes);
+ return new StandardFlowAction(attributes);
+ }
+
+ private void populateActionAttributes(final Action action, final
Map<String, String> attributes) {
+ attributes.put(FlowActionAttribute.ACTION_ID.key(),
String.valueOf(action.getId()));
+ attributes.put(FlowActionAttribute.ACTION_TIMESTAMP.key(),
action.getTimestamp().toInstant().toString());
+ attributes.put(FlowActionAttribute.ACTION_USER_IDENTITY.key(),
action.getUserIdentity());
+ attributes.put(FlowActionAttribute.ACTION_SOURCE_ID.key(),
action.getSourceId());
+ attributes.put(FlowActionAttribute.ACTION_SOURCE_TYPE.key(),
action.getSourceType().name());
+ attributes.put(FlowActionAttribute.ACTION_OPERATION.key(),
action.getOperation().name());
+ }
+
+ private void populateActionDetailsAttributes(final ActionDetails
actionDetails, final Map<String, String> attributes) {
+ switch (actionDetails) {
+ case ConfigureDetails configureDetails -> attributes.put(
+ FlowActionAttribute.ACTION_DETAILS_NAME.key(),
configureDetails.getName()
+ );
+ case ConnectDetails connectDetails -> {
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_SOURCE_ID.key(),
connectDetails.getSourceId());
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_SOURCE_TYPE.key(),
connectDetails.getSourceType().name());
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_DESTINATION_ID.key(),
connectDetails.getDestinationId());
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_DESTINATION_TYPE.key(),
connectDetails.getDestinationType().name());
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_RELATIONSHIP.key(),
connectDetails.getRelationship());
+ }
+ case MoveDetails moveDetails -> {
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_GROUP_ID.key(),
moveDetails.getGroupId());
+
attributes.put(FlowActionAttribute.ACTION_DETAILS_PREVIOUS_GROUP_ID.key(),
moveDetails.getPreviousGroupId());
+ }
+ case PurgeDetails purgeDetails -> attributes.put(
+ FlowActionAttribute.ACTION_DETAILS_END_DATE.key(),
purgeDetails.getEndDate().toInstant().toString()
+ );
+ case null, default -> {
+ }
+ }
+ }
+
+ private void populateComponentDetailsProperties(final ComponentDetails
componentDetails, final Map<String, String> attributes) {
+ switch (componentDetails) {
+ case ExtensionDetails extensionDetails -> attributes.put(
+ FlowActionAttribute.COMPONENT_DETAILS_TYPE.key(),
extensionDetails.getType()
+ );
+ case RemoteProcessGroupDetails remoteProcessGroupDetails ->
attributes.put(
+ FlowActionAttribute.COMPONENT_DETAILS_URI.key(),
remoteProcessGroupDetails.getUri()
+ );
+ case null, default -> {
+ }
+ }
+ }
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/StandardFlowAction.java
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/StandardFlowAction.java
new file mode 100644
index 0000000000..86f635d188
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/action/StandardFlowAction.java
@@ -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.
+ */
+package org.apache.nifi.admin.action;
+
+import org.apache.nifi.action.FlowAction;
+
+import java.util.Map;
+
+/**
+ * A standard implementation of the {@link FlowAction} interface allowing to
store {@link String} key and values.
+ */
+public record StandardFlowAction(Map<String, String> attributes) implements
FlowAction {
+
+ @Override
+ public Map<String, String> getAttributes() {
+ return Map.copyOf(attributes);
+ }
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/EntityStoreAuditService.java
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/EntityStoreAuditService.java
index 1152ddc40a..04929025da 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/EntityStoreAuditService.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/admin/service/EntityStoreAuditService.java
@@ -16,6 +16,7 @@
*/
package org.apache.nifi.admin.service;
+import jakarta.annotation.Nullable;
import jetbrains.exodus.entitystore.Entity;
import jetbrains.exodus.entitystore.EntityId;
import jetbrains.exodus.entitystore.EntityIterable;
@@ -27,6 +28,7 @@ import jetbrains.exodus.env.EnvironmentConfig;
import jetbrains.exodus.env.Environments;
import org.apache.nifi.action.Action;
import org.apache.nifi.action.Component;
+import org.apache.nifi.action.FlowActionReporter;
import org.apache.nifi.action.FlowChangeAction;
import org.apache.nifi.action.Operation;
import org.apache.nifi.action.component.details.ComponentDetails;
@@ -43,6 +45,7 @@ import org.apache.nifi.action.details.FlowChangeMoveDetails;
import org.apache.nifi.action.details.FlowChangePurgeDetails;
import org.apache.nifi.action.details.MoveDetails;
import org.apache.nifi.action.details.PurgeDetails;
+import org.apache.nifi.admin.action.ActionConverter;
import org.apache.nifi.admin.service.entity.ActionEntity;
import org.apache.nifi.admin.service.entity.ActionLink;
import org.apache.nifi.admin.service.entity.ConfigureDetailsEntity;
@@ -93,15 +96,24 @@ public class EntityStoreAuditService implements
AuditService, Closeable {
private final Environment environment;
+ private final ActionConverter actionConverter;
+
+ @Nullable
+ private final FlowActionReporter flowActionReporter;
+
/**
* Entity Store Audit Service constructor with required properties for
persistent location
*
- * @param directory Persistent Entity Store directory
+ * @param directory Persistent Entity Store directory
+ * @param flowActionReporter Flow Action Reporter
+ * @param actionConverter Action Converter
*/
- public EntityStoreAuditService(final File directory) {
+ public EntityStoreAuditService(final File directory, final ActionConverter
actionConverter, @Nullable final FlowActionReporter flowActionReporter) {
environment = loadEnvironment(directory);
entityStore = PersistentEntityStores.newInstance(environment);
logger.info("Environment configured with directory [{}]", directory);
+ this.actionConverter = actionConverter;
+ this.flowActionReporter = flowActionReporter;
}
/**
@@ -119,6 +131,14 @@ public class EntityStoreAuditService implements
AuditService, Closeable {
}
logger.debug("Actions added [{}]", actions.size());
});
+ if (flowActionReporter != null) {
+ flowActionReporter.reportFlowActions(
+ actions.stream()
+ .map(actionConverter::convert)
+ .toList()
+ );
+ }
+
}
/**
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/test/java/org/apache/nifi/admin/service/EntityStoreAuditServiceTest.java
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/test/java/org/apache/nifi/admin/service/EntityStoreAuditServiceTest.java
index 203271e090..da1018a70a 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-administration/src/test/java/org/apache/nifi/admin/service/EntityStoreAuditServiceTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-administration/src/test/java/org/apache/nifi/admin/service/EntityStoreAuditServiceTest.java
@@ -18,6 +18,8 @@ package org.apache.nifi.admin.service;
import org.apache.nifi.action.Action;
import org.apache.nifi.action.Component;
+import org.apache.nifi.action.FlowAction;
+import org.apache.nifi.action.FlowActionReporter;
import org.apache.nifi.action.FlowChangeAction;
import org.apache.nifi.action.Operation;
import org.apache.nifi.action.details.ActionDetails;
@@ -26,6 +28,7 @@ import
org.apache.nifi.action.details.FlowChangeConfigureDetails;
import org.apache.nifi.action.details.FlowChangeConnectDetails;
import org.apache.nifi.action.details.FlowChangePurgeDetails;
import org.apache.nifi.action.details.PurgeDetails;
+import org.apache.nifi.admin.action.ActionConverter;
import org.apache.nifi.history.History;
import org.apache.nifi.history.HistoryQuery;
import org.apache.nifi.history.PreviousValue;
@@ -40,6 +43,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -103,14 +107,18 @@ class EntityStoreAuditServiceTest {
private static final String SORT_ASCENDING = "ASC";
+ private static final ActionConverter actionConverter = action ->
(FlowAction) Map::of;
+
@TempDir
File directory;
private EntityStoreAuditService service;
+ InMemoryFlowActionReporter flowActionReporter = new
InMemoryFlowActionReporter();
+
@BeforeEach
void setService() {
- service = new EntityStoreAuditService(directory);
+ service = new EntityStoreAuditService(directory, actionConverter,
flowActionReporter);
}
@AfterEach
@@ -133,7 +141,7 @@ class EntityStoreAuditServiceTest {
}
// Create Service with corrupted directory
- service = new EntityStoreAuditService(directory);
+ service = new EntityStoreAuditService(directory, actionConverter,
flowActionReporter);
final Action action = newAction();
final Collection<Action> actions = Collections.singletonList(action);
service.addActions(actions);
@@ -237,7 +245,7 @@ class EntityStoreAuditServiceTest {
final History actionsHistory = service.getActions(historyQuery);
assertNotNull(actionsHistory);
- assertEquals(actionsHistory.getTotal(), 1);
+ assertEquals(1, actionsHistory.getTotal());
assertNotNull(actionsHistory.getLastRefreshed());
final Collection<Action> actionsFound = actionsHistory.getActions();
@@ -460,6 +468,29 @@ class EntityStoreAuditServiceTest {
assertConnectDetailsFound(connectDetails, actionDetails);
}
+ @Test
+ void shouldReportActions() {
+ final List<Action> actions = new ArrayList<>();
+ actions.add(newAction());
+
+ service.addActions(actions);
+
+ assertEquals(1, flowActionReporter.getReportedActions().size());
+ }
+
+ private static class InMemoryFlowActionReporter implements
FlowActionReporter {
+ List<FlowAction> reportedActions = new ArrayList<>();
+
+ @Override
+ public void reportFlowActions(final Collection<FlowAction> actions) {
+ reportedActions.addAll(actions);
+ }
+
+ List<FlowAction> getReportedActions() {
+ return reportedActions;
+ }
+ }
+
private FlowChangeAction newAction() {
final FlowChangeAction action = new FlowChangeAction();
action.setTimestamp(ACTION_TIMESTAMP);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/action/StandardFlowActionReporterConfigurationContext.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/action/StandardFlowActionReporterConfigurationContext.java
new file mode 100644
index 0000000000..74dc2479dd
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/action/StandardFlowActionReporterConfigurationContext.java
@@ -0,0 +1,44 @@
+/*
+ * 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.action;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.X509TrustManager;
+import java.util.Optional;
+
+/**
+ * A context object that provides the configuration for a FlowActionReporter.
+ */
+public class StandardFlowActionReporterConfigurationContext implements
FlowActionReporterConfigurationContext {
+ private final SSLContext sslContext;
+ private final X509TrustManager trustManager;
+
+ public StandardFlowActionReporterConfigurationContext(final SSLContext
sslContext, final X509TrustManager trustManager) {
+ this.sslContext = sslContext;
+ this.trustManager = trustManager;
+ }
+
+ @Override
+ public Optional<SSLContext> getSSLContext() {
+ return Optional.ofNullable(sslContext);
+ }
+
+ @Override
+ public Optional<X509TrustManager> getTrustManager() {
+ return Optional.ofNullable(trustManager);
+ }
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/FlowControllerConfiguration.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/FlowControllerConfiguration.java
index abc8509a8f..1d3d6c6e13 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/FlowControllerConfiguration.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/framework/configuration/FlowControllerConfiguration.java
@@ -16,6 +16,9 @@
*/
package org.apache.nifi.framework.configuration;
+import org.apache.nifi.action.FlowActionReporter;
+import org.apache.nifi.action.FlowActionReporterConfigurationContext;
+import org.apache.nifi.action.StandardFlowActionReporterConfigurationContext;
import org.apache.nifi.admin.service.AuditService;
import org.apache.nifi.asset.AssetComponentManager;
import org.apache.nifi.asset.AssetManager;
@@ -83,6 +86,8 @@ import java.util.concurrent.TimeUnit;
@Configuration
public class FlowControllerConfiguration {
+ private static final String FLOW_ACTION_REPORTER_IMPLEMENTATION =
"nifi.flow.action.reporter.implementation";
+
private NiFiProperties properties;
private ExtensionDiscoveringManager extensionManager;
@@ -471,4 +476,29 @@ public class FlowControllerConfiguration {
public AssetComponentManager affectedComponentManager() throws Exception {
return new StandardAssetComponentManager(flowController());
}
+
+ /**
+ * Flow Action Reporter configured from NiFi Application Properties
+ *
+ * @return Flow Action Reporter
+ */
+ @Bean
+ public FlowActionReporter flowActionReporter() {
+ final FlowActionReporter flowActionReporter;
+
+ final String configuredClassName =
properties.getProperty(FLOW_ACTION_REPORTER_IMPLEMENTATION);
+ if (configuredClassName == null || configuredClassName.isBlank()) {
+ flowActionReporter = null;
+ } else {
+ try {
+ flowActionReporter =
NarThreadContextClassLoader.createInstance(extensionManager,
configuredClassName, FlowActionReporter.class, properties);
+ final FlowActionReporterConfigurationContext
configurationContext = new
StandardFlowActionReporterConfigurationContext(sslContext, trustManager);
+ flowActionReporter.onConfigured(configurationContext);
+ } catch (final Exception e) {
+ throw new IllegalStateException("Failed to create
FlowActionReporter with class [%s]".formatted(configuredClassName), e);
+ }
+ }
+
+ return flowActionReporter;
+ }
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
index 735716640b..6e9a6293d2 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/nar/StandardExtensionDiscoveringManager.java
@@ -16,6 +16,7 @@
*/
package org.apache.nifi.nar;
+import org.apache.nifi.action.FlowActionReporter;
import org.apache.nifi.annotation.behavior.RequiresInstanceClassLoading;
import org.apache.nifi.asset.AssetManager;
import org.apache.nifi.authentication.LoginIdentityProvider;
@@ -132,6 +133,7 @@ public class StandardExtensionDiscoveringManager implements
ExtensionDiscovering
definitionMap.put(PythonBridge.class, new HashSet<>());
definitionMap.put(NarPersistenceProvider.class, new HashSet<>());
definitionMap.put(AssetManager.class, new HashSet<>());
+ definitionMap.put(FlowActionReporter.class, new HashSet<>());
additionalExtensionTypes.forEach(type ->
definitionMap.putIfAbsent(type, new HashSet<>()));
}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
index d5c8bb9376..daa6429a93 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
@@ -16,6 +16,10 @@
*/
package org.apache.nifi.web;
+import jakarta.annotation.Nullable;
+import org.apache.nifi.admin.action.ActionConverter;
+import org.apache.nifi.admin.action.ActionToFlowActionConverter;
+import org.apache.nifi.action.FlowActionReporter;
import org.apache.nifi.admin.service.AuditService;
import org.apache.nifi.admin.service.EntityStoreAuditService;
import
org.apache.nifi.framework.configuration.ApplicationPropertiesConfiguration;
@@ -36,9 +40,9 @@ import java.net.URISyntaxException;
* Web Application Spring Configuration
*/
@ComponentScan(basePackageClasses = {
- ApplicationPropertiesConfiguration.class,
- WebSecurityConfiguration.class,
- WebApplicationConfiguration.class
+ ApplicationPropertiesConfiguration.class,
+ WebSecurityConfiguration.class,
+ WebApplicationConfiguration.class
})
@Configuration
public class NiFiWebApiConfiguration {
@@ -67,13 +71,15 @@ public class NiFiWebApiConfiguration {
/**
* Audit Service implementation from nifi-administration
*
- * @param properties NiFi Properties
+ * @param properties NiFi Properties
+ * @param flowActionReporter Flow Action Reporter can be null
* @return Audit Service implementation using Persistent Entity Store
*/
@Bean
- public AuditService auditService(final NiFiProperties properties) {
+ public AuditService auditService(final NiFiProperties properties,
@Nullable final FlowActionReporter flowActionReporter) {
final File databaseDirectory =
properties.getDatabaseRepositoryPath().toFile();
- return new EntityStoreAuditService(databaseDirectory);
+ final ActionConverter actionConverter = new
ActionToFlowActionConverter();
+ return new EntityStoreAuditService(databaseDirectory, actionConverter,
flowActionReporter);
}
@Bean