You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jp...@apache.org on 2016/07/29 21:29:05 UTC

[4/4] nifi git commit: NIFI-2208 - initial commit Custom Property Expression Language support with Variable Registry, includes bug fix for NIFI-2057

NIFI-2208 - initial commit Custom Property Expression Language support with Variable Registry, includes bug fix for NIFI-2057

This closes #529

Signed-off-by: jpercivall <jo...@yahoo.com>


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/8412d266
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/8412d266
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/8412d266

Branch: refs/heads/master
Commit: 8412d2662ae1cab6c52be62272a2971d199719df
Parents: b213ed9
Author: Yolanda M. Davis <yo...@gmail.com>
Authored: Thu Jun 23 13:25:17 2016 -0400
Committer: jpercivall <jo...@yahoo.com>
Committed: Fri Jul 29 17:10:20 2016 -0400

----------------------------------------------------------------------
 nifi-api/pom.xml                                |   4 +-
 .../nifi/registry/FileVariableRegistry.java     |  67 +++++++
 .../apache/nifi/registry/ImmutableMultiMap.java | 145 ++++++++++++++
 .../nifi/registry/MultiMapVariableRegistry.java |  70 +++++++
 .../registry/PropertiesVariableRegistry.java    |  82 ++++++++
 .../apache/nifi/registry/VariableRegistry.java  |  60 ++++++
 .../nifi/registry/VariableRegistryFactory.java  |  48 +++++
 .../nifi/registry/VariableRegistryProvider.java |  23 +++
 .../nifi/registry/VariableRegistryUtils.java    |  87 +++++++++
 .../nifi/registry/TestVariableRegistry.java     | 170 +++++++++++++++++
 .../registry/TestVariableRegistryUtils.java     | 143 ++++++++++++++
 .../TestVariableRegistry/foobar.properties      |  16 ++
 .../TestVariableRegistry/test.properties        |  17 ++
 nifi-bootstrap/pom.xml                          |   5 +
 .../bootstrap/NotificationServiceManager.java   |  17 +-
 .../NotificationValidationContext.java          |  10 +-
 .../NotificationServiceManagerSpec.groovy       |  50 +++++
 .../TestCustomNotificationService.java          |  85 +++++++++
 .../test/resources/notification-services.xml    |  24 +++
 .../expression/language/EmptyPreparedQuery.java |  35 +---
 .../language/InvalidPreparedQuery.java          |  33 +---
 .../expression/language/PreparedQuery.java      |  16 +-
 .../attribute/expression/language/Query.java    | 190 +------------------
 .../language/StandardAttributeExpression.java   |   9 +-
 .../StandardExpressionLanguageCompiler.java     |   9 +-
 .../language/StandardPreparedQuery.java         |  37 +---
 .../language/StandardPropertyValue.java         |  23 ++-
 .../expression/language/QueryGroovyTest.groovy  |  17 +-
 .../expression/language/TestQuery.java          | 112 +++++++----
 .../language/TestStandardPreparedQuery.java     |   7 +-
 .../org/apache/nifi/util/NiFiProperties.java    |  27 +++
 .../nifi/web/NiFiWebConfigurationContext.java   |   7 +-
 .../nifi/util/MockConfigurationContext.java     |  13 +-
 .../apache/nifi/util/MockProcessContext.java    |  23 ++-
 .../org/apache/nifi/util/MockPropertyValue.java |  18 +-
 .../apache/nifi/util/MockReportingContext.java  |   7 +-
 .../apache/nifi/util/MockValidationContext.java |  15 +-
 .../nifi/util/StandardProcessorTestRunner.java  |  15 +-
 .../java/org/apache/nifi/util/TestRunners.java  |   8 +-
 .../CurrentTestStandardProcessorTestRunner.java |   3 +-
 .../nifi/util/TestMockProcessContext.java       |   3 +-
 .../ambari/TestAmbariReportingTask.java         |  12 +-
 .../elasticsearch/TestFetchElasticsearch.java   |   6 +-
 .../authorization/AuthorizerFactoryBean.java    |  10 +-
 .../main/resources/nifi-authorizer-context.xml  |   1 +
 .../nifi/authorization/FileAuthorizerTest.java  |  37 ++--
 .../StandardAuthorizerConfigurationContext.java |   7 +-
 .../apache/nifi/controller/FlowController.java  |  90 +++++----
 .../reporting/AbstractReportingTaskNode.java    |  13 +-
 .../reporting/StandardReportingContext.java     |  10 +-
 .../reporting/StandardReportingTaskNode.java    |  12 +-
 .../scheduling/EventDrivenSchedulingAgent.java  |   8 +-
 .../scheduling/QuartzSchedulingAgent.java       |   8 +-
 .../scheduling/StandardProcessScheduler.java    |   9 +-
 .../scheduling/TimerDrivenSchedulingAgent.java  |   8 +-
 .../service/StandardConfigurationContext.java   |   9 +-
 .../service/StandardControllerServiceNode.java  |  18 +-
 .../StandardControllerServiceProvider.java      |  12 +-
 .../manager/StandardStateManagerProvider.java   |  27 +--
 .../nifi/groups/StandardProcessGroup.java       |  12 +-
 .../nifi/processor/StandardProcessContext.java  |  11 +-
 .../processor/StandardValidationContext.java    |  18 +-
 .../StandardValidationContextFactory.java       |   9 +-
 .../nifi/spring/FlowControllerFactoryBean.java  |  16 +-
 .../src/main/resources/nifi-context.xml         |   6 +
 .../controller/StandardFlowServiceTest.java     |   7 +-
 .../nifi/controller/TestFlowController.java     |   8 +-
 .../scheduling/TestProcessorLifecycle.java      |   4 +-
 .../TestStandardProcessScheduler.java           |  29 +--
 .../StandardControllerServiceProviderTest.java  |   6 +-
 .../TestStandardControllerServiceProvider.java  |  27 +--
 .../local/TestWriteAheadLocalStateProvider.java |   8 +-
 .../zookeeper/TestZooKeeperStateProvider.java   |   8 +-
 .../processor/TestStandardPropertyValue.java    |  27 +--
 .../src/main/resources/conf/nifi.properties     |   6 +-
 .../StandardNiFiWebConfigurationContext.java    |  11 ++
 .../nifi/web/controller/ControllerFacade.java   |  12 +-
 .../web/controller/StandardSearchContext.java   |   7 +-
 .../src/main/resources/nifi-web-api-context.xml |   2 +
 .../authorization/TestRangerNiFiAuthorizer.java |  26 +--
 .../processors/script/TestInvokeGroovy.java     |  13 +-
 .../TestSiteToSiteProvenanceReportingTask.java  |   3 +-
 .../standard/TestRouteOnAttribute.java          |   8 +-
 .../nifi/controller/MonitorMemoryTest.java      |   3 +-
 .../cache/server/TestServerAndClient.java       |  14 +-
 .../attributes/UpdateAttributeModelFactory.java |   9 +-
 .../update/attributes/api/RuleResource.java     |  20 +-
 87 files changed, 1769 insertions(+), 608 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-api/pom.xml b/nifi-api/pom.xml
index 103eedd..34d8069 100644
--- a/nifi-api/pom.xml
+++ b/nifi-api/pom.xml
@@ -21,5 +21,5 @@
         <version>1.0.0-SNAPSHOT</version>
     </parent>
     <artifactId>nifi-api</artifactId>
-    <packaging>jar</packaging>    
-</project>
+    <packaging>jar</packaging>
+ </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/FileVariableRegistry.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/FileVariableRegistry.java b/nifi-api/src/main/java/org/apache/nifi/registry/FileVariableRegistry.java
new file mode 100644
index 0000000..9d77d6c
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/FileVariableRegistry.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nifi.registry;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Map;
+
+
+abstract class FileVariableRegistry extends MultiMapVariableRegistry {
+
+    FileVariableRegistry() {
+        super();
+    }
+
+    FileVariableRegistry(File... files) throws IOException{
+        super();
+        addVariables(files);
+    }
+
+    FileVariableRegistry(Path... paths) throws IOException{
+        super();
+        addVariables(paths);
+    }
+
+    private void addVariables(File ...files) throws IOException{
+        if(files != null) {
+            for (final File file : files) {
+                Map<String,String> map = convertFile(file);
+                if(map != null) {
+                    registry.addMap(convertFile(file));
+                }
+            }
+
+        }
+    }
+
+    private void addVariables(Path ...paths) throws IOException{
+        if(paths != null) {
+            for (final Path path : paths) {
+                Map<String,String> map = convertFile(path.toFile());
+                if(map != null) {
+                    registry.addMap(map);
+                }
+            }
+        }
+    }
+
+    protected abstract Map<String,String> convertFile(File file) throws IOException;
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/ImmutableMultiMap.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/ImmutableMultiMap.java b/nifi-api/src/main/java/org/apache/nifi/registry/ImmutableMultiMap.java
new file mode 100644
index 0000000..2fba560
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/ImmutableMultiMap.java
@@ -0,0 +1,145 @@
+/*
+ * 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.registry;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ImmutableMultiMap<V> implements Map<String,V> {
+
+    private final List<Map<String,V>> maps;
+
+    ImmutableMultiMap() {
+        this.maps = new ArrayList<>();
+    }
+
+    @Override
+    public int size() {
+        return keySet().size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        for (final Map<String,V> map : maps) {
+            if (!map.isEmpty()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean containsKey(final Object key) {
+        if (key == null) {
+            return false;
+        }
+
+        for (final Map<String,V> map : maps) {
+            if (map.containsKey(key)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean containsValue(final Object value) {
+        for (final Map<String,V> map : maps) {
+            if (map.containsValue(value)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public V get(final Object key) {
+        if (key == null) {
+            throw new IllegalArgumentException("Null Keys are not allowed");
+        }
+
+        for (final Map<String,V> map : maps) {
+            final V val = map.get(key);
+            if (val != null) {
+                return val;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public V put(String key, V value) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public V remove(Object key) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void putAll(Map<? extends String, ? extends V> m) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void clear() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public Set<String> keySet() {
+        final Set<String> keySet = new HashSet<>();
+        for (final Map map : maps) {
+            keySet.addAll(map.keySet());
+        }
+        return keySet;
+    }
+
+    @Override
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public Collection<V> values() {
+        final Set<V> values = new HashSet<>();
+        for (final Map map : maps) {
+            values.addAll(map.values());
+        }
+        return values;
+    }
+
+    @Override
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public Set<java.util.Map.Entry<String, V>> entrySet() {
+        final Set<java.util.Map.Entry<String, V>> entrySet = new HashSet<>();
+        for (final Map map : maps) {
+            entrySet.addAll(map.entrySet());
+        }
+        return entrySet;
+    }
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    void addMap(Map<String,V> map){
+        this.maps.add(map);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/MultiMapVariableRegistry.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/MultiMapVariableRegistry.java b/nifi-api/src/main/java/org/apache/nifi/registry/MultiMapVariableRegistry.java
new file mode 100644
index 0000000..029bfb5
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/MultiMapVariableRegistry.java
@@ -0,0 +1,70 @@
+/*
+ * 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.registry;
+
+import java.util.Map;
+import java.util.Set;
+
+/***
+ * This implementation of variable registry uses the ImmutableMultiMap which stores one or more
+ * registries that can be searched, accessed and appended.  NOTE: Duplicate values within
+ * or between added registries will be stored however on retrieval the first value encountered will be returned.
+ * */
+public class MultiMapVariableRegistry implements VariableRegistry {
+
+    protected final ImmutableMultiMap<String> registry;
+
+    MultiMapVariableRegistry() {
+        this.registry = new ImmutableMultiMap<>();
+    }
+
+    @SafeVarargs
+    MultiMapVariableRegistry(Map<String,String>...maps){
+        this();
+        if(maps != null) {
+            for (Map<String, String> map : maps) {
+                addVariables(map);
+            }
+        }
+    }
+
+    public void addVariables(Map<String, String> map) {
+        this.registry.addMap(map);
+    }
+
+    @Override
+    public void addRegistry(VariableRegistry variableRegistry) {
+        if(variableRegistry != null && !variableRegistry.getVariables().isEmpty()) {
+            this.registry.addMap(variableRegistry.getVariables());
+        }
+    }
+
+    @Override
+    public Map<String, String> getVariables() {
+        return registry;
+    }
+
+    @Override
+    public String getVariableValue(String variable) {
+        return registry.get(variable);
+    }
+
+    @Override
+    public Set<String> getVariableNames() {
+        return this.registry.keySet();
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/PropertiesVariableRegistry.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/PropertiesVariableRegistry.java b/nifi-api/src/main/java/org/apache/nifi/registry/PropertiesVariableRegistry.java
new file mode 100644
index 0000000..8798930
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/PropertiesVariableRegistry.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+class PropertiesVariableRegistry extends FileVariableRegistry {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PropertiesVariableRegistry.class);
+
+    PropertiesVariableRegistry(File... files) throws IOException{
+        super(files);
+    }
+
+    PropertiesVariableRegistry(Path... paths) throws IOException {
+        super(paths);
+    }
+
+    PropertiesVariableRegistry(Properties...properties){
+        super();
+        addVariables(properties);
+    }
+
+    private void addVariables(Properties... properties){
+        if(properties != null) {
+            for (Properties props : properties) {
+                addVariables(convertToMap(props));
+            }
+        }
+    }
+
+    @Override
+    protected Map<String,String> convertFile(File file) throws IOException{
+
+        if(file.exists()) {
+            try (final InputStream inStream = new BufferedInputStream(new FileInputStream(file))) {
+                Properties properties = new Properties();
+                properties.load(inStream);
+                return convertToMap(properties);
+            }
+        }else{
+            LOG.warn("Could not add file " + file.getName() + ". file did not exist.");
+            return null;
+        }
+
+    }
+
+    private Map<String,String> convertToMap(Properties properties){
+        HashMap<String,String> propertiesMap = new HashMap<>(properties.keySet().size());
+        for(Object key:  properties.keySet()){
+            propertiesMap.put((String)key,(String) properties.get(key));
+        }
+        return propertiesMap;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistry.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistry.java b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistry.java
new file mode 100644
index 0000000..48eacfd
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistry.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry;
+
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *  Access key/value pairs throughout the application.
+ */
+public interface VariableRegistry {
+
+    /**
+     * Returns a map of key/value pairs stored in the registry
+     *  @return variables
+     **/
+    Map<String, String> getVariables();
+
+    /**
+     * Return a value for a given variable
+     * @param variable variable
+     * @return value
+     **/
+    String getVariableValue(String variable);
+
+    /**
+     * Concatenate a variable registry
+     * @param variableRegistry variableRegistry
+     * */
+    void addRegistry(VariableRegistry variableRegistry);
+
+    /**
+     * Returns a set variable names in the registry
+     * @return variableNames
+     **/
+    Set<String> getVariableNames();
+
+    /**
+     * Concatenate variable key value pair to registry
+     * @param variables variable Map
+     * */
+    void addVariables(Map<String,String> variables);
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryFactory.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryFactory.java b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryFactory.java
new file mode 100644
index 0000000..1852ad4
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryFactory.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.registry;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Properties;
+
+public class VariableRegistryFactory {
+
+    public static VariableRegistry getPropertiesInstance(final Properties...properties){
+        return new PropertiesVariableRegistry(properties);
+    }
+
+    public static VariableRegistry getPropertiesInstance(final Path... paths) throws IOException{
+        return new PropertiesVariableRegistry(paths);
+    }
+
+    public static VariableRegistry getPropertiesInstance(final File ...files) throws IOException{
+        return new PropertiesVariableRegistry(files);
+    }
+
+    @SafeVarargs
+    public static VariableRegistry getInstance(final Map<String,String> ...maps){
+        return new MultiMapVariableRegistry(maps);
+    }
+
+    public static VariableRegistry getInstance(){
+        return new MultiMapVariableRegistry();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryProvider.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryProvider.java b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryProvider.java
new file mode 100644
index 0000000..af7ab38
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryProvider.java
@@ -0,0 +1,23 @@
+/*
+ * 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.registry;
+
+public interface VariableRegistryProvider {
+
+    VariableRegistry getVariableRegistry();
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryUtils.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryUtils.java b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryUtils.java
new file mode 100644
index 0000000..6e280d6
--- /dev/null
+++ b/nifi-api/src/main/java/org/apache/nifi/registry/VariableRegistryUtils.java
@@ -0,0 +1,87 @@
+/*
+ * 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.registry;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.nifi.flowfile.FlowFile;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VariableRegistryUtils {
+
+    private final static Logger LOG =  LoggerFactory.getLogger(VariableRegistryUtils.class);
+
+    public static VariableRegistry createSystemVariableRegistry(){
+        VariableRegistry variableRegistry = VariableRegistryFactory.getInstance();
+        VariableRegistry propRegistry = VariableRegistryFactory.getPropertiesInstance(System.getProperties());
+        VariableRegistry envRegistry = VariableRegistryFactory.getInstance(System.getenv());
+        variableRegistry.addRegistry(propRegistry);
+        variableRegistry.addRegistry(envRegistry);
+        return variableRegistry;
+    }
+
+    public static VariableRegistry createCustomVariableRegistry(Path[] properties){
+
+        VariableRegistry customRegistry = null;
+        try {
+            customRegistry = VariableRegistryFactory.getPropertiesInstance(properties);
+            customRegistry.addRegistry(createSystemVariableRegistry());
+        } catch (IOException ioe){
+            LOG.error("Exception thrown while attempting to add properties to registry",ioe);
+        }
+        return customRegistry;
+    }
+
+    public static VariableRegistry createFlowVariableRegistry(VariableRegistry variableRegistry, final FlowFile flowFile, final Map<String, String> additionalAttributes){
+        final Map<String, String> flowFileAttributes = flowFile == null ? null : flowFile.getAttributes();
+        final Map<String, String> additionalMap = additionalAttributes == null ? null : additionalAttributes;
+
+        Map<String, String> flowFileProps = null;
+        if (flowFile != null) {
+            flowFileProps = new HashMap<>();
+            flowFileProps.put("flowFileId", String.valueOf(flowFile.getId()));
+            flowFileProps.put("fileSize", String.valueOf(flowFile.getSize()));
+            flowFileProps.put("entryDate", String.valueOf(flowFile.getEntryDate()));
+            flowFileProps.put("lineageStartDate", String.valueOf(flowFile.getLineageStartDate()));
+            flowFileProps.put("lastQueueDate",String.valueOf(flowFile.getLastQueueDate()));
+            flowFileProps.put("queueDateIndex",String.valueOf(flowFile.getQueueDateIndex()));
+        }
+
+        VariableRegistry newRegistry = VariableRegistryFactory.getInstance();
+
+        if(flowFileAttributes != null) {
+            newRegistry.addVariables(flowFileAttributes);
+        }
+        if(additionalMap != null) {
+            newRegistry.addVariables(additionalMap);
+        }
+        if(flowFileProps != null) {
+            newRegistry.addVariables(flowFileProps);
+        }
+
+        if(variableRegistry != null) {
+            newRegistry.addRegistry(variableRegistry);
+        }
+
+        return newRegistry;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistry.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistry.java b/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistry.java
new file mode 100644
index 0000000..93099b2
--- /dev/null
+++ b/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistry.java
@@ -0,0 +1,170 @@
+/*
+ * 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.registry;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class TestVariableRegistry {
+
+    @Test
+    public void testReadMap(){
+        Map<String,String> variables1 = new HashMap<>();
+        variables1.put("fake.property.1","fake test value");
+
+        Map<String,String> variables2 = new HashMap<>();
+        variables1.put("fake.property.2","fake test value");
+
+        VariableRegistry registry = VariableRegistryFactory.getInstance(variables1,variables2);
+
+        Map<String,String> variables = registry.getVariables();
+        assertTrue(variables.size() == 2);
+        assertTrue(variables.get("fake.property.1").equals("fake test value"));
+        assertTrue(registry.getVariableValue("fake.property.2").equals("fake test value"));
+    }
+
+    @Test
+    public void testReadProperties(){
+        Properties properties = new Properties();
+        properties.setProperty("fake.property.1","fake test value");
+        VariableRegistry registry = VariableRegistryFactory.getPropertiesInstance(properties);
+        Map<String,String> variables = registry.getVariables();
+        assertTrue(variables.get("fake.property.1").equals("fake test value"));
+    }
+
+    @Test
+    public void testReadFiles() throws IOException{
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        VariableRegistry registry = VariableRegistryFactory.getPropertiesInstance(fooPath.toFile(),testPath.toFile());
+        Map<String,String> variables = registry.getVariables();
+        assertTrue(variables.size() == 3);
+        assertTrue(variables.get("fake.property.1").equals("test me out 1"));
+        assertTrue(variables.get("fake.property.3").equals("test me out 3, test me out 4"));
+    }
+
+    @Test
+    public void testExcludeInvalidFiles() throws IOException{
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        final Path fakePath = Paths.get("src/test/resources/TestVariableRegistry/fake.properties");
+        VariableRegistry registry = VariableRegistryFactory.getPropertiesInstance(fooPath.toFile(),testPath.toFile(),fakePath.toFile());
+        Map<String,String> variables = registry.getVariables();
+        assertTrue(variables.size() == 3);
+        assertTrue(variables.get("fake.property.1").equals("test me out 1"));
+        assertTrue(variables.get("fake.property.3").equals("test me out 3, test me out 4"));
+    }
+
+
+    @Test
+    public void testReadPaths() throws IOException{
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        VariableRegistry registry = VariableRegistryFactory.getPropertiesInstance(fooPath,testPath);
+        Map<String,String> variables = registry.getVariables();
+        assertTrue(variables.size() == 3);
+        assertTrue(variables.get("fake.property.1").equals("test me out 1"));
+        assertTrue(variables.get("fake.property.3").equals("test me out 3, test me out 4"));
+    }
+
+    @Test
+    public void testExcludeInvalidPaths() throws IOException{
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        final Path fakePath = Paths.get("src/test/resources/TestVariableRegistry/fake.properties");
+        VariableRegistry registry = VariableRegistryFactory.getPropertiesInstance(fooPath,testPath,fakePath);
+        Map<String,String> variables = registry.getVariables();
+        assertTrue(variables.size() == 3);
+    }
+
+    @Test
+    public void testAddRegistry() throws IOException{
+
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        VariableRegistry pathRegistry = VariableRegistryFactory.getPropertiesInstance(fooPath);
+
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        VariableRegistry fileRegistry = VariableRegistryFactory.getPropertiesInstance(testPath.toFile());
+
+        Properties properties = new Properties();
+        properties.setProperty("fake.property.5","test me out 5");
+        VariableRegistry propRegistry = VariableRegistryFactory.getPropertiesInstance(properties);
+
+        propRegistry.addRegistry(pathRegistry);
+        propRegistry.addRegistry(fileRegistry);
+
+        Map<String,String> variables = propRegistry.getVariables();
+        assertTrue(variables.size() == 4);
+    }
+
+    @Test
+    public void testAttemptToAddNullRegistry() throws IOException{
+
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        VariableRegistry pathRegistry = VariableRegistryFactory.getPropertiesInstance(fooPath);
+        VariableRegistry nullRegistry = null;
+        pathRegistry.addRegistry(nullRegistry);
+        assertTrue(pathRegistry.getVariables().size() == 1);
+    }
+
+    @Test
+    public void testNoOverwriteRegistry()throws IOException{
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        VariableRegistry pathRegistry = VariableRegistryFactory.getPropertiesInstance(fooPath);
+
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        VariableRegistry fileRegistry = VariableRegistryFactory.getPropertiesInstance(testPath.toFile());
+
+        Properties properties = new Properties();
+        properties.setProperty("fake.property.3","test me out 5");
+        VariableRegistry propRegistry = VariableRegistryFactory.getPropertiesInstance(properties);
+
+        propRegistry.addRegistry(pathRegistry);
+        propRegistry.addRegistry(fileRegistry);
+
+        Map<String,String> variables = propRegistry.getVariables();
+        String testDuplicate = propRegistry.getVariableValue("fake.property.3");
+        assertTrue(variables.size() == 3);
+        assertTrue(testDuplicate.equals("test me out 5"));
+    }
+
+    @Test
+    public void testGetVariableNames() throws IOException{
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        VariableRegistry registry = VariableRegistryFactory.getPropertiesInstance(fooPath,testPath);
+        Set<String> variableNames= registry.getVariableNames();
+        assertTrue(variableNames.size() == 3);
+        assertTrue(variableNames.contains("fake.property.1"));
+        assertTrue(variableNames.contains("fake.property.2"));
+        assertTrue(variableNames.contains("fake.property.3"));
+        assertTrue(!variableNames.contains("fake.property.4"));
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistryUtils.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistryUtils.java b/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistryUtils.java
new file mode 100644
index 0000000..a3c4ae4
--- /dev/null
+++ b/nifi-api/src/test/java/org/apache/nifi/registry/TestVariableRegistryUtils.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.nifi.flowfile.FlowFile;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class TestVariableRegistryUtils {
+
+    @Test
+    public void testCreateSystemVariableRegistry(){
+        System.setProperty("fake","test");
+        VariableRegistry variableRegistry = VariableRegistryUtils.createSystemVariableRegistry();
+        Map<String,String> variables = variableRegistry.getVariables();
+        assertTrue(variables.containsKey("PATH"));
+        assertTrue(variables.get("fake").equals("test"));
+    }
+
+    @Test
+    public void testCreateCustomVariableRegistry(){
+        final Path fooPath = Paths.get("src/test/resources/TestVariableRegistry/foobar.properties");
+        final Path testPath = Paths.get("src/test/resources/TestVariableRegistry/test.properties");
+        Path[] paths = {fooPath,testPath};
+        System.setProperty("fake","test");
+        VariableRegistry variableRegistry = VariableRegistryUtils.createCustomVariableRegistry(paths);
+        Map<String,String> variables = variableRegistry.getVariables();
+        assertTrue(variables.containsKey("PATH"));
+        assertTrue(variables.containsKey("fake.property.3"));
+        assertTrue(variables.get("fake").equals("test"));
+        assertTrue(variables.get("fake.property.3").equals("test me out 3, test me out 4"));
+    }
+
+    @Test
+    public void testCreateFlowVariableRegistry(){
+        System.setProperty("fake","test");
+        FlowFile flowFile = createFlowFile();
+
+        VariableRegistry variableRegistry = VariableRegistryUtils.createSystemVariableRegistry();
+        VariableRegistry populatedRegistry = VariableRegistryUtils.createFlowVariableRegistry(variableRegistry,flowFile,null);
+        Map<String,String> variables = populatedRegistry.getVariables();
+        assertTrue(variables.containsKey("PATH"));
+        assertTrue(variables.get("fake").equals("test"));
+        assertTrue(variables.get("flowFileId").equals("1"));
+        assertTrue(variables.get("fileSize").equals("50"));
+        assertTrue(variables.get("entryDate").equals("1000"));
+        assertTrue(variables.get("lineageStartDate").equals("10000"));
+        assertTrue(variables.get("filename").equals("fakefile.txt"));
+    }
+
+    @Test
+    public void testPopulateRegistryWithEmptyFlowFileAndAttributes(){
+        System.setProperty("fake","test");
+        VariableRegistry variableRegistry = VariableRegistryUtils.createSystemVariableRegistry();
+        VariableRegistry populatedRegistry = VariableRegistryUtils.createFlowVariableRegistry(variableRegistry,null,null);
+        Map<String,String> variables = populatedRegistry.getVariables();
+        assertTrue( variables.containsKey("PATH"));
+        assertTrue( variables.get("fake").equals("test"));
+    }
+
+
+    private FlowFile createFlowFile(){
+        return  new FlowFile() {
+            @Override
+            public long getId() {
+                return 1;
+            }
+
+            @Override
+            public long getEntryDate() {
+                return 1000;
+            }
+
+            @Override
+            public long getLineageStartDate() {
+                return 10000;
+            }
+
+            @Override
+            public Long getLastQueueDate() {
+                return null;
+            }
+
+            @Override
+            public boolean isPenalized() {
+                return false;
+            }
+
+            @Override
+            public String getAttribute(String key) {
+                return null;
+            }
+
+            @Override
+            public long getSize() {
+                return 50;
+            }
+
+            @Override
+            public long getLineageStartIndex() {
+                return 0;
+            }
+
+            @Override
+            public long getQueueDateIndex() {
+                return 0;
+            }
+
+            @Override
+            public Map<String, String> getAttributes() {
+                Map<String,String> attributes = new HashMap<>();
+                attributes.put("filename","fakefile.txt");
+                return attributes;
+            }
+
+            @Override
+            public int compareTo(FlowFile o) {
+                return 0;
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/test/resources/TestVariableRegistry/foobar.properties
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/resources/TestVariableRegistry/foobar.properties b/nifi-api/src/test/resources/TestVariableRegistry/foobar.properties
new file mode 100644
index 0000000..1094e1b
--- /dev/null
+++ b/nifi-api/src/test/resources/TestVariableRegistry/foobar.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+fake.property.3=test me out 3, test me out 4
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-api/src/test/resources/TestVariableRegistry/test.properties
----------------------------------------------------------------------
diff --git a/nifi-api/src/test/resources/TestVariableRegistry/test.properties b/nifi-api/src/test/resources/TestVariableRegistry/test.properties
new file mode 100644
index 0000000..6191449
--- /dev/null
+++ b/nifi-api/src/test/resources/TestVariableRegistry/test.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+fake.property.1=test me out 1
+fake.property.2=test me out 2

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-bootstrap/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-bootstrap/pom.xml b/nifi-bootstrap/pom.xml
index ce30cd7..5694fd9 100644
--- a/nifi-bootstrap/pom.xml
+++ b/nifi-bootstrap/pom.xml
@@ -41,5 +41,10 @@
 			<groupId>org.apache.nifi</groupId>
 			<artifactId>nifi-expression-language</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.spockframework</groupId>
+			<artifactId>spock-core</artifactId>
+			<scope>test</scope>
+		</dependency>
 	</dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
----------------------------------------------------------------------
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 21d8e82..233c66d 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
@@ -46,6 +46,8 @@ import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.PropertyValue;
 import org.apache.nifi.components.ValidationContext;
 import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.registry.VariableRegistry;
+import org.apache.nifi.registry.VariableRegistryUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
@@ -62,8 +64,15 @@ public class NotificationServiceManager {
 
     private final ScheduledExecutorService notificationExecutor;
     private int maxAttempts = 5;
+    private final VariableRegistry variableRegistry;
+
 
     public NotificationServiceManager() {
+        this(VariableRegistryUtils.createSystemVariableRegistry());
+    }
+
+    NotificationServiceManager(VariableRegistry variableRegistry){
+        this.variableRegistry = variableRegistry;
         notificationExecutor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
             @Override
             public Thread newThread(final Runnable r) {
@@ -141,7 +150,7 @@ public class NotificationServiceManager {
                 }
 
                 // Check if the service is valid; if not, warn now so that users know this before they fail to receive notifications
-                final ValidationContext validationContext = new NotificationValidationContext(buildNotificationContext(config));
+                final ValidationContext validationContext = new NotificationValidationContext(buildNotificationContext(config), variableRegistry);
                 final Collection<ValidationResult> validationResults = service.validate(validationContext);
                 final List<String> invalidReasons = new ArrayList<>();
 
@@ -179,7 +188,7 @@ public class NotificationServiceManager {
                 @Override
                 public void run() {
                     // Check if the service is valid; if not, warn now so that users know this before they fail to receive notifications
-                    final ValidationContext validationContext = new NotificationValidationContext(buildNotificationContext(config));
+                    final ValidationContext validationContext = new NotificationValidationContext(buildNotificationContext(config), variableRegistry);
                     final Collection<ValidationResult> validationResults = service.validate(validationContext);
                     final List<String> invalidReasons = new ArrayList<>();
 
@@ -247,7 +256,7 @@ public class NotificationServiceManager {
                     configuredValue = fullPropDescriptor.getDefaultValue();
                 }
 
-                return new StandardPropertyValue(configuredValue, null);
+                return new StandardPropertyValue(configuredValue, null, variableRegistry);
             }
 
             @Override
@@ -364,7 +373,7 @@ public class NotificationServiceManager {
                         value = descriptor.getDefaultValue();
                     }
 
-                    return new StandardPropertyValue(value, null);
+                    return new StandardPropertyValue(value, null, variableRegistry);
                 }
 
                 @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/notification/NotificationValidationContext.java
----------------------------------------------------------------------
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 f29c1c9..99d3b23 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
@@ -30,12 +30,14 @@ import org.apache.nifi.components.ValidationContext;
 import org.apache.nifi.controller.ControllerService;
 import org.apache.nifi.controller.ControllerServiceLookup;
 import org.apache.nifi.expression.ExpressionLanguageCompiler;
+import org.apache.nifi.registry.VariableRegistry;
 
 public class NotificationValidationContext implements ValidationContext {
     private final NotificationContext context;
     private final Map<String, Boolean> expressionLanguageSupported;
+    private final VariableRegistry variableRegistry;
 
-    public NotificationValidationContext(final NotificationContext processContext) {
+    public NotificationValidationContext(final NotificationContext processContext, VariableRegistry variableRegistry) {
         this.context = processContext;
 
         final Map<PropertyDescriptor, String> properties = processContext.getProperties();
@@ -43,17 +45,19 @@ public class NotificationValidationContext implements ValidationContext {
         for (final PropertyDescriptor descriptor : properties.keySet()) {
             expressionLanguageSupported.put(descriptor.getName(), descriptor.isExpressionLanguageSupported());
         }
+        this.variableRegistry = variableRegistry;
     }
 
 
     @Override
     public PropertyValue newPropertyValue(final String rawValue) {
-        return new StandardPropertyValue(rawValue, null);
+        return new StandardPropertyValue(rawValue, null, variableRegistry);
     }
 
     @Override
     public ExpressionLanguageCompiler newExpressionLanguageCompiler() {
-        return new StandardExpressionLanguageCompiler();
+
+        return new StandardExpressionLanguageCompiler(null);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/NotificationServiceManagerSpec.groovy
----------------------------------------------------------------------
diff --git a/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/NotificationServiceManagerSpec.groovy b/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/NotificationServiceManagerSpec.groovy
new file mode 100644
index 0000000..7bd4c52
--- /dev/null
+++ b/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/NotificationServiceManagerSpec.groovy
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.nifi.bootstrap
+
+import org.apache.nifi.bootstrap.notification.NotificationType
+import org.apache.nifi.registry.VariableRegistry
+import spock.lang.Specification
+import java.nio.file.Paths
+
+class NotificationServiceManagerSpec extends Specification{
+
+    def setupSpec(){
+    }
+
+    def "should acess variable registry to replace EL values"(){
+
+        given:
+            def mockRegistry = Mock(VariableRegistry.class)
+            def notificationServiceManager = new NotificationServiceManager(mockRegistry);
+            def file = Paths.get("src/test/resources/notification-services.xml").toFile()
+            notificationServiceManager.loadNotificationServices(file)
+            //testing with stopped becasue it will block until method is completed
+            notificationServiceManager.registerNotificationService(NotificationType.NIFI_STOPPED,"custom-notification")
+
+        when:
+            notificationServiceManager.notify(NotificationType.NIFI_STOPPED,"NiFi Stopped","NiFi Stopped")
+
+        then:
+            6 * mockRegistry.getVariables() >> ["test.server":"smtp://fakeserver.com","test.username":"user","test.password":"pass"]
+
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/notification/TestCustomNotificationService.java
----------------------------------------------------------------------
diff --git a/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/notification/TestCustomNotificationService.java b/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/notification/TestCustomNotificationService.java
new file mode 100644
index 0000000..3685cb1
--- /dev/null
+++ b/nifi-bootstrap/src/test/groovy/org/apache/nifi/bootstrap/notification/TestCustomNotificationService.java
@@ -0,0 +1,85 @@
+package org.apache.nifi.bootstrap.notification;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestCustomNotificationService extends AbstractNotificationService {
+
+    private static Logger logger = LoggerFactory.getLogger(TestCustomNotificationService.class);
+
+    public static final PropertyDescriptor CUSTOM_HOSTNAME = new PropertyDescriptor.Builder()
+            .name("Custom Hostname")
+            .description("The hostname of the Custom Server that is used to send notifications")
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .expressionLanguageSupported(true)
+            .required(true)
+            .build();
+    public static final PropertyDescriptor CUSTOM_USERNAME = new PropertyDescriptor.Builder()
+            .name("Custom Username")
+            .description("Username for the account")
+            .expressionLanguageSupported(true)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .required(false)
+            .build();
+    public static final PropertyDescriptor CUSTOM_PASSWORD = new PropertyDescriptor.Builder()
+            .name("Custom Password")
+            .description("Password for the account")
+            .expressionLanguageSupported(true)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .required(false)
+            .sensitive(true)
+            .build();
+
+    /**
+     * Mapping of the mail properties to the NiFi PropertyDescriptors that will be evaluated at runtime
+     */
+    private static final Map<String, PropertyDescriptor> propertyToContext = new HashMap<>();
+
+    static {
+        propertyToContext.put("custom.host", CUSTOM_HOSTNAME);
+        propertyToContext.put("custom.user", CUSTOM_USERNAME);
+        propertyToContext.put("custom.password", CUSTOM_PASSWORD);
+    }
+
+    @Override
+    protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+        final List<PropertyDescriptor> properties = new ArrayList<>();
+        properties.add(CUSTOM_HOSTNAME);
+        properties.add(CUSTOM_USERNAME);
+        properties.add(CUSTOM_PASSWORD);
+        return properties;
+    }
+
+    @Override
+    public void notify(NotificationContext context, String subject, String message) throws NotificationFailedException {
+        logger.info(context.getProperty(CUSTOM_HOSTNAME).evaluateAttributeExpressions().getValue());
+        logger.info(context.getProperty(CUSTOM_USERNAME).evaluateAttributeExpressions().getValue());
+        logger.info(context.getProperty(CUSTOM_PASSWORD).evaluateAttributeExpressions().getValue());
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-bootstrap/src/test/resources/notification-services.xml
----------------------------------------------------------------------
diff --git a/nifi-bootstrap/src/test/resources/notification-services.xml b/nifi-bootstrap/src/test/resources/notification-services.xml
new file mode 100644
index 0000000..5f02a3b
--- /dev/null
+++ b/nifi-bootstrap/src/test/resources/notification-services.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<services>
+         <service>
+            <id>custom-notification</id>
+            <class>org.apache.nifi.bootstrap.notification.TestCustomNotificationService</class>
+            <property name="Custom Hostname">${test.server}</property>
+            <property name="Custom Username">${test.username}</property>
+            <property name="Custom Password">${test.password}</property>
+         </service>
+</services>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/EmptyPreparedQuery.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/EmptyPreparedQuery.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/EmptyPreparedQuery.java
index d85c9ef..5dec2fa 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/EmptyPreparedQuery.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/EmptyPreparedQuery.java
@@ -16,11 +16,10 @@
  */
 package org.apache.nifi.attribute.expression.language;
 
-import java.util.Map;
 
 import org.apache.nifi.expression.AttributeValueDecorator;
-import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.registry.VariableRegistry;
 
 public class EmptyPreparedQuery implements PreparedQuery {
 
@@ -31,37 +30,7 @@ public class EmptyPreparedQuery implements PreparedQuery {
     }
 
     @Override
-    public String evaluateExpressions(final FlowFile flowFile, final AttributeValueDecorator decorator) throws ProcessException {
-        return value;
-    }
-
-    @Override
-    public String evaluateExpressions() throws ProcessException {
-        return value;
-    }
-
-    @Override
-    public String evaluateExpressions(final AttributeValueDecorator decorator) throws ProcessException {
-        return value;
-    }
-
-    @Override
-    public String evaluateExpressions(final FlowFile flowFile) throws ProcessException {
-        return value;
-    }
-
-    @Override
-    public String evaluateExpressions(Map<String, String> attributes) throws ProcessException {
-        return value;
-    }
-
-    @Override
-    public String evaluateExpressions(Map<String, String> attributes, AttributeValueDecorator decorator) throws ProcessException {
-        return value;
-    }
-
-    @Override
-    public String evaluateExpressions(FlowFile flowFile, Map<String, String> additionalAttributes, AttributeValueDecorator decorator) throws ProcessException {
+    public String evaluateExpressions(VariableRegistry variableRegistry, AttributeValueDecorator decorator) throws ProcessException {
         return value;
     }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/InvalidPreparedQuery.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/InvalidPreparedQuery.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/InvalidPreparedQuery.java
index aa2428d..0ca9a8f 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/InvalidPreparedQuery.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/InvalidPreparedQuery.java
@@ -16,12 +16,11 @@
  */
 package org.apache.nifi.attribute.expression.language;
 
-import java.util.Map;
 
 import org.apache.nifi.attribute.expression.language.exception.AttributeExpressionLanguageException;
 import org.apache.nifi.expression.AttributeValueDecorator;
-import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.registry.VariableRegistry;
 
 /**
  * An implementation of PreparedQuery that throws an
@@ -40,37 +39,9 @@ public class InvalidPreparedQuery implements PreparedQuery {
     }
 
     @Override
-    public String evaluateExpressions(final FlowFile flowFile, final AttributeValueDecorator decorator) throws ProcessException {
+    public String evaluateExpressions(final VariableRegistry variableRegistry, final AttributeValueDecorator decorator) throws ProcessException {
         throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
     }
 
-    @Override
-    public String evaluateExpressions() throws ProcessException {
-        throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
-    }
-
-    @Override
-    public String evaluateExpressions(final AttributeValueDecorator decorator) throws ProcessException {
-        throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
-    }
-
-    @Override
-    public String evaluateExpressions(final FlowFile flowFile) throws ProcessException {
-        throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
-    }
 
-    @Override
-    public String evaluateExpressions(final Map<String, String> attributes) throws ProcessException {
-        throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
-    }
-
-    @Override
-    public String evaluateExpressions(final Map<String, String> attributes, final AttributeValueDecorator decorator) throws ProcessException {
-        throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
-    }
-
-    @Override
-    public String evaluateExpressions(FlowFile flowFile, Map<String, String> additionalAttributes, AttributeValueDecorator decorator) throws ProcessException {
-        throw new AttributeExpressionLanguageException("Invalid Expression: " + query + " due to " + explanation);
-    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/PreparedQuery.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/PreparedQuery.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/PreparedQuery.java
index ad9225d..37d8b86 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/PreparedQuery.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/PreparedQuery.java
@@ -16,25 +16,13 @@
  */
 package org.apache.nifi.attribute.expression.language;
 
-import java.util.Map;
 
 import org.apache.nifi.expression.AttributeValueDecorator;
-import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.registry.VariableRegistry;
 
 public interface PreparedQuery {
 
-    String evaluateExpressions(FlowFile flowFile, AttributeValueDecorator decorator) throws ProcessException;
+    String evaluateExpressions(VariableRegistry registry, AttributeValueDecorator decorator) throws ProcessException;
 
-    String evaluateExpressions() throws ProcessException;
-
-    String evaluateExpressions(AttributeValueDecorator decorator) throws ProcessException;
-
-    String evaluateExpressions(FlowFile flowFile) throws ProcessException;
-
-    String evaluateExpressions(Map<String, String> attributes) throws ProcessException;
-
-    String evaluateExpressions(Map<String, String> attributes, AttributeValueDecorator decorator) throws ProcessException;
-
-    String evaluateExpressions(FlowFile flowFile, Map<String, String> additionalAttributes, AttributeValueDecorator decorator) throws ProcessException;
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java
index 6985bfc..f2d3915 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java
@@ -18,13 +18,9 @@ package org.apache.nifi.attribute.expression.language;
 
 import java.net.UnknownHostException;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionLexer;
@@ -198,6 +194,7 @@ import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpre
 import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.UUID;
 
 import org.apache.nifi.attribute.expression.language.evaluation.selection.MappingEvaluator;
+import org.apache.nifi.registry.VariableRegistry;
 
 /**
  * Class used for creating and evaluating NiFi Expression Language. Once a Query
@@ -367,8 +364,8 @@ public class Query {
         return -1;
     }
 
-    static String evaluateExpression(final Tree tree, final String queryText, final Map<String, String> expressionMap, final AttributeValueDecorator decorator) throws ProcessException {
-        final Object evaluated = Query.fromTree(tree, queryText).evaluate(expressionMap).getValue();
+    static String evaluateExpression(final Tree tree, final String queryText, final VariableRegistry registry, final AttributeValueDecorator decorator) throws ProcessException {
+        final Object evaluated = Query.fromTree(tree, queryText).evaluate(registry).getValue();
         if (evaluated == null) {
             return null;
         }
@@ -378,29 +375,12 @@ public class Query {
         return decorator == null ? escaped : decorator.decorate(escaped);
     }
 
-    static String evaluateExpressions(final String rawValue, Map<String, String> expressionMap) throws ProcessException {
-        return evaluateExpressions(rawValue, expressionMap, null);
+    static String evaluateExpressions(final String rawValue, VariableRegistry registry) throws ProcessException {
+        return evaluateExpressions(rawValue, registry, null);
     }
 
-    static String evaluateExpressions(final String rawValue) throws ProcessException {
-        return evaluateExpressions(rawValue, createExpressionMap(null), null);
-    }
-
-    static String evaluateExpressions(final String rawValue, final FlowFile flowFile) throws ProcessException {
-        return evaluateExpressions(rawValue, createExpressionMap(flowFile), null);
-    }
-
-    static String evaluateExpressions(final String rawValue, Map<String, String> expressionMap, final AttributeValueDecorator decorator) throws ProcessException {
-        return Query.prepare(rawValue).evaluateExpressions(expressionMap, decorator);
-    }
-
-    public static String evaluateExpressions(final String rawValue, final FlowFile flowFile, final AttributeValueDecorator decorator) throws ProcessException {
-        if (rawValue == null) {
-            return null;
-        }
-
-        final Map<String, String> expressionMap = createExpressionMap(flowFile);
-        return evaluateExpressions(rawValue, expressionMap, decorator);
+    static String evaluateExpressions(final String rawValue, VariableRegistry registry, final AttributeValueDecorator decorator) throws ProcessException {
+        return Query.prepare(rawValue).evaluateExpressions(registry, decorator);
     }
 
     private static Evaluator<?> getRootSubjectEvaluator(final Evaluator<?> evaluator) {
@@ -426,150 +406,6 @@ public class Query {
         return value.replaceAll("\\$\\$(?=\\$*\\{.*?\\})", "\\$");
     }
 
-    static Map<String, String> createExpressionMap(final FlowFile flowFile) {
-        return createExpressionMap(flowFile, null);
-    }
-
-    static Map<String, String> createExpressionMap(final FlowFile flowFile, final Map<String, String> additionalAttributes) {
-        final Map<String, String> attributeMap = flowFile == null ? Collections.emptyMap() : flowFile.getAttributes();
-        final Map<String, String> additionalOrEmpty = additionalAttributes == null ? Collections.emptyMap() : additionalAttributes;
-        final Map<String, String> envMap = System.getenv();
-        final Map<?, ?> sysProps = System.getProperties();
-
-        final Map<String, String> flowFileProps = new HashMap<>();
-        if (flowFile != null) {
-            flowFileProps.put("flowFileId", String.valueOf(flowFile.getId()));
-            flowFileProps.put("fileSize", String.valueOf(flowFile.getSize()));
-            flowFileProps.put("entryDate", String.valueOf(flowFile.getEntryDate()));
-            flowFileProps.put("lineageStartDate", String.valueOf(flowFile.getLineageStartDate()));
-        }
-
-        return wrap(additionalOrEmpty, attributeMap, flowFileProps, envMap, sysProps);
-    }
-
-    private static Map<String, String> wrap(final Map<String, String> additional, final Map<String, String> attributes, final Map<String, String> flowFileProps,
-        final Map<String, String> env, final Map<?, ?> sysProps) {
-        @SuppressWarnings("rawtypes")
-        final Map[] maps = new Map[] {additional, attributes, flowFileProps, env, sysProps};
-
-        return new Map<String, String>() {
-            @Override
-            public int size() {
-                int size = 0;
-                for (final Map<?, ?> map : maps) {
-                    size += map.size();
-                }
-                return size;
-            }
-
-            @Override
-            public boolean isEmpty() {
-                for (final Map<?, ?> map : maps) {
-                    if (!map.isEmpty()) {
-                        return false;
-                    }
-                }
-                return true;
-            }
-
-            @Override
-            public boolean containsKey(final Object key) {
-                if (key == null) {
-                    return false;
-                }
-                if (!(key instanceof String)) {
-                    return false;
-                }
-
-                for (final Map<?, ?> map : maps) {
-                    if (map.containsKey(key)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public boolean containsValue(final Object value) {
-                for (final Map<?, ?> map : maps) {
-                    if (map.containsValue(value)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            @SuppressWarnings("rawtypes")
-            public String get(final Object key) {
-                if (key == null) {
-                    throw new IllegalArgumentException("Null Keys are not allowed");
-                }
-                if (!(key instanceof String)) {
-                    return null;
-                }
-
-                for (final Map map : maps) {
-                    final Object val = map.get(key);
-                    if (val != null) {
-                        return String.valueOf(val);
-                    }
-                }
-                return null;
-            }
-
-            @Override
-            public String put(String key, String value) {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public String remove(final Object key) {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public void putAll(final Map<? extends String, ? extends String> m) {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public void clear() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            @SuppressWarnings({"unchecked", "rawtypes"})
-            public Set<String> keySet() {
-                final Set<String> keySet = new HashSet<>();
-                for (final Map map : maps) {
-                    keySet.addAll(map.keySet());
-                }
-                return keySet;
-            }
-
-            @Override
-            @SuppressWarnings({"unchecked", "rawtypes"})
-            public Collection<String> values() {
-                final Set<String> values = new HashSet<>();
-                for (final Map map : maps) {
-                    values.addAll(map.values());
-                }
-                return values;
-            }
-
-            @Override
-            @SuppressWarnings({"unchecked", "rawtypes"})
-            public Set<java.util.Map.Entry<String, String>> entrySet() {
-                final Set<java.util.Map.Entry<String, String>> entrySet = new HashSet<>();
-                for (final Map map : maps) {
-                    entrySet.addAll(map.entrySet());
-                }
-                return entrySet;
-            }
-
-        };
-    }
 
     public static Query fromTree(final Tree tree, final String text) {
         return new Query(text, tree, buildEvaluator(tree));
@@ -706,20 +542,12 @@ public class Query {
         return evaluator.getResultType();
     }
 
-    QueryResult<?> evaluate() {
-        return evaluate(createExpressionMap(null));
-    }
-
-    QueryResult<?> evaluate(final FlowFile flowFile) {
-        return evaluate(createExpressionMap(flowFile));
-    }
-
-    QueryResult<?> evaluate(final Map<String, String> attributes) {
+    QueryResult<?> evaluate(final VariableRegistry registry) {
         if (evaluated.getAndSet(true)) {
             throw new IllegalStateException("A Query cannot be evaluated more than once");
         }
 
-        return evaluator.evaluate(attributes);
+        return evaluator.evaluate(registry.getVariables());
     }
 
     Tree getTree() {

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardAttributeExpression.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardAttributeExpression.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardAttributeExpression.java
index 49ef6ef..1e18953 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardAttributeExpression.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardAttributeExpression.java
@@ -20,13 +20,17 @@ import org.apache.nifi.expression.AttributeExpression;
 import org.apache.nifi.expression.AttributeValueDecorator;
 import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.registry.VariableRegistry;
+import org.apache.nifi.registry.VariableRegistryUtils;
 
 public class StandardAttributeExpression implements AttributeExpression {
 
     private final Query query;
+    private final VariableRegistry variableRegistry;
 
-    public StandardAttributeExpression(final Query query) {
+    public StandardAttributeExpression(final Query query, final VariableRegistry variableRegistry) {
         this.query = query;
+        this.variableRegistry = variableRegistry;
     }
 
     @Override
@@ -51,7 +55,8 @@ public class StandardAttributeExpression implements AttributeExpression {
 
     @Override
     public String evaluate(final FlowFile flowFile, final AttributeValueDecorator decorator) throws ProcessException {
-        final Object evaluationResult = query.evaluate(flowFile).getValue();
+        VariableRegistry flowFileRegistry = VariableRegistryUtils.createFlowVariableRegistry(variableRegistry,flowFile,null);
+        final Object evaluationResult = query.evaluate(flowFileRegistry).getValue();
         if (evaluationResult == null) {
             return "";
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardExpressionLanguageCompiler.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardExpressionLanguageCompiler.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardExpressionLanguageCompiler.java
index cec73d1..e85853f 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardExpressionLanguageCompiler.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardExpressionLanguageCompiler.java
@@ -20,13 +20,20 @@ import org.apache.nifi.attribute.expression.language.exception.AttributeExpressi
 import org.apache.nifi.expression.AttributeExpression;
 import org.apache.nifi.expression.ExpressionLanguageCompiler;
 import org.apache.nifi.expression.AttributeExpression.ResultType;
+import org.apache.nifi.registry.VariableRegistry;
 
 public class StandardExpressionLanguageCompiler implements ExpressionLanguageCompiler {
 
+    private final VariableRegistry variableRegistry;
+
+    public StandardExpressionLanguageCompiler(final VariableRegistry variableRegistry) {
+        this.variableRegistry = variableRegistry;
+    }
+
     @Override
     public AttributeExpression compile(final String expression) throws IllegalArgumentException {
         try {
-            return new StandardAttributeExpression(Query.compile(expression));
+            return new StandardAttributeExpression(Query.compile(expression),variableRegistry);
         } catch (final AttributeExpressionLanguageParsingException e) {
             throw new IllegalArgumentException(e.getMessage());
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/8412d266/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPreparedQuery.java
----------------------------------------------------------------------
diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPreparedQuery.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPreparedQuery.java
index b81a583..4ee3e02 100644
--- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPreparedQuery.java
+++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/StandardPreparedQuery.java
@@ -22,10 +22,10 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.nifi.expression.AttributeValueDecorator;
-import org.apache.nifi.flowfile.FlowFile;
 import org.apache.nifi.processor.exception.ProcessException;
 
 import org.antlr.runtime.tree.Tree;
+import org.apache.nifi.registry.VariableRegistry;
 
 public class StandardPreparedQuery implements PreparedQuery {
 
@@ -37,20 +37,16 @@ public class StandardPreparedQuery implements PreparedQuery {
         this.trees = new HashMap<>(trees);
     }
 
-    @Override
-    public String evaluateExpressions(Map<String, String> attributes) throws ProcessException {
-        return evaluateExpressions(attributes, null);
-    }
 
     @Override
-    public String evaluateExpressions(final Map<String, String> attributes, final AttributeValueDecorator decorator) throws ProcessException {
+    public String evaluateExpressions(final VariableRegistry registry, final AttributeValueDecorator decorator) throws ProcessException {
         final StringBuilder sb = new StringBuilder();
         for (final String val : queryStrings) {
             final Tree tree = trees.get(val);
             if (tree == null) {
                 sb.append(val);
             } else {
-                final String evaluated = Query.evaluateExpression(tree, val, attributes, decorator);
+                final String evaluated = Query.evaluateExpression(tree, val, registry, decorator);
                 if (evaluated != null) {
                     sb.append(evaluated);
                 }
@@ -59,31 +55,4 @@ public class StandardPreparedQuery implements PreparedQuery {
         return sb.toString();
     }
 
-    @Override
-    public String evaluateExpressions(final FlowFile flowFile, final Map<String, String> additionalAttributes, final AttributeValueDecorator decorator) throws ProcessException {
-        final Map<String, String> expressionMap = Query.createExpressionMap(flowFile, additionalAttributes);
-        return evaluateExpressions(expressionMap, decorator);
-    }
-
-    @Override
-    public String evaluateExpressions(final FlowFile flowFile, final AttributeValueDecorator decorator) throws ProcessException {
-        final Map<String, String> expressionMap = Query.createExpressionMap(flowFile);
-        return evaluateExpressions(expressionMap, decorator);
-    }
-
-    @Override
-    public String evaluateExpressions() throws ProcessException {
-        return evaluateExpressions((FlowFile) null, null);
-    }
-
-    @Override
-    public String evaluateExpressions(final AttributeValueDecorator decorator) throws ProcessException {
-        return evaluateExpressions((FlowFile) null, decorator);
-    }
-
-    @Override
-    public String evaluateExpressions(final FlowFile flowFile) throws ProcessException {
-        return evaluateExpressions(flowFile, null);
-    }
-
 }