Repository: nifi
Updated Branches:
  refs/heads/master c72a9aa54 -> 36846e0fe


NIFI-2719: - Caching components recently added/removed in case ajax requests 
are received out of order. This is not an issue for modifications of existing 
components as we're able to leverage the revision.

This closes #1011.

Signed-off-by: Bryan Bende <[email protected]>


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

Branch: refs/heads/master
Commit: 36846e0fe77b06a34a3fcf99af78c64ab7ecf16e
Parents: c72a9aa
Author: Matt Gilman <[email protected]>
Authored: Tue Sep 13 09:19:29 2016 -0400
Committer: Bryan Bende <[email protected]>
Committed: Wed Sep 14 10:33:10 2016 -0400

----------------------------------------------------------------------
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   |  3 ++
 .../main/webapp/js/nf/canvas/nf-connection.js   | 56 ++++++++++++++++----
 .../src/main/webapp/js/nf/canvas/nf-funnel.js   | 56 ++++++++++++++++----
 .../src/main/webapp/js/nf/canvas/nf-graph.js    | 20 +++++++
 .../src/main/webapp/js/nf/canvas/nf-label.js    | 56 ++++++++++++++++----
 .../src/main/webapp/js/nf/canvas/nf-port.js     | 56 ++++++++++++++++----
 .../webapp/js/nf/canvas/nf-process-group.js     | 56 ++++++++++++++++----
 .../main/webapp/js/nf/canvas/nf-processor.js    | 56 ++++++++++++++++----
 .../js/nf/canvas/nf-remote-process-group.js     | 56 ++++++++++++++++----
 9 files changed, 345 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
index 316e080..7ae1353 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas.js
@@ -615,6 +615,8 @@ nf.Canvas = (function () {
      * @argument {object} options               Configuration options
      */
     var reloadProcessGroup = function (processGroupId, options) {
+        var now = new Date().getTime();
+
         // load the controller
         return $.ajax({
             type: 'GET',
@@ -654,6 +656,7 @@ nf.Canvas = (function () {
             }
 
             // refresh the graph
+            nf.Graph.expireCaches(now);
             nf.Graph.set(processGroupFlow.flow, $.extend({
                 'selectAll': false
             }, options));

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js
index b94026c..4242c69 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection.js
@@ -58,6 +58,13 @@ nf.Connection = (function () {
 
     var connectionMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // ---------------------
     // connection containers
     // ---------------------
@@ -1201,6 +1208,8 @@ nf.Connection = (function () {
 
         init: function () {
             connectionMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the connection container
             connectionContainer = d3.select('#canvas').append('g')
@@ -1543,7 +1552,12 @@ nf.Connection = (function () {
                 selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? 
options.selectAll : selectAll;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (connectionEntity) {
+                addedCache.set(connectionEntity.id, now);
+
                 // add the connection
                 connectionMap.set(connectionEntity.id, $.extend({
                     type: 'Connection'
@@ -1585,8 +1599,8 @@ nf.Connection = (function () {
             var set = function (proposedConnectionEntity) {
                 var currentConnectionEntity = 
connectionMap.get(proposedConnectionEntity.id);
 
-                // set the connection if appropriate
-                if (nf.Client.isNewerRevision(currentConnectionEntity, 
proposedConnectionEntity)) {
+                // set the connection if appropriate due to revision and 
wasn't previously removed
+                if (nf.Client.isNewerRevision(currentConnectionEntity, 
proposedConnectionEntity) && !removedCache.has(proposedConnectionEntity.id)) {
                     connectionMap.set(proposedConnectionEntity.id, $.extend({
                         type: 'Connection'
                     }, proposedConnectionEntity));
@@ -1601,8 +1615,8 @@ nf.Connection = (function () {
                         return proposedConnectionEntity.id === 
currentConnectionEntity.id;
                     });
 
-                    // if the current connection is not present, remove it
-                    if (isPresent.length === 0) {
+                    // if the current connection is not present and was not 
recently added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         connectionMap.remove(key);
                     }
                 });
@@ -1663,15 +1677,19 @@ nf.Connection = (function () {
         /**
          * Removes the specified connection.
          *
-         * @param {array|string} connections      The connection id
+         * @param {array|string} connectionIds      The connection id
          */
-        remove: function (connections) {
-            if ($.isArray(connections)) {
-                $.each(connections, function (_, connection) {
-                    connectionMap.remove(connection);
+        remove: function (connectionIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(connectionIds)) {
+                $.each(connectionIds, function (_, connectionId) {
+                    removedCache.set(connectionId, now);
+                    connectionMap.remove(connectionId);
                 });
             } else {
-                connectionMap.remove(connections);
+                removedCache.set(connectionIds, now);
+                connectionMap.remove(connectionIds);
             }
 
             // apply the selection and handle all removed connections
@@ -1732,6 +1750,24 @@ nf.Connection = (function () {
             } else {
                 return connectionMap.get(id);
             }
+        },
+
+        /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
         }
     };
 }());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js
index e9f8caa..543cd6d 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-funnel.js
@@ -30,6 +30,13 @@ nf.Funnel = (function () {
 
     var funnelMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // --------------------
     // component containers
     // --------------------
@@ -160,6 +167,8 @@ nf.Funnel = (function () {
          */
         init: function () {
             funnelMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the funnel container
             funnelContainer = d3.select('#canvas').append('g')
@@ -181,7 +190,12 @@ nf.Funnel = (function () {
                 selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? 
options.selectAll : selectAll;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (funnelEntity) {
+                addedCache.set(funnelEntity.id, now);
+
                 // add the funnel
                 funnelMap.set(funnelEntity.id, $.extend({
                     type: 'Funnel',
@@ -221,8 +235,8 @@ nf.Funnel = (function () {
             var set = function (proposedFunnelEntity) {
                 var currentFunnelEntity = 
funnelMap.get(proposedFunnelEntity.id);
 
-                // set the funnel if appropriate
-                if (nf.Client.isNewerRevision(currentFunnelEntity, 
proposedFunnelEntity)) {
+                // set the funnel if appropriate due to revision and wasn't 
previously removed
+                if (nf.Client.isNewerRevision(currentFunnelEntity, 
proposedFunnelEntity) && !removedCache.has(proposedFunnelEntity.id)) {
                     funnelMap.set(proposedFunnelEntity.id, $.extend({
                         type: 'Funnel',
                         dimensions: dimensions
@@ -237,8 +251,8 @@ nf.Funnel = (function () {
                         return proposedFunnelEntity.id === 
currentFunnelEntity.id;
                     });
 
-                    // if the current funnel is not present, remove it
-                    if (isPresent.length === 0) {
+                    // if the current funnel is not present and was not 
recently added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         funnelMap.remove(key);
                     }
                 });
@@ -315,15 +329,19 @@ nf.Funnel = (function () {
         /**
          * Removes the specified funnel.
          *
-         * @param {array|string} funnels      The funnel id
+         * @param {array|string} funnelIds      The funnel id
          */
-        remove: function (funnels) {
-            if ($.isArray(funnels)) {
-                $.each(funnels, function (_, funnel) {
-                    funnelMap.remove(funnel);
+        remove: function (funnelIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(funnelIds)) {
+                $.each(funnelIds, function (_, funnelId) {
+                    removedCache.set(funnelId, now);
+                    funnelMap.remove(funnelId);
                 });
             } else {
-                funnelMap.remove(funnels);
+                removedCache.set(funnelIds, now);
+                funnelMap.remove(funnelIds);
             }
 
             // apply the selection and handle all removed funnels
@@ -335,6 +353,24 @@ nf.Funnel = (function () {
          */
         removeAll: function () {
             nf.Funnel.remove(funnelMap.keys());
+        },
+
+        /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
         }
     };
 }());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js
index 006def4..cf33394 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-graph.js
@@ -128,6 +128,26 @@ nf.Graph = (function () {
                 nf.ng.Bridge.digest();
             }
         },
+
+        /**
+         * Expires any caches prior to setting updated components via 
.set(...) above. This is necessary
+         * if an ajax request returns out of order. The caches will ensure 
that added/removed components
+         * will not be removed/added due to process group refreshes. Whether 
or not a component is present
+         * is ambiguous whether the request is from before the component was 
added/removed or if another
+         * client has legitimately removed/added it. Once a request is 
initiated after the component is
+         * added/removed we can remove the entry from the cache.
+         *
+         * @param timestamp expire caches before
+         */
+        expireCaches: function (timestamp) {
+            nf.Label.expireCaches(timestamp);
+            nf.Funnel.expireCaches(timestamp);
+            nf.RemoteProcessGroup.expireCaches(timestamp);
+            nf.Port.expireCaches(timestamp);
+            nf.ProcessGroup.expireCaches(timestamp);
+            nf.Processor.expireCaches(timestamp);
+            nf.Connection.expireCaches(timestamp);
+        },
         
         /**
          * Gets the components currently on the canvas.

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js
index 4fb40b6..1d73079 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label.js
@@ -33,6 +33,13 @@ nf.Label = (function () {
 
     var labelMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // --------------------
     // component containers
     // --------------------
@@ -262,6 +269,8 @@ nf.Label = (function () {
          */
         init: function () {
             labelMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the label container
             labelContainer = d3.select('#canvas').append('g')
@@ -363,7 +372,12 @@ nf.Label = (function () {
                 selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? 
options.selectAll : selectAll;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (labelEntity) {
+                addedCache.set(labelEntity.id, now);
+
                 // add the label
                 labelMap.set(labelEntity.id, $.extend({
                     type: 'Label'
@@ -402,8 +416,8 @@ nf.Label = (function () {
             var set = function (proposedLabelEntity) {
                 var currentLabelEntity = labelMap.get(proposedLabelEntity.id);
 
-                // set the processor if appropriate
-                if (nf.Client.isNewerRevision(currentLabelEntity, 
proposedLabelEntity)) {
+                // set the processor if appropriate due to revision and wasn't 
previously removed
+                if (nf.Client.isNewerRevision(currentLabelEntity, 
proposedLabelEntity) && !removedCache.has(proposedLabelEntity.id)) {
                     labelMap.set(proposedLabelEntity.id, $.extend({
                         type: 'Label'
                     }, proposedLabelEntity));
@@ -417,8 +431,8 @@ nf.Label = (function () {
                         return proposedLabelEntity.id === 
currentLabelEntity.id;
                     });
 
-                    // if the current label is not present, remove it
-                    if (isPresent.length === 0) {
+                    // if the current label is not present and was not 
recently added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         labelMap.remove(key);
                     }
                 });
@@ -495,15 +509,19 @@ nf.Label = (function () {
         /**
          * Removes the specified label.
          *
-         * @param {array|string} labels      The label id(s)
+         * @param {array|string} labelIds      The label id(s)
          */
-        remove: function (labels) {
-            if ($.isArray(labels)) {
-                $.each(labels, function (_, label) {
-                    labelMap.remove(label);
+        remove: function (labelIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(labelIds)) {
+                $.each(labelIds, function (_, labelId) {
+                    removedCache.set(labelId, now);
+                    labelMap.remove(labelId);
                 });
             } else {
-                labelMap.remove(labels);
+                removedCache.set(labelIds, now);
+                labelMap.remove(labelIds);
             }
 
             // apply the selection and handle all removed labels
@@ -518,6 +536,24 @@ nf.Label = (function () {
         },
 
         /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
+        },
+
+        /**
          * Returns the default color that should be used when drawing a label.
          */
         defaultColor: function () {

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js
index 622fcb9..5b58d44 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port.js
@@ -37,6 +37,13 @@ nf.Port = (function () {
 
     var portMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // --------------------
     // component containers
     // --------------------
@@ -467,6 +474,8 @@ nf.Port = (function () {
          */
         init: function () {
             portMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the port container
             portContainer = d3.select('#canvas').append('g')
@@ -494,7 +503,12 @@ nf.Port = (function () {
                 dimensions = remotePortDimensions;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (portEntity) {
+                addedCache.set(portEntity.id, now);
+
                 // add the port
                 portMap.set(portEntity.id, $.extend({
                     type: 'Port',
@@ -543,8 +557,8 @@ nf.Port = (function () {
             var set = function (proposedPortEntity) {
                 var currentPortEntity = portMap.get(proposedPortEntity.id);
 
-                // set the port if appropriate
-                if (nf.Client.isNewerRevision(currentPortEntity, 
proposedPortEntity)) {
+                // set the port if appropriate due to revision and wasn't 
previously removed
+                if (nf.Client.isNewerRevision(currentPortEntity, 
proposedPortEntity) && !removedCache.has(proposedPortEntity.id)) {
                     // add the port
                     portMap.set(proposedPortEntity.id, $.extend({
                         type: 'Port',
@@ -564,8 +578,8 @@ nf.Port = (function () {
                         return proposedPortEntity.id === currentPortEntity.id;
                     });
 
-                    // if the current port is not present, remove it
-                    if (isPresent.length === 0) {
+                    // if the current port is not present and was not recently 
added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         portMap.remove(key);
                     }
                 });
@@ -649,15 +663,19 @@ nf.Port = (function () {
         /**
          * Removes the specified port.
          *
-         * @param {string} ports      The port id(s)
+         * @param {string} portIds      The port id(s)
          */
-        remove: function (ports) {
-            if ($.isArray(ports)) {
-                $.each(ports, function (_, port) {
-                    portMap.remove(port);
+        remove: function (portIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(portIds)) {
+                $.each(portIds, function (_, portId) {
+                    removedCache.set(portId, now);
+                    portMap.remove(portId);
                 });
             } else {
-                portMap.remove(ports);
+                removedCache.set(portIds, now);
+                portMap.remove(portIds);
             }
 
             // apply the selection and handle all removed ports
@@ -669,6 +687,24 @@ nf.Port = (function () {
          */
         removeAll: function () {
             nf.Port.remove(portMap.keys());
+        },
+
+        /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
         }
     };
 }());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js
index c5f03be..80c7eec 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group.js
@@ -32,6 +32,13 @@ nf.ProcessGroup = (function () {
 
     var processGroupMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // --------------------
     // component containers
     // --------------------
@@ -960,6 +967,8 @@ nf.ProcessGroup = (function () {
          */
         init: function () {
             processGroupMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the process group container
             processGroupContainer = d3.select('#canvas').append('g')
@@ -981,7 +990,12 @@ nf.ProcessGroup = (function () {
                 selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? 
options.selectAll : selectAll;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (processGroupEntity) {
+                addedCache.set(processGroupEntity.id, now);
+
                 // add the process group
                 processGroupMap.set(processGroupEntity.id, $.extend({
                     type: 'ProcessGroup',
@@ -1021,8 +1035,8 @@ nf.ProcessGroup = (function () {
             var set = function (proposedProcessGroupEntity) {
                 var currentProcessGroupEntity = 
processGroupMap.get(proposedProcessGroupEntity.id);
 
-                // set the process group if appropriate
-                if (nf.Client.isNewerRevision(currentProcessGroupEntity, 
proposedProcessGroupEntity)) {
+                // set the process group if appropriate due to revision and 
wasn't previously removed
+                if (nf.Client.isNewerRevision(currentProcessGroupEntity, 
proposedProcessGroupEntity) && 
!removedCache.has(proposedProcessGroupEntity.id)) {
                     processGroupMap.set(proposedProcessGroupEntity.id, 
$.extend({
                         type: 'ProcessGroup',
                         dimensions: dimensions
@@ -1038,8 +1052,8 @@ nf.ProcessGroup = (function () {
                         return proposedProcessGroupEntity.id === 
currentProcessGroupEntity.id;
                     });
 
-                    // if the current process group is not present, remove it
-                    if (isPresent.length === 0) {
+                    // if the current process group is not present and was not 
recently added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         processGroupMap.remove(key);
                     }
                 });
@@ -1123,15 +1137,19 @@ nf.ProcessGroup = (function () {
         /**
          * Removes the specified process group.
          *
-         * @param {string} processGroups      The process group id(s)
+         * @param {string} processGroupIds      The process group id(s)
          */
-        remove: function (processGroups) {
-            if ($.isArray(processGroups)) {
-                $.each(processGroups, function (_, processGroup) {
-                    processGroupMap.remove(processGroup);
+        remove: function (processGroupIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(processGroupIds)) {
+                $.each(processGroupIds, function (_, processGroupId) {
+                    removedCache.set(processGroupId, now);
+                    processGroupMap.remove(processGroupId);
                 });
             } else {
-                processGroupMap.remove(processGroups);
+                removedCache.set(processGroupIds, now);
+                processGroupMap.remove(processGroupIds);
             }
 
             // apply the selection and handle all removed process groups
@@ -1143,6 +1161,24 @@ nf.ProcessGroup = (function () {
          */
         removeAll: function () {
             nf.ProcessGroup.remove(processGroupMap.keys());
+        },
+
+        /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
         }
     };
 }());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
index 67aa4d8..183d1b5 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor.js
@@ -33,6 +33,13 @@ nf.Processor = (function () {
 
     var processorMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // --------------------
     // component containers
     // --------------------
@@ -733,6 +740,8 @@ nf.Processor = (function () {
          */
         init: function () {
             processorMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the processor container
             processorContainer = d3.select('#canvas').append('g')
@@ -754,7 +763,12 @@ nf.Processor = (function () {
                 selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? 
options.selectAll : selectAll;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (processorEntity) {
+                addedCache.set(processorEntity.id, now);
+
                 // add the processor
                 processorMap.set(processorEntity.id, $.extend({
                     type: 'Processor',
@@ -794,8 +808,8 @@ nf.Processor = (function () {
             var set = function (proposedProcessorEntity) {
                 var currentProcessorEntity = 
processorMap.get(proposedProcessorEntity.id);
 
-                // set the processor if appropriate
-                if (nf.Client.isNewerRevision(currentProcessorEntity, 
proposedProcessorEntity)) {
+                // set the processor if appropriate due to revision and wasn't 
previously removed
+                if (nf.Client.isNewerRevision(currentProcessorEntity, 
proposedProcessorEntity) && !removedCache.has(proposedProcessorEntity.id)) {
                     processorMap.set(proposedProcessorEntity.id, $.extend({
                         type: 'Processor',
                         dimensions: dimensions
@@ -811,8 +825,8 @@ nf.Processor = (function () {
                         return proposedProcessorEntity.id === 
currentProcessorEntity.id;
                     });
 
-                    // if the current processor is not present, remove it
-                    if (isPresent.length === 0) {
+                    // if the current processor is not present and was not 
recently added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         processorMap.remove(key);
                     }
                 });
@@ -896,15 +910,19 @@ nf.Processor = (function () {
         /**
          * Removes the specified processor.
          *
-         * @param {array|string} processors      The processors
+         * @param {array|string} processorIds      The processors
          */
-        remove: function (processors) {
-            if ($.isArray(processors)) {
-                $.each(processors, function (_, processor) {
-                    processorMap.remove(processor);
+        remove: function (processorIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(processorIds)) {
+                $.each(processorIds, function (_, processorId) {
+                    removedCache.set(processorId, now);
+                    processorMap.remove(processorId);
                 });
             } else {
-                processorMap.remove(processors);
+                removedCache.set(processorIds, now);
+                processorMap.remove(processorIds);
             }
 
             // apply the selection and handle all removed processors
@@ -919,6 +937,24 @@ nf.Processor = (function () {
         },
 
         /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
+        },
+
+        /**
          * Returns the default color that should be used when drawing a 
processor.
          */
         defaultColor: function () {

http://git-wip-us.apache.org/repos/asf/nifi/blob/36846e0f/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js
index 7d3afb5..39df01f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group.js
@@ -32,6 +32,13 @@ nf.RemoteProcessGroup = (function () {
 
     var remoteProcessGroupMap;
 
+    // -----------------------------------------------------------
+    // cache for components that are added/removed from the canvas
+    // -----------------------------------------------------------
+
+    var removedCache;
+    var addedCache;
+
     // --------------------
     // component containers
     // --------------------
@@ -814,6 +821,8 @@ nf.RemoteProcessGroup = (function () {
          */
         init: function () {
             remoteProcessGroupMap = d3.map();
+            removedCache = d3.map();
+            addedCache = d3.map();
 
             // create the process group container
             remoteProcessGroupContainer = d3.select('#canvas').append('g')
@@ -835,7 +844,12 @@ nf.RemoteProcessGroup = (function () {
                 selectAll = nf.Common.isDefinedAndNotNull(options.selectAll) ? 
options.selectAll : selectAll;
             }
 
+            // get the current time
+            var now = new Date().getTime();
+
             var add = function (remoteProcessGroupEntity) {
+                addedCache.set(remoteProcessGroupEntity.id, now);
+
                 // add the remote process group
                 remoteProcessGroupMap.set(remoteProcessGroupEntity.id, 
$.extend({
                     type: 'RemoteProcessGroup',
@@ -875,8 +889,8 @@ nf.RemoteProcessGroup = (function () {
             var set = function (proposedRemoteProcessGroupEntity) {
                 var currentRemoteProcessGroupEntity = 
remoteProcessGroupMap.get(proposedRemoteProcessGroupEntity.id);
 
-                // set the remote process group if appropriate
-                if (nf.Client.isNewerRevision(currentRemoteProcessGroupEntity, 
proposedRemoteProcessGroupEntity)) {
+                // set the remote process group if appropriate due to revision 
and wasn't previously removed
+                if (nf.Client.isNewerRevision(currentRemoteProcessGroupEntity, 
proposedRemoteProcessGroupEntity) && 
!removedCache.has(proposedRemoteProcessGroupEntity.id)) {
                     
remoteProcessGroupMap.set(proposedRemoteProcessGroupEntity.id, $.extend({
                         type: 'RemoteProcessGroup',
                         dimensions: dimensions
@@ -892,8 +906,8 @@ nf.RemoteProcessGroup = (function () {
                         return proposedRemoteProcessGroupEntity.id === 
currentRemoteProcessGroupEntity.id;
                     });
 
-                    // if the current remote process group is not present, 
remove it
-                    if (isPresent.length === 0) {
+                    // if the current remote process group is not present and 
was not recently added, remove it
+                    if (isPresent.length === 0 && !addedCache.has(key)) {
                         remoteProcessGroupMap.remove(key);
                     }
                 });
@@ -985,15 +999,19 @@ nf.RemoteProcessGroup = (function () {
         /**
          * Removes the specified process group.
          *
-         * @param {array|string} remoteProcessGroups      The remote process 
group id(s)
+         * @param {array|string} remoteProcessGroupIds      The remote process 
group id(s)
          */
-        remove: function (remoteProcessGroups) {
-            if ($.isArray(remoteProcessGroups)) {
-                $.each(remoteProcessGroups, function (_, remoteProcessGroup) {
-                    remoteProcessGroupMap.remove(remoteProcessGroup);
+        remove: function (remoteProcessGroupIds) {
+            var now = new Date().getTime();
+
+            if ($.isArray(remoteProcessGroupIds)) {
+                $.each(remoteProcessGroupIds, function (_, 
remoteProcessGroupId) {
+                    removedCache.set(remoteProcessGroupId, now);
+                    remoteProcessGroupMap.remove(remoteProcessGroupId);
                 });
             } else {
-                remoteProcessGroupMap.remove(remoteProcessGroups);
+                removedCache.set(remoteProcessGroupIds, now);
+                remoteProcessGroupMap.remove(remoteProcessGroupIds);
             }
 
             // apply the selection and handle all removed remote process groups
@@ -1005,6 +1023,24 @@ nf.RemoteProcessGroup = (function () {
          */
         removeAll: function () {
             nf.RemoteProcessGroup.remove(remoteProcessGroupMap.keys());
+        },
+
+        /**
+         * Expires the caches up to the specified timestamp.
+         *
+         * @param timestamp
+         */
+        expireCaches: function (timestamp) {
+            var expire = function (cache) {
+                cache.forEach(function (id, entryTimestamp) {
+                    if (timestamp > entryTimestamp) {
+                        cache.remove(id);
+                    }
+                });
+            };
+
+            expire(addedCache);
+            expire(removedCache);
         }
     };
 }());
\ No newline at end of file

Reply via email to