From aabd4a25d2cb8b2a6108be6c16315acee08ee712 Mon Sep 17 00:00:00 2001
From: Bryan Bende
Date: Mon, 12 Jun 2017 15:53:20 -0400
Subject: [PATCH] NIFI-4043 Initial commit of nifi-redis-bundle
NIFI-4061 Initial version of RedisStateProvider
- Adding PropertyContext and updating existing contexts to extend it
- Added embedded Redis for unit testing
- Added wrapped StateProvider with NAR ClassLoader in StandardStateManagerProvider
- Updating state-management.xml with config for RedisStateProvider
- Renaming tests that use RedisServer to be IT tests so they don't run all the time
This closes #1918.
---
.../nifi/components/ValidationContext.java | 10 +-
.../apache/nifi/context/PropertyContext.java | 41 ++
.../controller/AbstractControllerService.java | 18 +-
.../nifi/controller/ConfigurationContext.java | 14 +-
.../apache/nifi/processor/ProcessContext.java | 12 +-
.../nifi/reporting/ReportingContext.java | 11 +-
nifi-assembly/pom.xml | 10 +
.../bootstrap/NotificationServiceManager.java | 6 +
.../NotificationInitializationContext.java | 14 +-
.../NotificationValidationContext.java | 10 +
.../StateProviderInitializationContext.java | 12 +-
.../nifi/util/MockConfigurationContext.java | 10 +
.../apache/nifi/util/MockProcessContext.java | 9 +
.../nifi/util/MockReportingContext.java | 10 +
.../nifi/util/MockValidationContext.java | 10 +
.../reporting/StandardReportingContext.java | 10 +
.../scheduling/ConnectableProcessContext.java | 5 +
.../service/StandardConfigurationContext.java | 10 +
...ardStateProviderInitializationContext.java | 10 +
.../manager/StandardStateManagerProvider.java | 127 +++++-
.../processor/StandardProcessContext.java | 10 +
.../processor/StandardSchedulingContext.java | 10 +
.../processor/StandardValidationContext.java | 10 +
.../controller/TestStandardProcessorNode.java | 10 +
.../TestWriteAheadLocalStateProvider.java | 10 +
.../zookeeper/TestZooKeeperStateProvider.java | 10 +
.../nifi/mock/MockConfigurationContext.java | 5 +
.../apache/nifi/mock/MockProcessContext.java | 5 +
.../main/resources/conf/state-management.xml | 68 +++
.../nifi-redis-extensions/pom.xml | 89 ++++
.../service/RedisConnectionPoolService.java | 93 ++++
...RedisDistributedMapCacheClientService.java | 327 +++++++++++++
.../nifi/redis/state/RedisStateMap.java | 100 ++++
.../redis/state/RedisStateMapJsonSerDe.java | 85 ++++
.../nifi/redis/state/RedisStateMapSerDe.java | 44 ++
.../nifi/redis/state/RedisStateProvider.java | 299 ++++++++++++
.../apache/nifi/redis/util/RedisAction.java | 30 ++
.../apache/nifi/redis/util/RedisUtils.java | 428 ++++++++++++++++++
...apache.nifi.components.state.StateProvider | 15 +
...g.apache.nifi.controller.ControllerService | 16 +
.../redis/service/FakeRedisProcessor.java | 53 +++
...RedisDistributedMapCacheClientService.java | 264 +++++++++++
.../TestRedisConnectionPoolService.java | 95 ++++
.../redis/state/ITRedisStateProvider.java | 318 +++++++++++++
.../state/TestRedisStateMapJsonSerDe.java | 79 ++++
.../nifi-redis-bundle/nifi-redis-nar/pom.xml | 46 ++
.../src/main/resources/META-INF/NOTICE | 32 ++
.../nifi-redis-service-api-nar/pom.xml | 46 ++
.../src/main/resources/META-INF/LICENSE | 239 ++++++++++
.../src/main/resources/META-INF/NOTICE | 33 ++
.../nifi-redis-service-api/pom.xml | 44 ++
.../nifi/redis/RedisConnectionPool.java | 44 ++
.../java/org/apache/nifi/redis/RedisType.java | 56 +++
nifi-nar-bundles/nifi-redis-bundle/pom.xml | 41 ++
.../standard/WaitNotifyProtocol.java | 10 +-
nifi-nar-bundles/pom.xml | 1 +
pom.xml | 12 +
57 files changed, 3372 insertions(+), 64 deletions(-)
create mode 100644 nifi-api/src/main/java/org/apache/nifi/context/PropertyContext.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/pom.xml
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisConnectionPoolService.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisDistributedMapCacheClientService.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/state/RedisStateMap.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/state/RedisStateMapJsonSerDe.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/state/RedisStateMapSerDe.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/state/RedisStateProvider.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/util/RedisAction.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/util/RedisUtils.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/resources/META-INF/services/org.apache.nifi.components.state.StateProvider
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/resources/META-INF/services/org.apache.nifi.controller.ControllerService
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/test/java/org/apache/nifi/redis/service/FakeRedisProcessor.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/test/java/org/apache/nifi/redis/service/ITRedisDistributedMapCacheClientService.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/test/java/org/apache/nifi/redis/service/TestRedisConnectionPoolService.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/test/java/org/apache/nifi/redis/state/ITRedisStateProvider.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/test/java/org/apache/nifi/redis/state/TestRedisStateMapJsonSerDe.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-nar/pom.xml
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-nar/src/main/resources/META-INF/NOTICE
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-service-api-nar/pom.xml
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-service-api-nar/src/main/resources/META-INF/LICENSE
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-service-api-nar/src/main/resources/META-INF/NOTICE
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-service-api/pom.xml
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-service-api/src/main/java/org/apache/nifi/redis/RedisConnectionPool.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/nifi-redis-service-api/src/main/java/org/apache/nifi/redis/RedisType.java
create mode 100644 nifi-nar-bundles/nifi-redis-bundle/pom.xml
diff --git a/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java b/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java
index 66a54fa956..444d1bd62a 100644
--- a/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java
+++ b/nifi-api/src/main/java/org/apache/nifi/components/ValidationContext.java
@@ -18,11 +18,12 @@ package org.apache.nifi.components;
import java.util.Map;
+import org.apache.nifi.context.PropertyContext;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.controller.ControllerServiceLookup;
import org.apache.nifi.expression.ExpressionLanguageCompiler;
-public interface ValidationContext {
+public interface ValidationContext extends PropertyContext {
/**
* @return the {@link ControllerServiceLookup} which can be used to obtain
@@ -43,13 +44,6 @@ public interface ValidationContext {
*/
ExpressionLanguageCompiler newExpressionLanguageCompiler();
- /**
- * @param property being validated
- * @return a PropertyValue that encapsulates the value configured for the
- * given PropertyDescriptor
- */
- PropertyValue getProperty(PropertyDescriptor property);
-
/**
* @param value to make a PropertyValue object for
* @return a PropertyValue that represents the given value
diff --git a/nifi-api/src/main/java/org/apache/nifi/context/PropertyContext.java b/nifi-api/src/main/java/org/apache/nifi/context/PropertyContext.java
new file mode 100644
index 0000000000..2771927b48
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/context/PropertyContext.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.context;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.PropertyValue;
+
+import java.util.Map;
+
+/**
+ * A context for retrieving a PropertyValue from a PropertyDescriptor.
+ */
+public interface PropertyContext {
+
+ /**
+ * Retrieves the current value set for the given descriptor, if a value is
+ * set - else uses the descriptor to determine the appropriate default value
+ *
+ * @param descriptor to lookup the value of
+ * @return the property value of the given descriptor
+ */
+ PropertyValue getProperty(PropertyDescriptor descriptor);
+
+
+ Map getAllProperties();
+
+}
diff --git a/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java b/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java
index 9762f3e7ff..95f0583be0 100644
--- a/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java
+++ b/nifi-api/src/main/java/org/apache/nifi/controller/AbstractControllerService.java
@@ -23,7 +23,6 @@ import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.logging.ComponentLog;
-import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.reporting.InitializationException;
public abstract class AbstractControllerService extends AbstractConfigurableComponent implements ControllerService {
@@ -33,6 +32,7 @@ public abstract class AbstractControllerService extends AbstractConfigurableComp
private ComponentLog logger;
private StateManager stateManager;
private volatile ConfigurationContext configurationContext;
+ private volatile boolean enabled = false;
@Override
public final void initialize(final ControllerServiceInitializationContext context) throws InitializationException {
@@ -50,7 +50,7 @@ public abstract class AbstractControllerService extends AbstractConfigurableComp
/**
* @return the {@link ControllerServiceLookup} that was passed to the
- * {@link #init(ProcessorInitializationContext)} method
+ * {@link #init(ControllerServiceInitializationContext)} method
*/
protected final ControllerServiceLookup getControllerServiceLookup() {
return serviceLookup;
@@ -66,6 +66,20 @@ public abstract class AbstractControllerService extends AbstractConfigurableComp
protected void init(final ControllerServiceInitializationContext config) throws InitializationException {
}
+ @OnEnabled
+ public final void enabled() {
+ this.enabled = true;
+ }
+
+ @OnDisabled
+ public final void disabled() {
+ this.enabled = false;
+ }
+
+ public boolean isEnabled() {
+ return this.enabled;
+ }
+
/**
* @return the logger that has been provided to the component by the
* framework in its initialize method
diff --git a/nifi-api/src/main/java/org/apache/nifi/controller/ConfigurationContext.java b/nifi-api/src/main/java/org/apache/nifi/controller/ConfigurationContext.java
index 03965d4c7d..e6b3cb2613 100644
--- a/nifi-api/src/main/java/org/apache/nifi/controller/ConfigurationContext.java
+++ b/nifi-api/src/main/java/org/apache/nifi/controller/ConfigurationContext.java
@@ -16,23 +16,17 @@
*/
package org.apache.nifi.controller;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.context.PropertyContext;
+
import java.util.Map;
import java.util.concurrent.TimeUnit;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.PropertyValue;
-
/**
* This context is passed to ControllerServices and Reporting Tasks in order
* to expose their configuration to them.
*/
-public interface ConfigurationContext {
-
- /**
- * @param property to retrieve by name
- * @return the configured value for the property with the given name
- */
- PropertyValue getProperty(PropertyDescriptor property);
+public interface ConfigurationContext extends PropertyContext {
/**
* @return an unmodifiable map of all configured properties for this
diff --git a/nifi-api/src/main/java/org/apache/nifi/processor/ProcessContext.java b/nifi-api/src/main/java/org/apache/nifi/processor/ProcessContext.java
index c112e8a697..2bbe06a49f 100644
--- a/nifi-api/src/main/java/org/apache/nifi/processor/ProcessContext.java
+++ b/nifi-api/src/main/java/org/apache/nifi/processor/ProcessContext.java
@@ -22,6 +22,7 @@ import java.util.Set;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.components.state.StateManager;
+import org.apache.nifi.context.PropertyContext;
import org.apache.nifi.controller.ControllerServiceLookup;
/**
@@ -34,16 +35,7 @@ import org.apache.nifi.controller.ControllerServiceLookup;
* thread-safe.
*
*/
-public interface ProcessContext {
-
- /**
- * Retrieves the current value set for the given descriptor, if a value is
- * set - else uses the descriptor to determine the appropriate default value
- *
- * @param descriptor to lookup the value of
- * @return the property value of the given descriptor
- */
- PropertyValue getProperty(PropertyDescriptor descriptor);
+public interface ProcessContext extends PropertyContext {
/**
* Retrieves the current value set for the given descriptor, if a value is
diff --git a/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingContext.java b/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingContext.java
index f1acfe3b25..8b3ad5629d 100644
--- a/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingContext.java
+++ b/nifi-api/src/main/java/org/apache/nifi/reporting/ReportingContext.java
@@ -17,8 +17,8 @@
package org.apache.nifi.reporting;
import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.components.state.StateManager;
+import org.apache.nifi.context.PropertyContext;
import org.apache.nifi.controller.ControllerServiceLookup;
import java.util.Map;
@@ -29,7 +29,7 @@ import java.util.Map;
* statistics, metrics, and monitoring information, as well as configuration
* supplied by the user.
*/
-public interface ReportingContext {
+public interface ReportingContext extends PropertyContext {
/**
* @return a Map of all known {@link PropertyDescriptor}s to their
@@ -39,13 +39,6 @@ public interface ReportingContext {
*/
Map getProperties();
- /**
- * @param propertyName descriptor of property to lookup the value of
- * @return PropertyValue that represents the user-configured value for the given
- * {@link PropertyDescriptor}
- */
- PropertyValue getProperty(PropertyDescriptor propertyName);
-
/**
* @return the {@link EventAccess} object that can be used to obtain
* information about specific events and reports that have happened
diff --git a/nifi-assembly/pom.xml b/nifi-assembly/pom.xml
index bc9992cea0..8f73ec0e45 100755
--- a/nifi-assembly/pom.xml
+++ b/nifi-assembly/pom.xml
@@ -476,6 +476,16 @@
nifi-hwx-schema-registry-nar
nar
+
+ org.apache.nifi
+ nifi-redis-service-api-nar
+ nar
+
+
+ org.apache.nifi
+ nifi-redis-nar
+ nar
+
diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
index 6203a06ec6..6e917512d3 100644
--- a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
+++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
@@ -23,6 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -378,6 +379,11 @@ public class NotificationServiceManager {
return new StandardPropertyValue(value, null, variableRegistry);
}
+ @Override
+ public Map getAllProperties() {
+ return Collections.unmodifiableMap(propertyValues);
+ }
+
@Override
public String getIdentifier() {
return serviceId;
diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationInitializationContext.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationInitializationContext.java
index 88e0445334..e505d0b79a 100644
--- a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationInitializationContext.java
+++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationInitializationContext.java
@@ -17,19 +17,9 @@
package org.apache.nifi.bootstrap.notification;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.context.PropertyContext;
-public interface NotificationInitializationContext {
-
- /**
- * Returns the configured value for the given PropertyDescriptor
- *
- * @param descriptor the property to fetch the value for
- * @return the configured value for the given PropertyDescriptor, or the default value for the PropertyDescriptor
- * if no value has been configured.
- */
- PropertyValue getProperty(PropertyDescriptor descriptor);
+public interface NotificationInitializationContext extends PropertyContext {
/**
* @return the identifier for the NotificationService
diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationValidationContext.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationValidationContext.java
index 99d3b2344e..6d3ef537a6 100644
--- a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationValidationContext.java
+++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationValidationContext.java
@@ -17,6 +17,7 @@
package org.apache.nifi.bootstrap.notification;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -75,6 +76,15 @@ public class NotificationValidationContext implements ValidationContext {
return context.getProperties();
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String getAnnotationData() {
throw new UnsupportedOperationException();
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/components/state/StateProviderInitializationContext.java b/nifi-framework-api/src/main/java/org/apache/nifi/components/state/StateProviderInitializationContext.java
index 418249016e..5b90a1c4ed 100644
--- a/nifi-framework-api/src/main/java/org/apache/nifi/components/state/StateProviderInitializationContext.java
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/components/state/StateProviderInitializationContext.java
@@ -23,13 +23,14 @@ import javax.net.ssl.SSLContext;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyValue;
+import org.apache.nifi.context.PropertyContext;
import org.apache.nifi.logging.ComponentLog;
/**
* This interface defines an initialization context that is passed to a {@link StateProvider} when it
* is initialized.
*/
-public interface StateProviderInitializationContext {
+public interface StateProviderInitializationContext extends PropertyContext {
/**
* @return the identifier if the StateProvider
*/
@@ -40,15 +41,6 @@ public interface StateProviderInitializationContext {
*/
Map getProperties();
- /**
- * Returns the configured value for the given property
- *
- * @param property the property to retrieve the value for
- *
- * @return the configured value for the property.
- */
- PropertyValue getProperty(PropertyDescriptor property);
-
/**
* @return the SSL Context that should be used to communicate with remote resources,
* or null
if no SSLContext has been configured
diff --git a/nifi-mock/src/main/java/org/apache/nifi/util/MockConfigurationContext.java b/nifi-mock/src/main/java/org/apache/nifi/util/MockConfigurationContext.java
index 74b84ad330..91d805e2e8 100644
--- a/nifi-mock/src/main/java/org/apache/nifi/util/MockConfigurationContext.java
+++ b/nifi-mock/src/main/java/org/apache/nifi/util/MockConfigurationContext.java
@@ -17,6 +17,7 @@
package org.apache.nifi.util;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -69,6 +70,15 @@ public class MockConfigurationContext implements ConfigurationContext {
return new HashMap<>(this.properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
private PropertyDescriptor getActualDescriptor(final PropertyDescriptor property) {
if (service == null) {
return property;
diff --git a/nifi-mock/src/main/java/org/apache/nifi/util/MockProcessContext.java b/nifi-mock/src/main/java/org/apache/nifi/util/MockProcessContext.java
index 8cbe1ac50f..8651241e0c 100644
--- a/nifi-mock/src/main/java/org/apache/nifi/util/MockProcessContext.java
+++ b/nifi-mock/src/main/java/org/apache/nifi/util/MockProcessContext.java
@@ -212,6 +212,15 @@ public class MockProcessContext extends MockControllerServiceLookup implements S
}
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
/**
* Validates the current properties, returning ValidationResults for any
* invalid properties. All processor defined properties will be validated.
diff --git a/nifi-mock/src/main/java/org/apache/nifi/util/MockReportingContext.java b/nifi-mock/src/main/java/org/apache/nifi/util/MockReportingContext.java
index 26ad59010e..f65bc3e3a0 100644
--- a/nifi-mock/src/main/java/org/apache/nifi/util/MockReportingContext.java
+++ b/nifi-mock/src/main/java/org/apache/nifi/util/MockReportingContext.java
@@ -19,6 +19,7 @@ package org.apache.nifi.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -58,6 +59,15 @@ public class MockReportingContext extends MockControllerServiceLookup implements
return Collections.unmodifiableMap(properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public PropertyValue getProperty(final PropertyDescriptor property) {
final String configuredValue = properties.get(property);
diff --git a/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java b/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
index fbd2a368bc..564ec54a87 100644
--- a/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
+++ b/nifi-mock/src/main/java/org/apache/nifi/util/MockValidationContext.java
@@ -17,6 +17,7 @@
package org.apache.nifi.util;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -88,6 +89,15 @@ public class MockValidationContext implements ValidationContext, ControllerServi
return context.getProperties();
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String getAnnotationData() {
return context.getAnnotationData();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingContext.java
index 8f8b2314be..62183cc25d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/reporting/StandardReportingContext.java
@@ -40,6 +40,7 @@ import org.apache.nifi.reporting.Severity;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
@@ -107,6 +108,15 @@ public class StandardReportingContext implements ReportingContext, ControllerSer
return Collections.unmodifiableMap(properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public PropertyValue getProperty(final PropertyDescriptor property) {
final String configuredValue = properties.get(property);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/ConnectableProcessContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/ConnectableProcessContext.java
index 0d755b0b46..3116401486 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/ConnectableProcessContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/scheduling/ConnectableProcessContext.java
@@ -194,6 +194,11 @@ public class ConnectableProcessContext implements ProcessContext {
return null;
}
+ @Override
+ public Map getAllProperties() {
+ return new HashMap<>();
+ }
+
@Override
public Map getProperties() {
return new HashMap<>();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardConfigurationContext.java
index 61db8191b5..c188d75adf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardConfigurationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/StandardConfigurationContext.java
@@ -17,6 +17,7 @@
package org.apache.nifi.controller.service;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -81,6 +82,15 @@ public class StandardConfigurationContext implements ConfigurationContext {
return component.getProperties();
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String getSchedulingPeriod() {
return schedulingPeriod;
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/StandardStateProviderInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/StandardStateProviderInitializationContext.java
index d86a120576..ace92c7735 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/StandardStateProviderInitializationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/StandardStateProviderInitializationContext.java
@@ -19,6 +19,7 @@ package org.apache.nifi.controller.state;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import javax.net.ssl.SSLContext;
@@ -46,6 +47,15 @@ public class StandardStateProviderInitializationContext implements StateProvider
return Collections.unmodifiableMap(properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue().getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public PropertyValue getProperty(final PropertyDescriptor property) {
return properties.get(property);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/manager/StandardStateManagerProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/manager/StandardStateManagerProvider.java
index d63ae00b91..b365de25c8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/manager/StandardStateManagerProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/state/manager/StandardStateManagerProvider.java
@@ -38,6 +38,7 @@ import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.state.Scope;
import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.components.state.StateManagerProvider;
+import org.apache.nifi.components.state.StateMap;
import org.apache.nifi.components.state.StateProvider;
import org.apache.nifi.components.state.StateProviderInitializationContext;
import org.apache.nifi.controller.state.ConfigParseException;
@@ -48,6 +49,7 @@ import org.apache.nifi.controller.state.config.StateProviderConfiguration;
import org.apache.nifi.framework.security.util.SslContextFactory;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.NarCloseable;
import org.apache.nifi.processor.SimpleProcessLogger;
import org.apache.nifi.processor.StandardValidationContext;
import org.apache.nifi.registry.VariableRegistry;
@@ -232,7 +234,7 @@ public class StandardStateManagerProvider implements StateManagerProvider{
Thread.currentThread().setContextClassLoader(detectedClassLoaderForType);
final Class extends StateProvider> mgrClass = rawClass.asSubclass(StateProvider.class);
- return mgrClass.newInstance();
+ return withNarClassLoader(mgrClass.newInstance());
} finally {
if (ctxClassLoader != null) {
Thread.currentThread().setContextClassLoader(ctxClassLoader);
@@ -240,6 +242,129 @@ public class StandardStateManagerProvider implements StateManagerProvider{
}
}
+ /**
+ * Wrap the provider so that all method calls set the context class loader to the NAR's class loader before
+ * executing the actual provider.
+ *
+ * @param stateProvider the base provider to wrap
+ * @return the wrapped provider
+ */
+ private static StateProvider withNarClassLoader(final StateProvider stateProvider) {
+ return new StateProvider() {
+ @Override
+ public void initialize(StateProviderInitializationContext context) throws IOException {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.initialize(context);
+ }
+ }
+
+ @Override
+ public void shutdown() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.shutdown();
+ }
+ }
+
+ @Override
+ public void setState(Map state, String componentId) throws IOException {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.setState(state, componentId);
+ }
+ }
+
+ @Override
+ public StateMap getState(String componentId) throws IOException {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.getState(componentId);
+ }
+ }
+
+ @Override
+ public boolean replace(StateMap oldValue, Map newValue, String componentId) throws IOException {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.replace(oldValue, newValue, componentId);
+ }
+ }
+
+ @Override
+ public void clear(String componentId) throws IOException {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.clear(componentId);
+ }
+ }
+
+ @Override
+ public void onComponentRemoved(String componentId) throws IOException {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.onComponentRemoved(componentId);
+ }
+ }
+
+ @Override
+ public void enable() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.enable();
+ }
+ }
+
+ @Override
+ public void disable() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.disable();
+ }
+ }
+
+ @Override
+ public boolean isEnabled() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.isEnabled();
+ }
+ }
+
+ @Override
+ public Scope[] getSupportedScopes() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.getSupportedScopes();
+ }
+ }
+
+ @Override
+ public Collection validate(ValidationContext context) {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.validate(context);
+ }
+ }
+
+ @Override
+ public PropertyDescriptor getPropertyDescriptor(String name) {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.getPropertyDescriptor(name);
+ }
+ }
+
+ @Override
+ public void onPropertyModified(PropertyDescriptor descriptor, String oldValue, String newValue) {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ stateProvider.onPropertyModified(descriptor, oldValue, newValue);
+ }
+ }
+
+ @Override
+ public List getPropertyDescriptors() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.getPropertyDescriptors();
+ }
+ }
+
+ @Override
+ public String getIdentifier() {
+ try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+ return stateProvider.getIdentifier();
+ }
+ }
+ };
+ }
+
/**
* Returns the State Manager that has been created for the given component ID, or null
if none exists
*
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardProcessContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
index 83906e2851..2714392691 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardProcessContext.java
@@ -19,6 +19,7 @@ package org.apache.nifi.processor;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -125,6 +126,15 @@ public class StandardProcessContext implements ProcessContext, ControllerService
return procNode.getProperties();
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String encrypt(final String unencrypted) {
return encryptor.encrypt(unencrypted);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardSchedulingContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardSchedulingContext.java
index 86518b8036..1f5cfeed77 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardSchedulingContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardSchedulingContext.java
@@ -16,6 +16,7 @@
*/
package org.apache.nifi.processor;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -98,6 +99,15 @@ public class StandardSchedulingContext implements SchedulingContext {
return processContext.getProperties();
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String encrypt(final String unencrypted) {
return processContext.encrypt(unencrypted);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardValidationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
index dfc7965aad..662169c570 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/processor/StandardValidationContext.java
@@ -19,6 +19,7 @@ package org.apache.nifi.processor;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -118,6 +119,15 @@ public class StandardValidationContext implements ValidationContext {
return Collections.unmodifiableMap(properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String getAnnotationData() {
return annotationData;
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java
index c248d25788..32b6f539cf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/TestStandardProcessorNode.java
@@ -62,6 +62,7 @@ import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -512,6 +513,15 @@ public class TestStandardProcessorNode {
return Collections.unmodifiableMap(properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public String getAnnotationData() {
return null;
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/local/TestWriteAheadLocalStateProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/local/TestWriteAheadLocalStateProvider.java
index d2e4a0519f..41b7d9d69d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/local/TestWriteAheadLocalStateProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/local/TestWriteAheadLocalStateProvider.java
@@ -20,6 +20,7 @@ package org.apache.nifi.controller.state.providers.local;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
@@ -61,6 +62,15 @@ public class TestWriteAheadLocalStateProvider extends AbstractTestStateProvider
return Collections.unmodifiableMap(properties);
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue().getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public PropertyValue getProperty(final PropertyDescriptor property) {
final PropertyValue prop = properties.get(property);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
index d09ee1f4e7..037b35026d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
@@ -18,6 +18,7 @@ package org.apache.nifi.controller.state.providers.zookeeper;
import java.io.IOException;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import javax.net.ssl.SSLContext;
@@ -75,6 +76,15 @@ public class TestZooKeeperStateProvider extends AbstractTestStateProvider {
return propValueMap;
}
+ @Override
+ public Map getAllProperties() {
+ final Map propValueMap = new LinkedHashMap<>();
+ for (final Map.Entry entry : getProperties().entrySet()) {
+ propValueMap.put(entry.getKey().getName(), entry.getValue().getValue());
+ }
+ return propValueMap;
+ }
+
@Override
public PropertyValue getProperty(final PropertyDescriptor property) {
final String prop = properties.get(property);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
index d1e73fb7e2..d9a1b37888 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockConfigurationContext.java
@@ -31,6 +31,11 @@ public class MockConfigurationContext implements ConfigurationContext {
return null;
}
+ @Override
+ public Map getAllProperties() {
+ return Collections.emptyMap();
+ }
+
@Override
public Map getProperties() {
return Collections.emptyMap();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
index cf2e2cf43c..cb173247fe 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-nar-utils/src/main/java/org/apache/nifi/mock/MockProcessContext.java
@@ -64,6 +64,11 @@ public class MockProcessContext implements ProcessContext {
return Collections.emptyMap();
}
+ @Override
+ public Map getAllProperties() {
+ return Collections.emptyMap();
+ }
+
@Override
public String encrypt(String unencrypted) {
return unencrypted;
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml
index d7631c2261..dcd7ee6c81 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/state-management.xml
@@ -63,4 +63,72 @@
10 seconds
Open
+
+
+
\ No newline at end of file
diff --git a/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/pom.xml b/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/pom.xml
new file mode 100644
index 0000000000..e59220df2f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/pom.xml
@@ -0,0 +1,89 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.nifi
+ nifi-redis-bundle
+ 1.4.0-SNAPSHOT
+
+
+ nifi-redis-extensions
+ jar
+
+
+
+
+ org.apache.nifi
+ nifi-distributed-cache-client-service-api
+ provided
+
+
+ org.apache.nifi
+ nifi-redis-service-api
+ 1.4.0-SNAPSHOT
+ provided
+
+
+ org.springframework.data
+ spring-data-redis
+ ${spring.data.redis.version}
+ provided
+
+
+ redis.clients
+ jedis
+ 2.9.0
+ provided
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.apache.nifi
+ nifi-api
+
+
+ org.apache.nifi
+ nifi-utils
+
+
+
+ org.apache.nifi
+ nifi-mock
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+ junit
+ junit
+ test
+
+
+ com.github.kstyrc
+ embedded-redis
+ 0.6
+ test
+
+
+
diff --git a/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisConnectionPoolService.java b/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisConnectionPoolService.java
new file mode 100644
index 0000000000..68169f9c39
--- /dev/null
+++ b/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisConnectionPoolService.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.redis.service;
+
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnDisabled;
+import org.apache.nifi.annotation.lifecycle.OnEnabled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.context.PropertyContext;
+import org.apache.nifi.controller.AbstractControllerService;
+import org.apache.nifi.controller.ConfigurationContext;
+import org.apache.nifi.redis.RedisConnectionPool;
+import org.apache.nifi.redis.RedisType;
+import org.apache.nifi.redis.util.RedisUtils;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
+
+import java.util.Collection;
+import java.util.List;
+
+@Tags({"redis", "cache"})
+@CapabilityDescription("A service that provides connections to Redis.")
+public class RedisConnectionPoolService extends AbstractControllerService implements RedisConnectionPool {
+
+ private volatile PropertyContext context;
+ private volatile RedisType redisType;
+ private volatile JedisConnectionFactory connectionFactory;
+
+ @Override
+ protected List getSupportedPropertyDescriptors() {
+ return RedisUtils.REDIS_CONNECTION_PROPERTY_DESCRIPTORS;
+ }
+
+ @Override
+ protected Collection customValidate(ValidationContext validationContext) {
+ return RedisUtils.validate(validationContext);
+ }
+
+ @OnEnabled
+ public void onEnabled(final ConfigurationContext context) {
+ this.context = context;
+
+ final String redisMode = context.getProperty(RedisUtils.REDIS_MODE).getValue();
+ this.redisType = RedisType.fromDisplayName(redisMode);
+ }
+
+ @OnDisabled
+ public void onDisabled() {
+ if (connectionFactory != null) {
+ connectionFactory.destroy();
+ connectionFactory = null;
+ redisType = null;
+ context = null;
+ }
+ }
+
+ @Override
+ public RedisType getRedisType() {
+ return redisType;
+ }
+
+ @Override
+ public RedisConnection getConnection() {
+ if (connectionFactory == null) {
+ synchronized (this) {
+ if (connectionFactory == null) {
+ connectionFactory = RedisUtils.createConnectionFactory(context, getLogger());
+ }
+ }
+ }
+
+ return connectionFactory.getConnection();
+ }
+
+
+}
diff --git a/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisDistributedMapCacheClientService.java b/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisDistributedMapCacheClientService.java
new file mode 100644
index 0000000000..94b195c213
--- /dev/null
+++ b/nifi-nar-bundles/nifi-redis-bundle/nifi-redis-extensions/src/main/java/org/apache/nifi/redis/service/RedisDistributedMapCacheClientService.java
@@ -0,0 +1,327 @@
+/*
+ * 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.redis.service;
+
+import org.apache.nifi.annotation.documentation.CapabilityDescription;
+import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.annotation.lifecycle.OnDisabled;
+import org.apache.nifi.annotation.lifecycle.OnEnabled;
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.controller.AbstractControllerService;
+import org.apache.nifi.controller.ConfigurationContext;
+import org.apache.nifi.distributed.cache.client.AtomicCacheEntry;
+import org.apache.nifi.distributed.cache.client.AtomicDistributedMapCacheClient;
+import org.apache.nifi.distributed.cache.client.Deserializer;
+import org.apache.nifi.distributed.cache.client.Serializer;
+import org.apache.nifi.redis.RedisConnectionPool;
+import org.apache.nifi.redis.RedisType;
+import org.apache.nifi.redis.util.RedisAction;
+import org.apache.nifi.util.Tuple;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.Cursor;
+import org.springframework.data.redis.core.ScanOptions;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+@Tags({ "redis", "distributed", "cache", "map" })
+@CapabilityDescription("An implementation of DistributedMapCacheClient that uses Redis as the backing cache. This service relies on " +
+ "the WATCH, MULTI, and EXEC commands in Redis, which are not fully supported when Redis is clustered. As a result, this service " +
+ "can only be used with a Redis Connection Pool that is configured for standalone or sentinel mode. Sentinel mode can be used to " +
+ "provide high-availability configurations.")
+public class RedisDistributedMapCacheClientService extends AbstractControllerService implements AtomicDistributedMapCacheClient {
+
+ public static final PropertyDescriptor REDIS_CONNECTION_POOL = new PropertyDescriptor.Builder()
+ .name("redis-connection-pool")
+ .displayName("Redis Connection Pool")
+ .identifiesControllerService(RedisConnectionPool.class)
+ .required(true)
+ .build();
+
+ static final List PROPERTY_DESCRIPTORS;
+ static {
+ final List props = new ArrayList<>();
+ props.add(REDIS_CONNECTION_POOL);
+ PROPERTY_DESCRIPTORS = Collections.unmodifiableList(props);
+ }
+
+ private volatile RedisConnectionPool redisConnectionPool;
+
+ @Override
+ protected List getSupportedPropertyDescriptors() {
+ return PROPERTY_DESCRIPTORS;
+ }
+
+ @Override
+ protected Collection customValidate(ValidationContext validationContext) {
+ final List results = new ArrayList<>();
+
+ final RedisConnectionPool redisConnectionPool = validationContext.getProperty(REDIS_CONNECTION_POOL).asControllerService(RedisConnectionPool.class);
+ if (redisConnectionPool != null) {
+ final RedisType redisType = redisConnectionPool.getRedisType();
+ if (redisType != null && redisType == RedisType.CLUSTER) {
+ results.add(new ValidationResult.Builder()
+ .subject(REDIS_CONNECTION_POOL.getDisplayName())
+ .valid(false)
+ .explanation(REDIS_CONNECTION_POOL.getDisplayName()
+ + " is configured in clustered mode, and this service requires a non-clustered Redis")
+ .build());
+ }
+ }
+
+ return results;
+ }
+
+ @OnEnabled
+ public void onEnabled(final ConfigurationContext context) {
+ this.redisConnectionPool = context.getProperty(REDIS_CONNECTION_POOL).asControllerService(RedisConnectionPool.class);
+ }
+
+ @OnDisabled
+ public void onDisabled() {
+ this.redisConnectionPool = null;
+ }
+
+ @Override
+ public boolean putIfAbsent(final K key, final V value, final Serializer keySerializer, final Serializer valueSerializer) throws IOException {
+ return withConnection(redisConnection -> {
+ final Tuple kv = serialize(key, value, keySerializer, valueSerializer);
+ return redisConnection.setNX(kv.getKey(), kv.getValue());
+ });
+ }
+
+ @Override
+ public V getAndPutIfAbsent(final K key, final V value, final Serializer keySerializer, final Serializer valueSerializer, final Deserializer valueDeserializer) throws IOException {
+ return withConnection(redisConnection -> {
+ final Tuple kv = serialize(key, value, keySerializer, valueSerializer);
+ do {
+ // start a watch on the key and retrieve the current value
+ redisConnection.watch(kv.getKey());
+ final byte[] existingValue = redisConnection.get(kv.getKey());
+
+ // start a transaction and perform the put-if-absent
+ redisConnection.multi();
+ redisConnection.setNX(kv.getKey(), kv.getValue());
+
+ // execute the transaction
+ final List