You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by mc...@apache.org on 2016/04/29 22:32:14 UTC

[01/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Repository: nifi
Updated Branches:
  refs/heads/master a4409d366 -> ff98d823e


http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 dd7454b..27fa461 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
@@ -59,9 +59,7 @@ nf.RemoteProcessGroup = (function () {
      * Selects the remote process group elements against the current remote process group map.
      */
     var select = function () {
-        return remoteProcessGroupContainer.selectAll('g.remote-process-group').data(remoteProcessGroupMap.values(), function (d) {
-            return d.component.id;
-        });
+        return remoteProcessGroupContainer.selectAll('g.remote-process-group').data(remoteProcessGroupMap.values());
     };
 
     /**
@@ -78,7 +76,7 @@ nf.RemoteProcessGroup = (function () {
         var remoteProcessGroup = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': 'remote-process-group component'
                 })
@@ -153,9 +151,9 @@ nf.RemoteProcessGroup = (function () {
         remoteProcessGroup.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
 
         // only support dragging and connecting when appropriate
-        if (nf.Common.isDFM()) {
-            remoteProcessGroup.call(nf.Draggable.activate).call(nf.Connectable.activate);
-        }
+        remoteProcessGroup.filter(function (d) {
+            return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+        }).call(nf.Draggable.activate).call(nf.Connectable.activate);
 
         // call update to trigger some rendering
         remoteProcessGroup.call(updateRemoteProcessGroups);
@@ -174,7 +172,7 @@ nf.RemoteProcessGroup = (function () {
             return;
         }
 
-        updated.each(function () {
+        updated.each(function (remoteProcessGroupData) {
             var remoteProcessGroup = d3.select(this);
             var details = remoteProcessGroup.select('g.remote-process-group-details');
 
@@ -205,28 +203,30 @@ nf.RemoteProcessGroup = (function () {
                                 'y': 23
                             });
 
-                    // remote process group uri
-                    details.append('text')
-                            .attr({
-                                'x': 25,
-                                'y': 32,
-                                'width': 305,
-                                'height': 12,
-                                'font-size': '8pt',
-                                'fill': '#91b9ce',
-                                'class': 'remote-process-group-uri'
-                            })
-                            .each(function (d) {
-                                var remoteProcessGroupUri = d3.select(this);
-
-                                // reset the remote process group name to handle any previous state
-                                remoteProcessGroupUri.text(null).selectAll('title').remove();
-
-                                // apply ellipsis to the remote process group name as necessary
-                                nf.CanvasUtils.ellipsis(remoteProcessGroupUri, d.component.targetUri);
-                            }).append('title').text(function (d) {
-                        return d.component.name;
-                    });
+                    if (remoteProcessGroupData.accessPolicy.canRead) {
+                        // remote process group uri
+                        details.append('text')
+                                .attr({
+                                    'x': 25,
+                                    'y': 32,
+                                    'width': 305,
+                                    'height': 12,
+                                    'font-size': '8pt',
+                                    'fill': '#91b9ce',
+                                    'class': 'remote-process-group-uri'
+                                })
+                                .each(function (d) {
+                                    var remoteProcessGroupUri = d3.select(this);
+
+                                    // reset the remote process group name to handle any previous state
+                                    remoteProcessGroupUri.text(null).selectAll('title').remove();
+
+                                    // apply ellipsis to the remote process group name as necessary
+                                    nf.CanvasUtils.ellipsis(remoteProcessGroupUri, d.component.targetUri);
+                                }).append('title').text(function (d) {
+                            return d.component.name;
+                        });
+                    }
 
                     // ----------------
                     // stats background
@@ -282,116 +282,118 @@ nf.RemoteProcessGroup = (function () {
                     // contents
                     // --------
 
-                    // input ports icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconInputPortSmall.png',
-                                'width': 16,
-                                'height': 16,
-                                'x': 10,
-                                'y': 41
-                            });
-
-                    // input ports count
-                    details.append('text')
-                            .attr({
-                                'x': 30,
-                                'y': 53,
-                                'class': 'remote-process-group-input-port-count process-group-contents-count'
-                            });
-
-                    // input transmitting icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconTransmissionActive.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 41,
-                                'class': 'remote-process-group-input-transmitting'
-                            });
-
-                    // input transmitting count
-                    details.append('text')
-                            .attr({
-                                'y': 53,
-                                'class': 'remote-process-group-input-transmitting-count process-group-contents-count'
-                            });
-
-                    // input not transmitting icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconTransmissionInactive.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 41,
-                                'class': 'remote-process-group-input-not-transmitting'
-                            });
-
-                    // input not transmitting count
-                    details.append('text')
-                            .attr({
-                                'y': 53,
-                                'class': 'remote-process-group-input-not-transmitting-count process-group-contents-count'
-                            });
-
-                    // output ports icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconOutputPortSmall.png',
-                                'width': 16,
-                                'height': 16,
-                                'x': 186,
-                                'y': 41,
-                                'class': 'remote-process-group-output-port'
-                            });
-
-                    // output ports count
-                    details.append('text')
-                            .attr({
-                                'x': 206,
-                                'y': 53,
-                                'class': 'remote-process-group-output-port-count process-group-contents-count'
-                            });
-
-                    // output transmitting icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconTransmissionActive.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 41,
-                                'class': 'remote-process-group-output-transmitting'
-                            });
-
-                    // output transmitting count
-                    details.append('text')
-                            .attr({
-                                'y': 53,
-                                'class': 'remote-process-group-output-transmitting-count process-group-contents-count'
-                            });
-
-                    // output not transmitting icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconTransmissionInactive.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 41,
-                                'class': 'remote-process-group-output-not-transmitting'
-                            });
-
-                    // output not transmitting count
-                    details.append('text')
-                            .attr({
-                                'y': 53,
-                                'class': 'remote-process-group-output-not-transmitting-count process-group-contents-count'
-                            });
+                    if (remoteProcessGroupData.accessPolicy.canRead) {
+                        // input ports icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconInputPortSmall.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'x': 10,
+                                    'y': 41
+                                });
+
+                        // input ports count
+                        details.append('text')
+                                .attr({
+                                    'x': 30,
+                                    'y': 53,
+                                    'class': 'remote-process-group-input-port-count process-group-contents-count'
+                                });
+
+                        // input transmitting icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconTransmissionActive.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 41,
+                                    'class': 'remote-process-group-input-transmitting'
+                                });
+
+                        // input transmitting count
+                        details.append('text')
+                                .attr({
+                                    'y': 53,
+                                    'class': 'remote-process-group-input-transmitting-count process-group-contents-count'
+                                });
+
+                        // input not transmitting icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconTransmissionInactive.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 41,
+                                    'class': 'remote-process-group-input-not-transmitting'
+                                });
+
+                        // input not transmitting count
+                        details.append('text')
+                                .attr({
+                                    'y': 53,
+                                    'class': 'remote-process-group-input-not-transmitting-count process-group-contents-count'
+                                });
+
+                        // output ports icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconOutputPortSmall.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'x': 186,
+                                    'y': 41,
+                                    'class': 'remote-process-group-output-port'
+                                });
+
+                        // output ports count
+                        details.append('text')
+                                .attr({
+                                    'x': 206,
+                                    'y': 53,
+                                    'class': 'remote-process-group-output-port-count process-group-contents-count'
+                                });
+
+                        // output transmitting icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconTransmissionActive.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 41,
+                                    'class': 'remote-process-group-output-transmitting'
+                                });
+
+                        // output transmitting count
+                        details.append('text')
+                                .attr({
+                                    'y': 53,
+                                    'class': 'remote-process-group-output-transmitting-count process-group-contents-count'
+                                });
+
+                        // output not transmitting icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconTransmissionInactive.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 41,
+                                    'class': 'remote-process-group-output-not-transmitting'
+                                });
+
+                        // output not transmitting count
+                        details.append('text')
+                                .attr({
+                                    'y': 53,
+                                    'class': 'remote-process-group-output-not-transmitting-count process-group-contents-count'
+                                });
+                    }
 
                     // -----
                     // stats
@@ -545,179 +547,181 @@ nf.RemoteProcessGroup = (function () {
                             });
                 }
 
-                // update the process groups transmission status
-                details.select('image.remote-process-group-transmission-secure')
-                        .attr('xlink:href', function (d) {
-                            var img = '';
-                            if (d.component.targetSecure === true) {
-                                img = 'images/iconSecure.png';
-                            } else {
-                                img = 'images/iconNotSecure.png';
-                            }
-                            return img;
-                        })
-                        .each(function (d) {
-                            // remove the existing tip if necessary
-                            var tip = d3.select('#transmission-secure-' + d.component.id);
-                            if (!tip.empty()) {
-                                tip.remove();
-                            }
-
-                            tip = d3.select('#remote-process-group-tooltips').append('div')
-                                    .attr('id', function () {
-                                        return 'transmission-secure-' + d.component.id;
-                                    })
-                                    .attr('class', 'tooltip nifi-tooltip')
-                                    .text(function () {
-                                        if (d.component.targetSecure === true) {
-                                            return 'Site-to-Site is secure.';
-                                        } else {
-                                            return 'Site-to-Site is NOT secure.';
-                                        }
-                                    });
-
-                            // add the tooltip
-                            nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
-                        });
-
-                // ----------------------
-                // update the input ports
-                // ----------------------
+                if (remoteProcessGroupData.accessPolicy.canRead) {
+                    // update the process groups transmission status
+                    details.select('image.remote-process-group-transmission-secure')
+                            .attr('xlink:href', function (d) {
+                                var img = '';
+                                if (d.component.targetSecure === true) {
+                                    img = 'images/iconSecure.png';
+                                } else {
+                                    img = 'images/iconNotSecure.png';
+                                }
+                                return img;
+                            })
+                            .each(function (d) {
+                                // remove the existing tip if necessary
+                                var tip = d3.select('#transmission-secure-' + d.id);
+                                if (!tip.empty()) {
+                                    tip.remove();
+                                }
+
+                                tip = d3.select('#remote-process-group-tooltips').append('div')
+                                        .attr('id', function () {
+                                            return 'transmission-secure-' + d.id;
+                                        })
+                                        .attr('class', 'tooltip nifi-tooltip')
+                                        .text(function () {
+                                            if (d.component.targetSecure === true) {
+                                                return 'Site-to-Site is secure.';
+                                            } else {
+                                                return 'Site-to-Site is NOT secure.';
+                                            }
+                                        });
+
+                                // add the tooltip
+                                nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
+                            });
 
-                // input port count
-                details.select('text.remote-process-group-input-port-count')
-                        .text(function (d) {
-                            return d.component.inputPortCount;
-                        });
+                    // ----------------------
+                    // update the input ports
+                    // ----------------------
 
-                // get the input port container to help right align
-                var inputContainer = details.select('rect.remote-process-group-input-container');
+                    // input port count
+                    details.select('text.remote-process-group-input-port-count')
+                            .text(function (d) {
+                                return d.component.inputPortCount;
+                            });
 
-                // update input not transmitting
-                var inputNotTransmittingCount = details.select('text.remote-process-group-input-not-transmitting-count')
-                        .text(function (d) {
-                            return d.component.inactiveRemoteInputPortCount;
-                        })
-                        .attr('x', function () {
-                            var containerX = parseInt(inputContainer.attr('x'), 10);
-                            var containerWidth = parseInt(inputContainer.attr('width'), 10);
-                            return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var inputNotTransmitting = details.select('image.remote-process-group-input-not-transmitting')
-                        .attr('x', function () {
-                            var inputNotTransmittingCountX = parseInt(inputNotTransmittingCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return inputNotTransmittingCountX - width - CONTENTS_SPACER;
-                        });
+                    // get the input port container to help right align
+                    var inputContainer = details.select('rect.remote-process-group-input-container');
 
-                // update input transmitting
-                var inputTransmittingCount = details.select('text.remote-process-group-input-transmitting-count')
-                        .text(function (d) {
-                            return d.component.activeRemoteInputPortCount;
-                        })
-                        .attr('x', function () {
-                            var inputNotTransmittingX = parseInt(inputNotTransmitting.attr('x'), 10);
-                            return inputNotTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                details.select('image.remote-process-group-input-transmitting')
-                        .attr('x', function () {
-                            var inputTransmittingCountX = parseInt(inputTransmittingCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return inputTransmittingCountX - width - CONTENTS_SPACER;
-                        });
+                    // update input not transmitting
+                    var inputNotTransmittingCount = details.select('text.remote-process-group-input-not-transmitting-count')
+                            .text(function (d) {
+                                return d.component.inactiveRemoteInputPortCount;
+                            })
+                            .attr('x', function () {
+                                var containerX = parseInt(inputContainer.attr('x'), 10);
+                                var containerWidth = parseInt(inputContainer.attr('width'), 10);
+                                return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var inputNotTransmitting = details.select('image.remote-process-group-input-not-transmitting')
+                            .attr('x', function () {
+                                var inputNotTransmittingCountX = parseInt(inputNotTransmittingCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return inputNotTransmittingCountX - width - CONTENTS_SPACER;
+                            });
 
-                // -----------------------
-                // update the output ports
-                // -----------------------
+                    // update input transmitting
+                    var inputTransmittingCount = details.select('text.remote-process-group-input-transmitting-count')
+                            .text(function (d) {
+                                return d.component.activeRemoteInputPortCount;
+                            })
+                            .attr('x', function () {
+                                var inputNotTransmittingX = parseInt(inputNotTransmitting.attr('x'), 10);
+                                return inputNotTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    details.select('image.remote-process-group-input-transmitting')
+                            .attr('x', function () {
+                                var inputTransmittingCountX = parseInt(inputTransmittingCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return inputTransmittingCountX - width - CONTENTS_SPACER;
+                            });
 
-                // output port count
-                details.select('text.remote-process-group-output-port-count')
-                        .text(function (d) {
-                            return d.component.outputPortCount;
-                        });
+                    // -----------------------
+                    // update the output ports
+                    // -----------------------
 
-                // get the output port container to help right align
-                var outputContainer = details.select('rect.remote-process-group-output-container');
+                    // output port count
+                    details.select('text.remote-process-group-output-port-count')
+                            .text(function (d) {
+                                return d.component.outputPortCount;
+                            });
 
-                // update input not transmitting
-                var outputNotTransmittingCount = details.select('text.remote-process-group-output-not-transmitting-count')
-                        .text(function (d) {
-                            return d.component.inactiveRemoteOutputPortCount;
-                        })
-                        .attr('x', function () {
-                            var containerX = parseInt(outputContainer.attr('x'), 10);
-                            var containerWidth = parseInt(outputContainer.attr('width'), 10);
-                            return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var outputNotTransmitting = details.select('image.remote-process-group-output-not-transmitting')
-                        .attr('x', function () {
-                            var outputNotTransmittingCountX = parseInt(outputNotTransmittingCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return outputNotTransmittingCountX - width - CONTENTS_SPACER;
-                        });
+                    // get the output port container to help right align
+                    var outputContainer = details.select('rect.remote-process-group-output-container');
 
-                // update output transmitting
-                var outputTransmittingCount = details.select('text.remote-process-group-output-transmitting-count')
-                        .text(function (d) {
-                            return d.component.activeRemoteOutputPortCount;
-                        })
-                        .attr('x', function () {
-                            var outputNotTransmittingX = parseInt(outputNotTransmitting.attr('x'), 10);
-                            return outputNotTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                details.select('image.remote-process-group-output-transmitting')
-                        .attr('x', function () {
-                            var outputTransmittingCountX = parseInt(outputTransmittingCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return outputTransmittingCountX - width - CONTENTS_SPACER;
-                        });
+                    // update input not transmitting
+                    var outputNotTransmittingCount = details.select('text.remote-process-group-output-not-transmitting-count')
+                            .text(function (d) {
+                                return d.component.inactiveRemoteOutputPortCount;
+                            })
+                            .attr('x', function () {
+                                var containerX = parseInt(outputContainer.attr('x'), 10);
+                                var containerWidth = parseInt(outputContainer.attr('width'), 10);
+                                return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var outputNotTransmitting = details.select('image.remote-process-group-output-not-transmitting')
+                            .attr('x', function () {
+                                var outputNotTransmittingCountX = parseInt(outputNotTransmittingCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return outputNotTransmittingCountX - width - CONTENTS_SPACER;
+                            });
 
-                // ---------------
-                // update comments
-                // ---------------
+                    // update output transmitting
+                    var outputTransmittingCount = details.select('text.remote-process-group-output-transmitting-count')
+                            .text(function (d) {
+                                return d.component.activeRemoteOutputPortCount;
+                            })
+                            .attr('x', function () {
+                                var outputNotTransmittingX = parseInt(outputNotTransmitting.attr('x'), 10);
+                                return outputNotTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    details.select('image.remote-process-group-output-transmitting')
+                            .attr('x', function () {
+                                var outputTransmittingCountX = parseInt(outputTransmittingCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return outputTransmittingCountX - width - CONTENTS_SPACER;
+                            });
 
-                // update the process group comments
-                details.select('text.remote-process-group-comments')
-                        .each(function (d) {
-                            var remoteProcessGroupComments = d3.select(this);
+                    // ---------------
+                    // update comments
+                    // ---------------
 
-                            // reset the processor name to handle any previous state
-                            remoteProcessGroupComments.text(null).selectAll('tspan, title').remove();
+                    // update the process group comments
+                    details.select('text.remote-process-group-comments')
+                            .each(function (d) {
+                                var remoteProcessGroupComments = d3.select(this);
 
-                            // apply ellipsis to the port name as necessary
-                            nf.CanvasUtils.multilineEllipsis(remoteProcessGroupComments, 2, getProcessGroupComments(d));
-                        }).classed('unset', function (d) {
-                    return nf.Common.isBlank(d.component.comments);
-                }).append('title').text(function (d) {
-                    return getProcessGroupComments(d);
-                });
+                                // reset the processor name to handle any previous state
+                                remoteProcessGroupComments.text(null).selectAll('tspan, title').remove();
 
-                // --------------
-                // last refreshed
-                // --------------
+                                // apply ellipsis to the port name as necessary
+                                nf.CanvasUtils.multilineEllipsis(remoteProcessGroupComments, 2, getProcessGroupComments(d));
+                            }).classed('unset', function (d) {
+                        return nf.Common.isBlank(d.component.comments);
+                    }).append('title').text(function (d) {
+                        return getProcessGroupComments(d);
+                    });
 
-                details.select('text.remote-process-group-last-refresh')
-                        .text(function (d) {
-                            if (nf.Common.isDefinedAndNotNull(d.component.flowRefreshed)) {
-                                return d.component.flowRefreshed;
-                            } else {
-                                return 'Remote flow not current';
-                            }
-                        });
+                    // --------------
+                    // last refreshed
+                    // --------------
+
+                    details.select('text.remote-process-group-last-refresh')
+                            .text(function (d) {
+                                if (nf.Common.isDefinedAndNotNull(d.component.flowRefreshed)) {
+                                    return d.component.flowRefreshed;
+                                } else {
+                                    return 'Remote flow not current';
+                                }
+                            });
 
-                // update the process group name
-                remoteProcessGroup.select('text.remote-process-group-name')
-                        .each(function (d) {
-                            var remoteProcessGroupName = d3.select(this);
+                    // update the process group name
+                    remoteProcessGroup.select('text.remote-process-group-name')
+                            .each(function (d) {
+                                var remoteProcessGroupName = d3.select(this);
 
-                            // reset the remote process group name to handle any previous state
-                            remoteProcessGroupName.text(null).selectAll('title').remove();
+                                // reset the remote process group name to handle any previous state
+                                remoteProcessGroupName.text(null).selectAll('title').remove();
 
-                            // apply ellipsis to the remote process group name as necessary
-                            nf.CanvasUtils.ellipsis(remoteProcessGroupName, d.component.name);
-                        }).append('title').text(function (d) {
-                    return d.component.name;
-                });
+                                // apply ellipsis to the remote process group name as necessary
+                                nf.CanvasUtils.ellipsis(remoteProcessGroupName, d.component.name);
+                            }).append('title').text(function (d) {
+                        return d.component.name;
+                    });
+                }
 
                 // show the preview
                 remoteProcessGroup.select('image.remote-process-group-preview').style('display', 'none');
@@ -725,16 +729,18 @@ nf.RemoteProcessGroup = (function () {
                 // populate the stats
                 remoteProcessGroup.call(updateProcessGroupStatus);
             } else {
-                // update the process group name
-                remoteProcessGroup.select('text.remote-process-group-name')
-                        .text(function (d) {
-                            var name = d.component.name;
-                            if (name.length > PREVIEW_NAME_LENGTH) {
-                                return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
-                            } else {
-                                return name;
-                            }
-                        });
+                if (remoteProcessGroupData.accessPolicy.canRead) {
+                    // update the process group name
+                    remoteProcessGroup.select('text.remote-process-group-name')
+                            .text(function (d) {
+                                var name = d.component.name;
+                                if (name.length > PREVIEW_NAME_LENGTH) {
+                                    return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
+                                } else {
+                                    return name;
+                                }
+                            });
+                }
 
                 // show the preview
                 remoteProcessGroup.select('image.remote-process-group-preview').style('display', 'block');
@@ -784,22 +790,25 @@ nf.RemoteProcessGroup = (function () {
         // authorization issues
         // --------------------
 
+        // TODO - only consider state from the status
         // update the process groups transmission status
         updated.select('image.remote-process-group-transmission-status')
             .attr('xlink:href', function (d) {
                 var img = '';
                 if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues)) {
                     img = 'images/iconAlert.png';
-                } else if (d.component.transmitting === true) {
-                    img = 'images/iconTransmissionActive.png';
-                } else {
-                    img = 'images/iconTransmissionInactive.png';
+                } else if (d.accessPolicy.canRead) {
+                    if (d.component.transmitting === true) {
+                        img = 'images/iconTransmissionActive.png';
+                    } else {
+                        img = 'images/iconTransmissionInactive.png';
+                    }
                 }
                 return img;
             })
             .each(function (d) {
                 // remove the existing tip if necessary
-                var tip = d3.select('#authorization-issues-' + d.component.id);
+                var tip = d3.select('#authorization-issues-' + d.id);
                 if (!tip.empty()) {
                     tip.remove();
                 }
@@ -808,7 +817,7 @@ nf.RemoteProcessGroup = (function () {
                 if (nf.Common.isDefinedAndNotNull(d.status) && !nf.Common.isEmpty(d.status.authorizationIssues)) {
                     tip = d3.select('#remote-process-group-tooltips').append('div')
                         .attr('id', function () {
-                            return 'authorization-issues-' + d.component.id;
+                            return 'authorization-issues-' + d.id;
                         })
                         .attr('class', 'tooltip nifi-tooltip')
                         .html(function () {
@@ -868,9 +877,9 @@ nf.RemoteProcessGroup = (function () {
     var removeTooltips = function (removed) {
         removed.each(function (d) {
             // remove any associated tooltips
-            $('#bulletin-tip-' + d.component.id).remove();
-            $('#authorization-issues-' + d.component.id).remove();
-            $('#transmission-secure-' + d.component.id).remove();
+            $('#bulletin-tip-' + d.id).remove();
+            $('#authorization-issues-' + d.id).remove();
+            $('#transmission-secure-' + d.id).remove();
         });
     };
 
@@ -892,28 +901,27 @@ nf.RemoteProcessGroup = (function () {
         /**
          * Populates the graph with the specified remote process groups.
          *
-         * @argument {object | array} remoteProcessGroups                   The remote process groups to add
+         * @argument {object | array} remoteProcessGroupEntities                   The remote process groups to add
          * @argument {boolean} selectAll                                    Whether or not to select the new contents
          */
-        add: function (remoteProcessGroups, selectAll) {
+        add: function (remoteProcessGroupEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
-            var add = function (remoteProcessGroup) {
+            var add = function (remoteProcessGroupEntity) {
                 // add the remote process group
-                remoteProcessGroupMap.set(remoteProcessGroup.id, {
+                remoteProcessGroupMap.set(remoteProcessGroupEntity.id, $.extend({
                     type: 'RemoteProcessGroup',
-                    component: remoteProcessGroup,
                     dimensions: dimensions
-                });
+                }, remoteProcessGroupEntity));
             };
 
             // determine how to handle the specified remote process groups
-            if ($.isArray(remoteProcessGroups)) {
-                $.each(remoteProcessGroups, function (_, remoteProcessGroup) {
-                    add(remoteProcessGroup);
+            if ($.isArray(remoteProcessGroupEntities)) {
+                $.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) {
+                    add(remoteProcessGroupEntity);
                 });
             } else {
-                add(remoteProcessGroups);
+                add(remoteProcessGroupEntities);
             }
 
             // apply the selection and handle all new remote process groups
@@ -968,7 +976,7 @@ nf.RemoteProcessGroup = (function () {
                     url: remoteProcessGroup.uri,
                     dataType: 'json'
                 }).done(function (response) {
-                    nf.RemoteProcessGroup.set(response.remoteProcessGroup);
+                    nf.RemoteProcessGroup.set(response);
 
                     // reload the group's connections
                     var connections = nf.Connection.getComponentConnections(remoteProcessGroup.id);
@@ -993,27 +1001,27 @@ nf.RemoteProcessGroup = (function () {
          * will set each remote process group. If it is not an array, it will
          * attempt to set the specified remote process group.
          *
-         * @param {object | array} remoteProcessGroups
+         * @param {object | array} remoteProcessGroupEntities
          */
-        set: function (remoteProcessGroups) {
-            var set = function (remoteProcessGroup) {
-                if (remoteProcessGroupMap.has(remoteProcessGroup.id)) {
+        set: function (remoteProcessGroupEntities) {
+            var set = function (remoteProcessGroupEntity) {
+                if (remoteProcessGroupMap.has(remoteProcessGroupEntity.id)) {
                     // update the current entry
-                    var remoteProcessGroupEntry = remoteProcessGroupMap.get(remoteProcessGroup.id);
-                    remoteProcessGroupEntry.component = remoteProcessGroup;
-
+                    var remoteProcessGroupEntry = remoteProcessGroupMap.get(remoteProcessGroupEntity.id);
+                    $.extend(remoteProcessGroupEntry, remoteProcessGroupEntity);
+                    
                     // update the remote process group in the UI
-                    d3.select('#id-' + remoteProcessGroup.id).call(updateRemoteProcessGroups);
+                    d3.select('#id-' + remoteProcessGroupEntry.id).call(updateRemoteProcessGroups);
                 }
             };
 
             // determine how to handle the specified remote process group
-            if ($.isArray(remoteProcessGroups)) {
-                $.each(remoteProcessGroups, function (_, remoteProcessGroup) {
-                    set(remoteProcessGroup);
+            if ($.isArray(remoteProcessGroupEntities)) {
+                $.each(remoteProcessGroupEntities, function (_, remoteProcessGroupEntity) {
+                    set(remoteProcessGroupEntity);
                 });
             } else {
-                set(remoteProcessGroups);
+                set(remoteProcessGroupEntities);
             }
         },
         
@@ -1040,13 +1048,6 @@ nf.RemoteProcessGroup = (function () {
         },
 
         /**
-         * Returns the entity key when marshalling an entity of this type.
-         */
-        getEntityKey: function (d) {
-            return 'remoteProcessGroup';
-        },
-        
-        /**
          * Removes the specified process group.
          *
          * @param {array|string} remoteProcessGroups      The remote process group id(s)

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-snippet.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-snippet.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-snippet.js
index ecea569..c2d82b7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-snippet.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-snippet.js
@@ -51,21 +51,21 @@ nf.Snippet = (function () {
                 var selected = d3.select(this);
 
                 if (nf.CanvasUtils.isProcessor(selected)) {
-                    snippet.processors.push(d.component.id);
+                    snippet.processors.push(d.id);
                 } else if (nf.CanvasUtils.isFunnel(selected)) {
-                    snippet.funnels.push(d.component.id);
+                    snippet.funnels.push(d.id);
                 } else if (nf.CanvasUtils.isLabel(selected)) {
-                    snippet.labels.push(d.component.id);
+                    snippet.labels.push(d.id);
                 } else if (nf.CanvasUtils.isInputPort(selected)) {
-                    snippet.inputPorts.push(d.component.id);
+                    snippet.inputPorts.push(d.id);
                 } else if (nf.CanvasUtils.isOutputPort(selected)) {
-                    snippet.outputPorts.push(d.component.id);
+                    snippet.outputPorts.push(d.id);
                 } else if (nf.CanvasUtils.isProcessGroup(selected)) {
-                    snippet.processGroups.push(d.component.id);
+                    snippet.processGroups.push(d.id);
                 } else if (nf.CanvasUtils.isRemoteProcessGroup(selected)) {
-                    snippet.remoteProcessGroups.push(d.component.id);
+                    snippet.remoteProcessGroups.push(d.id);
                 } else if (nf.CanvasUtils.isConnection(selected)) {
-                    snippet.connections.push(d.component.id);
+                    snippet.connections.push(d.id);
                 }
             });
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-connection-details.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-connection-details.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-connection-details.js
index f9702ef..fb80e48 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-connection-details.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-connection-details.js
@@ -51,7 +51,7 @@ nf.ConnectionDetails = (function () {
             url: '../nifi-api/processors/' + encodeURIComponent(source.id),
             dataType: 'json'
         }).done(function (response) {
-            var processor = response.processor;
+            var processor = response.component;
             var processorName = $('<div class="label"></div>').text(processor.name);
             var processorType = $('<div></div>').text(nf.Common.substringAfterLast(processor.type, '.'));
 
@@ -94,7 +94,7 @@ nf.ConnectionDetails = (function () {
             },
             dataType: 'json'
         }).done(function (response) {
-            var remoteProcessGroup = response.remoteProcessGroup;
+            var remoteProcessGroup = response.component;
 
             // populate source port details
             $('#read-only-connection-source-label').text('From output');
@@ -128,7 +128,7 @@ nf.ConnectionDetails = (function () {
                     },
                     dataType: 'json'
                 }).done(function (response) {
-                    var processGroup = response.processGroup;
+                    var processGroup = response.component;
 
                     // populate source port details
                     $('#read-only-connection-source-label').text('From output');
@@ -176,7 +176,7 @@ nf.ConnectionDetails = (function () {
                 url: '../nifi-api/processors/' + encodeURIComponent(destination.id),
                 dataType: 'json'
             }).done(function (response) {
-                var processor = response.processor;
+                var processor = response.component;
                 var processorName = $('<div class="label"></div>').text(processor.name);
                 var processorType = $('<div></div>').text(nf.Common.substringAfterLast(processor.type, '.'));
 
@@ -224,7 +224,7 @@ nf.ConnectionDetails = (function () {
             },
             dataType: 'json'
         }).done(function (response) {
-            var remoteProcessGroup = response.remoteProcessGroup;
+            var remoteProcessGroup = response.component;
 
             // populate source port details
             $('#read-only-connection-target-label').text('To input');
@@ -258,7 +258,7 @@ nf.ConnectionDetails = (function () {
                     },
                     dataType: 'json'
                 }).done(function (response) {
-                    var processGroup = response.processGroup;
+                    var processGroup = response.component;
 
                     // populate destination port details
                     $('#read-only-connection-target-label').text('To input');
@@ -384,8 +384,8 @@ nf.ConnectionDetails = (function () {
                 var connectionResponse = connectionResult[0];
 
                 if (nf.Common.isDefinedAndNotNull(groupResponse.processGroup) && nf.Common.isDefinedAndNotNull(connectionResponse.connection)) {
-                    var processGroup = groupResponse.processGroup;
-                    var connection = connectionResponse.connection;
+                    var processGroup = groupResponse.component;
+                    var connection = connectionResponse.component;
 
                     // process the source
                     var connectionSource = initializeConnectionSource(processGroup.id, processGroup.name, connection.source);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
index 29579dd..5dc69e7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/nf-processor-details.js
@@ -143,9 +143,9 @@ nf.ProcessorDetails = (function () {
                 url: '../nifi-api/processors/' + encodeURIComponent(processorId),
                 dataType: 'json'
             }).done(function (response) {
-                if (nf.Common.isDefinedAndNotNull(response.processor)) {
+                if (nf.Common.isDefinedAndNotNull(response.component)) {
                     // get the processor details
-                    var details = response.processor;
+                    var details = response.component;
 
                     // record the processor details
                     $('#processor-details').data('processorDetails', details);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/views/nf-ng-breadcrumbs-directive-view.html
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/views/nf-ng-breadcrumbs-directive-view.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/views/nf-ng-breadcrumbs-directive-view.html
index 5bfa3cb..c152f12 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/views/nf-ng-breadcrumbs-directive-view.html
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/views/nf-ng-breadcrumbs-directive-view.html
@@ -19,7 +19,7 @@ limitations under the License.
         <div id="breadcrumbs-left-border"></div>
         <div id="data-flow-title-container">
             <span ng-repeat="crumb in breadcrumbs">
-                <span ng-if="separatorFunc(crumb.parent)" style="margin: 0 12px;">
+                <span ng-if="separatorFunc(crumb.parentBreadcrumb)" style="margin: 0 12px;">
                     &raquo;
                 </span>
                 <span class="link"


[04/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 175a598..83de139 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
@@ -450,8 +450,8 @@ nf.Canvas = (function () {
                     d3.selectAll('g.component').classed('selected', function (d) {
                         // consider it selected if its already selected or enclosed in the bounding box
                         return d3.select(this).classed('selected') ||
-                            d.component.position.x >= selectionBoundingBox.x && (d.component.position.x + d.dimensions.width) <= (selectionBoundingBox.x + selectionBoundingBox.width) &&
-                            d.component.position.y >= selectionBoundingBox.y && (d.component.position.y + d.dimensions.height) <= (selectionBoundingBox.y + selectionBoundingBox.height);
+                            d.position.x >= selectionBoundingBox.x && (d.position.x + d.dimensions.width) <= (selectionBoundingBox.x + selectionBoundingBox.width) &&
+                            d.position.y >= selectionBoundingBox.y && (d.position.y + d.dimensions.height) <= (selectionBoundingBox.y + selectionBoundingBox.height);
                     });
 
                     // see if a connection should be selected or not
@@ -777,32 +777,31 @@ nf.Canvas = (function () {
         // load the controller
         return $.ajax({
             type: 'GET',
-            url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupId),
+            url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(processGroupId),
             data: {
                 verbose: true
             },
             dataType: 'json'
-        }).done(function (processGroupResponse) {
+        }).done(function (flowResponse) {
             // set the revision
-            nf.Client.setRevision(processGroupResponse.revision);
+            nf.Client.setRevision(flowResponse.revision);
 
             // get the controller and its contents
-            var processGroup = processGroupResponse.processGroup;
+            var processGroupFlow = flowResponse.processGroupFlow;
 
             // set the group details
-            nf.Canvas.setGroupId(processGroup.id);
-            nf.Canvas.setGroupName(processGroup.name);
+            nf.Canvas.setGroupId(processGroupFlow.id);
 
             // update the breadcrumbs
             nf.ng.Bridge.call('AppCtrl.ServiceProvider.BreadcrumbsCtrl',
                 'AppCtrl.ServiceProvider.BreadcrumbsCtrl.resetBreadcrumbs');
             nf.ng.Bridge.call('AppCtrl.ServiceProvider.BreadcrumbsCtrl',
                 'AppCtrl.ServiceProvider.BreadcrumbsCtrl.generateBreadcrumbs',
-                processGroup);
+                processGroupFlow.breadcrumb);
 
             // set the parent id if applicable
-            if (nf.Common.isDefinedAndNotNull(processGroup.parent)) {
-                nf.Canvas.setParentGroupId(processGroup.parent.id);
+            if (nf.Common.isDefinedAndNotNull(processGroupFlow.parentGroupId)) {
+                nf.Canvas.setParentGroupId(processGroupFlow.parentGroupId);
             } else {
                 nf.Canvas.setParentGroupId(null);
             }
@@ -811,7 +810,7 @@ nf.Canvas = (function () {
             nf.Graph.removeAll();
 
             // refresh the graph
-            nf.Graph.add(processGroup.contents, false);
+            nf.Graph.add(processGroupFlow.flow, false);
 
             // update the toolbar
             nf.CanvasToolbar.refresh();
@@ -1253,8 +1252,8 @@ nf.Canvas = (function () {
                         return false;
                     }
 
-                    var left = d.component.position.x;
-                    var top = d.component.position.y;
+                    var left = d.position.x;
+                    var top = d.position.y;
                     var right = left + d.dimensions.width;
                     var bottom = top + d.dimensions.height;
 
@@ -1283,7 +1282,7 @@ nf.Canvas = (function () {
 
                 // marks the specific component as visible and determines if its entering or leaving visibility
                 var updateVisibility = function (d, isVisible) {
-                    var selection = d3.select('#id-' + d.component.id);
+                    var selection = d3.select('#id-' + d.id);
                     var visible = isVisible(d);
                     var wasVisible = selection.classed('visible');
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js
index 154c14b..a491266 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connectable.js
@@ -71,7 +71,7 @@ nf.Connectable = (function () {
                         var position = d3.mouse(canvas.node());
                         canvas.insert('path', ':first-child')
                                 .datum({
-                                    'sourceId': sourceData.component.id,
+                                    'sourceId': sourceData.id,
                                     'sourceWidth': sourceData.dimensions.width,
                                     'x': position[0],
                                     'y': position[1]
@@ -122,7 +122,7 @@ nf.Connectable = (function () {
                                 var destinationData = destination.datum();
                                 
                                 // show the line preview as appropriate
-                                if (pathDatum.sourceId === destinationData.component.id) {
+                                if (pathDatum.sourceId === destinationData.id) {
                                     var x = pathDatum.x;
                                     var y = pathDatum.y;
                                     var componentOffset = pathDatum.sourceWidth / 2;
@@ -132,8 +132,8 @@ nf.Connectable = (function () {
                                 } else {
                                     // get the position on the destination perimeter
                                     var end = nf.CanvasUtils.getPerimeterPoint(pathDatum, {
-                                        'x': destinationData.component.position.x,
-                                        'y': destinationData.component.position.y,
+                                        'x': destinationData.position.x,
+                                        'y': destinationData.position.y,
                                         'width': destinationData.dimensions.width,
                                         'height': destinationData.dimensions.height
                                     });
@@ -190,7 +190,7 @@ nf.Connectable = (function () {
 
                             // create the connection
                             var destinationData = destination.datum();
-                            nf.ConnectionConfiguration.createConnection(connectorData.sourceId, destinationData.component.id);
+                            nf.ConnectionConfiguration.createConnection(connectorData.sourceId, destinationData.id);
                         }
                     });
         },

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection-configuration.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-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection-configuration.js
index be2cb6c..e03c60d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection-configuration.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-connection-configuration.js
@@ -168,8 +168,8 @@ nf.ConnectionConfiguration = (function () {
             $('#input-port-source-name').text(inputPortData.component.name);
 
             // populate the connection source details
-            $('#connection-source-id').val(inputPortData.component.id);
-            $('#connection-source-component-id').val(inputPortData.component.id);
+            $('#connection-source-id').val(inputPortData.id);
+            $('#connection-source-component-id').val(inputPortData.id);
 
             // populate the group details
             $('#connection-source-group-id').val(nf.Canvas.getGroupId());
@@ -194,8 +194,8 @@ nf.ConnectionConfiguration = (function () {
             $('#funnel-source').show();
 
             // populate the connection source details
-            $('#connection-source-id').val(funnelData.component.id);
-            $('#connection-source-component-id').val(funnelData.component.id);
+            $('#connection-source-id').val(funnelData.id);
+            $('#connection-source-component-id').val(funnelData.id);
 
             // populate the group details
             $('#connection-source-group-id').val(nf.Canvas.getGroupId());
@@ -222,8 +222,8 @@ nf.ConnectionConfiguration = (function () {
             $('#processor-source-type').text(nf.Common.substringAfterLast(processorData.component.type, '.'));
 
             // populate the connection source details
-            $('#connection-source-id').val(processorData.component.id);
-            $('#connection-source-component-id').val(processorData.component.id);
+            $('#connection-source-id').val(processorData.id);
+            $('#connection-source-component-id').val(processorData.id);
 
             // populate the group details
             $('#connection-source-group-id').val(nf.Canvas.getGroupId());
@@ -248,13 +248,13 @@ nf.ConnectionConfiguration = (function () {
 
             $.ajax({
                 type: 'GET',
-                url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupData.component.id),
+                url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupData.id),
                 data: {
                     verbose: true
                 },
                 dataType: 'json'
             }).done(function (response) {
-                var processGroup = response.processGroup;
+                var processGroup = response.component;
                 var processGroupContents = processGroup.contents;
 
                 // only proceed if there are output ports
@@ -413,8 +413,8 @@ nf.ConnectionConfiguration = (function () {
             $('#output-port-destination-name').text(outputPortData.component.name);
 
             // populate the connection destination details
-            $('#connection-destination-id').val(outputPortData.component.id);
-            $('#connection-destination-component-id').val(outputPortData.component.id);
+            $('#connection-destination-id').val(outputPortData.id);
+            $('#connection-destination-component-id').val(outputPortData.id);
 
             // populate the group details
             $('#connection-destination-group-id').val(nf.Canvas.getGroupId());
@@ -431,8 +431,8 @@ nf.ConnectionConfiguration = (function () {
             $('#funnel-destination').show();
 
             // populate the connection destination details
-            $('#connection-destination-id').val(funnelData.component.id);
-            $('#connection-destination-component-id').val(funnelData.component.id);
+            $('#connection-destination-id').val(funnelData.id);
+            $('#connection-destination-component-id').val(funnelData.id);
 
             // populate the group details
             $('#connection-destination-group-id').val(nf.Canvas.getGroupId());
@@ -451,8 +451,8 @@ nf.ConnectionConfiguration = (function () {
             $('#processor-destination-type').text(nf.Common.substringAfterLast(processorData.component.type, '.'));
 
             // populate the connection destination details
-            $('#connection-destination-id').val(processorData.component.id);
-            $('#connection-destination-component-id').val(processorData.component.id);
+            $('#connection-destination-id').val(processorData.id);
+            $('#connection-destination-component-id').val(processorData.id);
 
             // populate the group details
             $('#connection-destination-group-id').val(nf.Canvas.getGroupId());
@@ -473,13 +473,13 @@ nf.ConnectionConfiguration = (function () {
 
             $.ajax({
                 type: 'GET',
-                url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupData.component.id),
+                url: config.urls.api + '/process-groups/' + encodeURIComponent(processGroupData.id),
                 data: {
                     verbose: true
                 },
                 dataType: 'json'
             }).done(function (response) {
-                var processGroup = response.processGroup;
+                var processGroup = response.component;
                 var processGroupContents = processGroup.contents;
 
                 // only proceed if there are output ports
@@ -628,10 +628,10 @@ nf.ConnectionConfiguration = (function () {
             $('#read-only-output-port-source').show();
 
             // populate the component information
-            $('#connection-source-component-id').val(sourceData.component.id);
+            $('#connection-source-component-id').val(sourceData.id);
 
             // populate the group details
-            $('#connection-source-group-id').val(sourceData.component.id);
+            $('#connection-source-group-id').val(sourceData.id);
             $('#connection-source-group-name').text(sourceData.component.name);
 
             // resolve the deferred
@@ -711,8 +711,8 @@ nf.ConnectionConfiguration = (function () {
         var bends = [];
         if (sourceComponentId === destinationComponentId) {
             var rightCenter = {
-                x: sourceData.component.position.x + (sourceData.dimensions.width),
-                y: sourceData.component.position.y + (sourceData.dimensions.height / 2)
+                x: sourceData.position.x + (sourceData.dimensions.width),
+                y: sourceData.position.y + (sourceData.dimensions.height / 2)
             };
 
             var xOffset = nf.Connection.config.selfLoopXOffset;
@@ -759,8 +759,8 @@ nf.ConnectionConfiguration = (function () {
                 // if we need to avoid a collision
                 if (avoidCollision === true) {
                     // determine the middle of the source/destination components
-                    var sourceMiddle = [sourceData.component.position.x + (sourceData.dimensions.width / 2), sourceData.component.position.y + (sourceData.dimensions.height / 2)];
-                    var destinationMiddle = [destinationData.component.position.x + (destinationData.dimensions.width / 2), destinationData.component.position.y + (destinationData.dimensions.height / 2)];
+                    var sourceMiddle = [sourceData.position.x + (sourceData.dimensions.width / 2), sourceData.position.y + (sourceData.dimensions.height / 2)];
+                    var destinationMiddle = [destinationData.position.x + (destinationData.dimensions.width / 2), destinationData.position.y + (destinationData.dimensions.height / 2)];
 
                     // detect if the line is more horizontal or vertical
                     var slope = ((sourceMiddle[1] - destinationMiddle[1]) / (sourceMiddle[0] - destinationMiddle[0]));
@@ -841,7 +841,7 @@ nf.ConnectionConfiguration = (function () {
         if (validateSettings()) {
             var connectionEntity = {
                 'revision': nf.Client.getRevision(),
-                'connection': {
+                'component': {
                     'name': connectionName,
                     'source': {
                         'id': sourceId,
@@ -875,7 +875,7 @@ nf.ConnectionConfiguration = (function () {
 
                 // add the connection
                 nf.Graph.add({
-                    'connections': [response.connection]
+                    'connections': [response]
                 }, true);
 
                 // reload the connections source/destination components
@@ -925,7 +925,7 @@ nf.ConnectionConfiguration = (function () {
         if (validateSettings()) {
             var connectionEntity = {
                 'revision': nf.Client.getRevision(),
-                'connection': {
+                'component': {
                     'id': connectionId,
                     'name': connectionName,
                     'destination': {
@@ -949,14 +949,12 @@ nf.ConnectionConfiguration = (function () {
                 dataType: 'json',
                 contentType: 'application/json'
             }).done(function (response) {
-                if (nf.Common.isDefinedAndNotNull(response.connection)) {
-                    var connection = response.connection;
-
+                if (nf.Common.isDefinedAndNotNull(response.component)) {
                     // update the revision
                     nf.Client.setRevision(response.revision);
 
                     // update this connection
-                    nf.Connection.set(connection);
+                    nf.Connection.set(response);
 
                     // reload the connections source/destination components
                     nf.CanvasUtils.reloadConnectionSourceAndDestination(sourceComponentId, destinationComponentId);
@@ -1226,16 +1224,16 @@ nf.ConnectionConfiguration = (function () {
          */
         showConfiguration: function (selection, destination) {
             return $.Deferred(function (deferred) {
-                var selectionData = selection.datum();
-                var connection = selectionData.component;
+                var connectionEntry = selection.datum();
+                var connection = connectionEntry.component;
 
                 // identify the source component
-                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(connection);
+                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(connectionEntry);
                 var source = d3.select('#id-' + sourceComponentId);
 
                 // identify the destination component
                 if (nf.Common.isUndefinedOrNull(destination)) {
-                    var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(connection);
+                    var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(connectionEntry);
                     destination = d3.select('#id-' + destinationComponentId);
                 }
 
@@ -1283,7 +1281,7 @@ nf.ConnectionConfiguration = (function () {
                         var destinationData = destination.datum();
 
                         // when the group ids differ, its a new destination component so we don't want to preselect any port
-                        if (connection.destination.groupId === destinationData.component.id) {
+                        if (connection.destination.groupId === destinationData.id) {
                             $('#input-port-options').combo('setSelectedOption', {
                                 value: connection.destination.id
                             });

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 8cab85e..48f7247 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
@@ -223,9 +223,7 @@ nf.Connection = (function () {
      * Selects the connection elements against the current connection map.
      */
     var select = function () {
-        return connectionContainer.selectAll('g.connection').data(connectionMap.values(), function (d) {
-            return d.component.id;
-        });
+        return connectionContainer.selectAll('g.connection').data(connectionMap.values());
     };
 
     var renderConnections = function (entered, selected) {
@@ -236,7 +234,7 @@ nf.Connection = (function () {
         var connection = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': 'connection'
                 })
@@ -268,45 +266,45 @@ nf.Connection = (function () {
                 })
                 .call(nf.ContextMenu.activate);
 
-        if (nf.Common.isDFM()) {
-            // only support adding bend points when appropriate
-            selectableConnection.on('dblclick', function (d) {
-                var position = d3.mouse(this.parentNode);
-
-                // find where to put this bend point
-                var bendIndex = getNearestSegment({
-                    'x': position[0],
-                    'y': position[1]
-                }, d);
-
-                // copy the original to restore if necessary
-                var bends = d.component.bends.slice();
+        // only support adding bend points when appropriate
+        selectableConnection.filter(function (d) {
+            return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+        }).on('dblclick', function (d) {
+            var position = d3.mouse(this.parentNode);
+
+            // find where to put this bend point
+            var bendIndex = getNearestSegment({
+                'x': position[0],
+                'y': position[1]
+            }, d);
+
+            // copy the original to restore if necessary
+            var bends = d.component.bends.slice();
+
+            // add it to the collection of points
+            bends.splice(bendIndex, 0, {
+                'x': position[0],
+                'y': position[1]
+            });
 
-                // add it to the collection of points
-                bends.splice(bendIndex, 0, {
-                    'x': position[0],
-                    'y': position[1]
-                });
+            var connection = {
+                id: d.id,
+                bends: bends
+            };
 
-                var connection = {
-                    id: d.component.id,
-                    bends: bends
-                };
-
-                // update the label index if necessary
-                var labelIndex = d.component.labelIndex;
-                if (bends.length === 1) {
-                    connection.labelIndex = 0;
-                } else if (bendIndex <= labelIndex) {
-                    connection.labelIndex = labelIndex + 1;
-                }
+            // update the label index if necessary
+            var labelIndex = d.component.labelIndex;
+            if (bends.length === 1) {
+                connection.labelIndex = 0;
+            } else if (bendIndex <= labelIndex) {
+                connection.labelIndex = labelIndex + 1;
+            }
 
-                // save the new state
-                save(d, connection);
+            // save the new state
+            save(d, connection);
 
-                d3.event.stopPropagation();
-            });
-        }
+            d3.event.stopPropagation();
+        });
 
         // update connection which will establish appropriate start/end points among other things
         connection.call(updateConnections, true, false);
@@ -339,9 +337,11 @@ nf.Connection = (function () {
             updated.classed('grouped', function (d) {
                 var grouped = false;
 
-                // if there are more than one selected relationship, mark this as grouped
-                if (nf.Common.isDefinedAndNotNull(d.component.selectedRelationships) && d.component.selectedRelationships.length > 1) {
-                    grouped = true;
+                if (d.accessPolicy.canRead) {
+                    // if there are more than one selected relationship, mark this as grouped
+                    if (nf.Common.isDefinedAndNotNull(d.component.selectedRelationships) && d.component.selectedRelationships.length > 1) {
+                        grouped = true;
+                    }
                 }
 
                 return grouped;
@@ -349,9 +349,11 @@ nf.Connection = (function () {
             .classed('ghost', function (d) {
                 var ghost = false;
 
-                // if the connection has a relationship that is unavailable, mark it a ghost relationship
-                if (hasUnavailableRelationship(d)) {
-                    ghost = true;
+                if (d.accessPolicy.canRead) {
+                    // if the connection has a relationship that is unavailable, mark it a ghost relationship
+                    if (hasUnavailableRelationship(d)) {
+                        ghost = true;
+                    }
                 }
 
                 return ghost;
@@ -363,7 +365,7 @@ nf.Connection = (function () {
 
             if (updatePath === true) {
                 // calculate the start and end points
-                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d.component);
+                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d);
                 var sourceData = d3.select('#id-' + sourceComponentId).datum();
                 var end;
 
@@ -373,8 +375,8 @@ nf.Connection = (function () {
                     endAnchor = d.bends[d.bends.length - 1];
                 } else {
                     endAnchor = {
-                        x: sourceData.component.position.x + (sourceData.dimensions.width / 2),
-                        y: sourceData.component.position.y + (sourceData.dimensions.height / 2)
+                        x: sourceData.position.x + (sourceData.dimensions.width / 2),
+                        y: sourceData.position.y + (sourceData.dimensions.height / 2)
                     };
                 }
 
@@ -391,8 +393,8 @@ nf.Connection = (function () {
 
                         // get the position on the new destination perimeter
                         var newEnd = nf.CanvasUtils.getPerimeterPoint(endAnchor, {
-                            'x': newDestinationData.component.position.x,
-                            'y': newDestinationData.component.position.y,
+                            'x': newDestinationData.position.x,
+                            'y': newDestinationData.position.y,
                             'width': newDestinationData.dimensions.width,
                             'height': newDestinationData.dimensions.height
                         });
@@ -402,13 +404,13 @@ nf.Connection = (function () {
                         end.y = newEnd.y;
                     }
                 } else {
-                    var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d.component);
+                    var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d);
                     var destinationData = d3.select('#id-' + destinationComponentId).datum();
 
                     // get the position on the destination perimeter
                     end = nf.CanvasUtils.getPerimeterPoint(endAnchor, {
-                        'x': destinationData.component.position.x,
-                        'y': destinationData.component.position.y,
+                        'x': destinationData.position.x,
+                        'y': destinationData.position.y,
                         'width': destinationData.dimensions.width,
                         'height': destinationData.dimensions.height
                     });
@@ -424,8 +426,8 @@ nf.Connection = (function () {
 
                 // get the position on the source perimeter
                 var start = nf.CanvasUtils.getPerimeterPoint(startAnchor, {
-                    'x': sourceData.component.position.x,
-                    'y': sourceData.component.position.y,
+                    'x': sourceData.position.x,
+                    'y': sourceData.position.y,
                     'width': sourceData.dimensions.width,
                     'height': sourceData.dimensions.height
                 });
@@ -444,9 +446,11 @@ nf.Connection = (function () {
                             'marker-end': function () {
                                 var marker = 'normal';
 
-                                // if the connection has a relationship that is unavailable, mark it a ghost relationship
-                                if (hasUnavailableRelationship(d)) {
-                                    marker = 'ghost';
+                                if (d.accessPolicy.canRead) {
+                                    // if the connection has a relationship that is unavailable, mark it a ghost relationship
+                                    if (hasUnavailableRelationship(d)) {
+                                        marker = 'ghost';
+                                    }
                                 }
 
                                 return 'url(#' + marker + ')';
@@ -471,7 +475,7 @@ nf.Connection = (function () {
                 // bends
                 // -----
 
-                if (nf.Common.isDFM()) {
+                if (d.accessPolicy.canWrite) {
                     // ------------------
                     // bends - startpoint
                     // ------------------
@@ -549,8 +553,8 @@ nf.Connection = (function () {
                                 d3.event.stopPropagation();
 
                                 // if this is a self loop prevent removing the last two bends
-                                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d.component);
-                                var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d.component);
+                                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d);
+                                var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d);
                                 if (sourceComponentId === destinationComponentId && d.component.bends.length <= 2) {
                                     nf.Dialog.showOkDialog({
                                         dialogContent: 'Looping connections must have at least two bend points.',
@@ -576,7 +580,7 @@ nf.Connection = (function () {
                                 }
 
                                 var connection = {
-                                    id: d.component.id,
+                                    id: d.id,
                                     bends: newBends
                                 };
 
@@ -640,224 +644,227 @@ nf.Connection = (function () {
 
                     var labelCount = 0;
 
-                    // -----------------------
-                    // connection label - from
-                    // -----------------------
-
-                    var connectionFrom = connectionLabelContainer.select('g.connection-from-container');
-
-                    // determine if the connection require a from label
-                    if (isGroup(d.component.source)) {
-                        // see if the connection from label is already rendered
-                        if (connectionFrom.empty()) {
-                            connectionFrom = connectionLabelContainer.append('g')
-                                    .attr({
-                                        'class': 'connection-from-container'
-                                    });
-
-                            connectionFrom.append('text')
-                                    .attr({
-                                        'class': 'connection-stats-label',
-                                        'x': 0,
-                                        'y': 10
-                                    })
-                                    .text('From');
-
-                            connectionFrom.append('text')
-                                    .attr({
-                                        'class': 'connection-stats-value connection-from',
-                                        'x': 33,
-                                        'y': 10,
-                                        'width': 130
-                                    });
-
-                            connectionFrom.append('image')
-                                    .call(nf.CanvasUtils.disableImageHref)
-                                    .attr({
-                                        'class': 'connection-from-run-status',
-                                        'width': 10,
-                                        'height': 10,
-                                        'x': 167,
-                                        'y': 1
+                    if (d.accessPolicy.canRead) {
+
+                        // -----------------------
+                        // connection label - from
+                        // -----------------------
+
+                        var connectionFrom = connectionLabelContainer.select('g.connection-from-container');
+                        
+                        // determine if the connection require a from label
+                        if (isGroup(d.component.source)) {
+                            // see if the connection from label is already rendered
+                            if (connectionFrom.empty()) {
+                                connectionFrom = connectionLabelContainer.append('g')
+                                        .attr({
+                                            'class': 'connection-from-container'
+                                        });
+    
+                                connectionFrom.append('text')
+                                        .attr({
+                                            'class': 'connection-stats-label',
+                                            'x': 0,
+                                            'y': 10
+                                        })
+                                        .text('From');
+    
+                                connectionFrom.append('text')
+                                        .attr({
+                                            'class': 'connection-stats-value connection-from',
+                                            'x': 33,
+                                            'y': 10,
+                                            'width': 130
+                                        });
+    
+                                connectionFrom.append('image')
+                                        .call(nf.CanvasUtils.disableImageHref)
+                                        .attr({
+                                            'class': 'connection-from-run-status',
+                                            'width': 10,
+                                            'height': 10,
+                                            'x': 167,
+                                            'y': 1
+                                        });
+                            }
+    
+                            // update the connection from positioning
+                            connectionFrom.attr('transform', function () {
+                                var y = 5 + (15 * labelCount++);
+                                return 'translate(5, ' + y + ')';
+                            });
+    
+                            // update the label text
+                            connectionFrom.select('text.connection-from')
+                                    .each(function () {
+                                        var connectionFromLabel = d3.select(this);
+    
+                                        // reset the label name to handle any previous state
+                                        connectionFromLabel.text(null).selectAll('title').remove();
+    
+                                        // apply ellipsis to the label as necessary
+                                        nf.CanvasUtils.ellipsis(connectionFromLabel, d.component.source.name);
+                                    }).append('title').text(function () {
+                                        return d.component.source.name;
                                     });
-                        }
-
-                        // update the connection from positioning
-                        connectionFrom.attr('transform', function () {
-                            var y = 5 + (15 * labelCount++);
-                            return 'translate(5, ' + y + ')';
-                        });
-
-                        // update the label text
-                        connectionFrom.select('text.connection-from')
-                                .each(function () {
-                                    var connectionFromLabel = d3.select(this);
-
-                                    // reset the label name to handle any previous state
-                                    connectionFromLabel.text(null).selectAll('title').remove();
-
-                                    // apply ellipsis to the label as necessary
-                                    nf.CanvasUtils.ellipsis(connectionFromLabel, d.component.source.name);
-                                }).append('title').text(function () {
-                                    return d.component.source.name;
-                                });
-
-                        // update the label run status
-                        connectionFrom.select('image.connection-from-run-status').attr('xlink:href', function () {
-                            if (d.component.source.exists === false) {
-                                return 'images/portRemoved.png';
-                            } else if (d.component.source.running === true) {
-                                return 'images/portRunning.png';
-                            } else {
-                                return 'images/portStopped.png';
+    
+                            // update the label run status
+                            connectionFrom.select('image.connection-from-run-status').attr('xlink:href', function () {
+                                if (d.component.source.exists === false) {
+                                    return 'images/portRemoved.png';
+                                } else if (d.component.source.running === true) {
+                                    return 'images/portRunning.png';
+                                } else {
+                                    return 'images/portStopped.png';
+                                }
+                            });
+                        } else {
+                            // there is no connection from, but check if the name was previous
+                            // rendered so it can be removed
+                            if (!connectionFrom.empty()) {
+                                connectionFrom.remove();
                             }
-                        });
-                    } else {
-                        // there is no connection from, but check if the name was previous
-                        // rendered so it can be removed
-                        if (!connectionFrom.empty()) {
-                            connectionFrom.remove();
                         }
-                    }
-
-                    // ---------------------
-                    // connection label - to
-                    // ---------------------
-
-                    var connectionTo = connectionLabelContainer.select('g.connection-to-container');
-
-                    // determine if the connection require a to label
-                    if (isGroup(d.component.destination)) {
-                        // see if the connection to label is already rendered
-                        if (connectionTo.empty()) {
-                            connectionTo = connectionLabelContainer.append('g')
-                                    .attr({
-                                        'class': 'connection-to-container'
-                                    });
-
-                            connectionTo.append('text')
-                                    .attr({
-                                        'class': 'connection-stats-label',
-                                        'x': 0,
-                                        'y': 10
-                                    })
-                                    .text('To');
-
-                            connectionTo.append('text')
-                                    .attr({
-                                        'class': 'connection-stats-value connection-to',
-                                        'x': 18,
-                                        'y': 10,
-                                        'width': 145
-                                    });
-
-                            connectionTo.append('image')
-                                    .call(nf.CanvasUtils.disableImageHref)
-                                    .attr({
-                                        'class': 'connection-to-run-status',
-                                        'width': 10,
-                                        'height': 10,
-                                        'x': 167,
-                                        'y': 1
+    
+                        // ---------------------
+                        // connection label - to
+                        // ---------------------
+    
+                        var connectionTo = connectionLabelContainer.select('g.connection-to-container');
+    
+                        // determine if the connection require a to label
+                        if (isGroup(d.component.destination)) {
+                            // see if the connection to label is already rendered
+                            if (connectionTo.empty()) {
+                                connectionTo = connectionLabelContainer.append('g')
+                                        .attr({
+                                            'class': 'connection-to-container'
+                                        });
+    
+                                connectionTo.append('text')
+                                        .attr({
+                                            'class': 'connection-stats-label',
+                                            'x': 0,
+                                            'y': 10
+                                        })
+                                        .text('To');
+    
+                                connectionTo.append('text')
+                                        .attr({
+                                            'class': 'connection-stats-value connection-to',
+                                            'x': 18,
+                                            'y': 10,
+                                            'width': 145
+                                        });
+    
+                                connectionTo.append('image')
+                                        .call(nf.CanvasUtils.disableImageHref)
+                                        .attr({
+                                            'class': 'connection-to-run-status',
+                                            'width': 10,
+                                            'height': 10,
+                                            'x': 167,
+                                            'y': 1
+                                        });
+                            }
+    
+                            // update the connection to positioning
+                            connectionTo.attr('transform', function () {
+                                var y = 5 + (15 * labelCount++);
+                                return 'translate(5, ' + y + ')';
+                            });
+    
+                            // update the label text
+                            connectionTo.select('text.connection-to')
+                                    .each(function (d) {
+                                        var connectionToLabel = d3.select(this);
+    
+                                        // reset the label name to handle any previous state
+                                        connectionToLabel.text(null).selectAll('title').remove();
+    
+                                        // apply ellipsis to the label as necessary
+                                        nf.CanvasUtils.ellipsis(connectionToLabel, d.component.destination.name);
+                                    }).append('title').text(function (d) {
+                                        return d.component.destination.name;
                                     });
-                        }
-
-                        // update the connection to positioning
-                        connectionTo.attr('transform', function () {
-                            var y = 5 + (15 * labelCount++);
-                            return 'translate(5, ' + y + ')';
-                        });
-
-                        // update the label text
-                        connectionTo.select('text.connection-to')
-                                .each(function (d) {
-                                    var connectionToLabel = d3.select(this);
-
-                                    // reset the label name to handle any previous state
-                                    connectionToLabel.text(null).selectAll('title').remove();
-
-                                    // apply ellipsis to the label as necessary
-                                    nf.CanvasUtils.ellipsis(connectionToLabel, d.component.destination.name);
-                                }).append('title').text(function (d) {
-                                    return d.component.destination.name;
-                                });
-
-                        // update the label run status
-                        connectionTo.select('image.connection-to-run-status').attr('xlink:href', function () {
-                            if (d.component.destination.exists === false) {
-                                return 'images/portRemoved.png';
-                            } else if (d.component.destination.running === true) {
-                                return 'images/portRunning.png';
-                            } else {
-                                return 'images/portStopped.png';
+    
+                            // update the label run status
+                            connectionTo.select('image.connection-to-run-status').attr('xlink:href', function () {
+                                if (d.component.destination.exists === false) {
+                                    return 'images/portRemoved.png';
+                                } else if (d.component.destination.running === true) {
+                                    return 'images/portRunning.png';
+                                } else {
+                                    return 'images/portStopped.png';
+                                }
+                            });
+                        } else {
+                            // there is no connection to, but check if the name was previous
+                            // rendered so it can be removed
+                            if (!connectionTo.empty()) {
+                                connectionTo.remove();
                             }
-                        });
-                    } else {
-                        // there is no connection to, but check if the name was previous
-                        // rendered so it can be removed
-                        if (!connectionTo.empty()) {
-                            connectionTo.remove();
                         }
-                    }
-
-                    // -----------------------
-                    // connection label - name
-                    // -----------------------
-
-                    // get the connection name
-                    var connectionNameValue = nf.CanvasUtils.formatConnectionName(d.component);
-                    var connectionName = connectionLabelContainer.select('g.connection-name-container');
-
-                    // is there a name to render
-                    if (!nf.Common.isBlank(connectionNameValue)) {
-                        // see if the connection name label is already rendered
-                        if (connectionName.empty()) {
-                            connectionName = connectionLabelContainer.append('g')
-                                    .attr({
-                                        'class': 'connection-name-container'
-                                    });
-
-                            connectionName.append('text')
-                                    .attr({
-                                        'class': 'connection-stats-label',
-                                        'x': 0,
-                                        'y': 10
-                                    })
-                                    .text('Name');
-
-                            connectionName.append('text')
-                                    .attr({
-                                        'class': 'connection-stats-value connection-name',
-                                        'x': 35,
-                                        'y': 10,
-                                        'width': 142
+    
+                        // -----------------------
+                        // connection label - name
+                        // -----------------------
+    
+                        // get the connection name
+                        var connectionNameValue = nf.CanvasUtils.formatConnectionName(d.component);
+                        var connectionName = connectionLabelContainer.select('g.connection-name-container');
+    
+                        // is there a name to render
+                        if (!nf.Common.isBlank(connectionNameValue)) {
+                            // see if the connection name label is already rendered
+                            if (connectionName.empty()) {
+                                connectionName = connectionLabelContainer.append('g')
+                                        .attr({
+                                            'class': 'connection-name-container'
+                                        });
+    
+                                connectionName.append('text')
+                                        .attr({
+                                            'class': 'connection-stats-label',
+                                            'x': 0,
+                                            'y': 10
+                                        })
+                                        .text('Name');
+    
+                                connectionName.append('text')
+                                        .attr({
+                                            'class': 'connection-stats-value connection-name',
+                                            'x': 35,
+                                            'y': 10,
+                                            'width': 142
+                                        });
+                            }
+    
+                            // update the connection name positioning
+                            connectionName.attr('transform', function () {
+                                var y = 5 + (15 * labelCount++);
+                                return 'translate(5, ' + y + ')';
+                            });
+    
+                            // update the connection name
+                            connectionName.select('text.connection-name')
+                                    .each(function () {
+                                        var connectionToLabel = d3.select(this);
+    
+                                        // reset the label name to handle any previous state
+                                        connectionToLabel.text(null).selectAll('title').remove();
+    
+                                        // apply ellipsis to the label as necessary
+                                        nf.CanvasUtils.ellipsis(connectionToLabel, connectionNameValue);
+                                    }).append('title').text(function () {
+                                        return connectionNameValue;
                                     });
-                        }
-
-                        // update the connection name positioning
-                        connectionName.attr('transform', function () {
-                            var y = 5 + (15 * labelCount++);
-                            return 'translate(5, ' + y + ')';
-                        });
-
-                        // update the connection name
-                        connectionName.select('text.connection-name')
-                                .each(function () {
-                                    var connectionToLabel = d3.select(this);
-
-                                    // reset the label name to handle any previous state
-                                    connectionToLabel.text(null).selectAll('title').remove();
-
-                                    // apply ellipsis to the label as necessary
-                                    nf.CanvasUtils.ellipsis(connectionToLabel, connectionNameValue);
-                                }).append('title').text(function () {
-                                    return connectionNameValue;
-                                });
-                    } else {
-                        // there is no connection name, but check if the name was previous
-                        // rendered so it can be removed
-                        if (!connectionName.empty()) {
-                            connectionName.remove();
+                        } else {
+                            // there is no connection name, but check if the name was previous
+                            // rendered so it can be removed
+                            if (!connectionName.empty()) {
+                                connectionName.remove();
+                            }
                         }
                     }
 
@@ -939,16 +946,18 @@ nf.Connection = (function () {
                                 return 5 + (15 * labelCount) + 3;
                             });
                             
-                    // determine whether or not to show the expiration icon
-                    connectionLabelContainer.select('g.expiration-icon')
-                            .classed('hidden', function () {
-                                return !isExpirationConfigured(d.component);
-                            })
-                            .select('title').text(function () {
-                                return 'Expires FlowFiles older than ' + d.component.flowFileExpiration;
-                            });
+                    if (d.accessPolicy.canRead) {
+                        // determine whether or not to show the expiration icon
+                        connectionLabelContainer.select('g.expiration-icon')
+                                .classed('hidden', function () {
+                                    return !isExpirationConfigured(d.component);
+                                })
+                                .select('title').text(function () {
+                                    return 'Expires FlowFiles older than ' + d.component.flowFileExpiration;
+                                });
+                    }
 
-                    if (nf.Common.isDFM()) {
+                    if (d.accessPolicy.canWrite) {
                         // only support dragging the label when appropriate
                         connectionLabelContainer.call(labelDrag);
                     }
@@ -1003,8 +1012,8 @@ nf.Connection = (function () {
         var revision = nf.Client.getRevision();
 
         var entity = {
-            revision: revision,
-            connection: connection
+            'revision': revision,
+            'component': connection
         };
 
         return $.ajax({
@@ -1018,7 +1027,7 @@ nf.Connection = (function () {
             nf.Client.setRevision(response.revision);
 
             // request was successful, update the entry
-            nf.Connection.set(response.connection);
+            nf.Connection.set(response);
         }).fail(function (xhr, status, error) {
             if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
                 nf.Dialog.showOkDialog({
@@ -1035,7 +1044,7 @@ nf.Connection = (function () {
     var removeConnections = function (removed) {
         // consider reloading source/destination of connection being removed
         removed.each(function (d) {
-            nf.CanvasUtils.reloadConnectionSourceAndDestination(d.component.source.id, d.component.destination.id);
+            nf.CanvasUtils.reloadConnectionSourceAndDestination(d.sourceId, d.destinationId);
         });
         
         // remove the connection
@@ -1099,7 +1108,7 @@ nf.Connection = (function () {
                             // only save the updated bends if necessary
                             if (different) {
                                 save(connectionData, {
-                                    id: connectionData.component.id,
+                                    id: connectionData.id,
                                     bends: bends
                                 }).fail(function () {
                                     // restore the previous bend points
@@ -1174,10 +1183,10 @@ nf.Connection = (function () {
 
                                 var connectionEntity = {
                                     'revision': nf.Client.getRevision(),
-                                    'connection': {
-                                        'id': connectionData.component.id,
+                                    'component': {
+                                        'id': connectionData.id,
                                         'destination': {
-                                            'id': destinationData.component.id,
+                                            'id': destinationData.id,
                                             'groupId': nf.Canvas.getGroupId(),
                                             'type': destinationType
                                         }
@@ -1185,10 +1194,10 @@ nf.Connection = (function () {
                                 };
 
                                 // if this is a self loop and there are less than 2 bends, add them
-                                if (connectionData.bends.length < 2 && connectionData.component.source.id === destinationData.component.id) {
+                                if (connectionData.bends.length < 2 && connectionData.component.source.id === destinationData.id) {
                                     var rightCenter = {
-                                        x: destinationData.component.position.x + (destinationData.dimensions.width),
-                                        y: destinationData.component.position.y + (destinationData.dimensions.height / 2)
+                                        x: destinationData.position.x + (destinationData.dimensions.width),
+                                        y: destinationData.position.y + (destinationData.dimensions.height / 2)
                                     };
                                     var xOffset = nf.Connection.config.selfLoopXOffset;
                                     var yOffset = nf.Connection.config.selfLoopYOffset;
@@ -1211,13 +1220,13 @@ nf.Connection = (function () {
                                     dataType: 'json',
                                     contentType: 'application/json'
                                 }).done(function (response) {
-                                    var updatedConnectionData = response.connection;
+                                    var updatedConnectionData = response.component;
 
                                     // update the revision
                                     nf.Client.setRevision(response.revision);
 
                                     // refresh to update the label
-                                    nf.Connection.set(updatedConnectionData);
+                                    nf.Connection.set(response);
                                     
                                     // reload the previous destination and the new source/destination
                                     nf.CanvasUtils.reloadConnectionSourceAndDestination(null, previousDestinationId);
@@ -1344,7 +1353,7 @@ nf.Connection = (function () {
 
                                 // save the new label index
                                 save(d, {
-                                    id: d.component.id,
+                                    id: d.id,
                                     labelIndex: d.labelIndex
                                 }).fail(function () {
                                     // restore the previous label index
@@ -1364,34 +1373,26 @@ nf.Connection = (function () {
         /**
          * Populates the graph with the specified connections.
          * 
-         * @argument {object | array} connections               The connections to add
+         * @argument {object | array} connectionEntities               The connections to add
          * @argument {boolean} selectAll                Whether or not to select the new contents
          */
-        add: function (connections, selectAll) {
+        add: function (connectionEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
-            var add = function (connection) {
+            var add = function (connectionEntity) {
                 // add the connection
-                connectionMap.set(connection.id, {
+                connectionMap.set(connectionEntity.id, $.extend({
                     type: 'Connection',
-                    component: connection,
-                    bends: $.map(connection.bends, function (bend) {
-                        return {
-                            x: bend.x,
-                            y: bend.y
-                        };
-                    }),
-                    labelIndex: connection.labelIndex
-                });
+                }, connectionEntity));
             };
 
             // determine how to handle the specified connection
-            if ($.isArray(connections)) {
-                $.each(connections, function (_, connection) {
-                    add(connection);
+            if ($.isArray(connectionEntities)) {
+                $.each(connectionEntities, function (_, connectionEntity) {
+                    add(connectionEntity);
                 });
             } else {
-                add(connections);
+                add(connectionEntities);
             }
 
             // apply the selection and handle all new connection
@@ -1408,34 +1409,27 @@ nf.Connection = (function () {
         /**
          * Sets the value of the specified connection.
          * 
-         * @param {type} connection
+         * @param {type} connectionEntities
          */
-        set: function (connection) {
-            var set = function (conn) {
-                if (connectionMap.has(conn.id)) {
+        set: function (connectionEntities) {
+            var set = function (connectionEntity) {
+                if (connectionMap.has(connectionEntity.id)) {
                     // update the current entry
-                    var connectionEntry = connectionMap.get(conn.id);
-                    connectionEntry.component = conn;
-                    connectionEntry.bends = $.map(conn.bends, function (bend) {
-                        return {
-                            x: bend.x,
-                            y: bend.y
-                        };
-                    });
-                    connectionEntry.labelIndex = conn.labelIndex;
+                    var connectionEntry = connectionMap.get(connectionEntity.id);
+                    $.extend(connectionEntry, connectionEntity);
 
                     // update the connection in the UI
-                    d3.select('#id-' + conn.id).call(updateConnections, true, true);
+                    d3.select('#id-' + connectionEntity.id).call(updateConnections, true, true);
                 }
             };
 
             // determine how to handle the specified connection
-            if ($.isArray(connection)) {
-                $.each(connection, function (_, conn) {
-                    set(conn);
+            if ($.isArray(connectionEntities)) {
+                $.each(connectionEntities, function (_, connectionEntity) {
+                    set(connectionEntity);
                 });
             } else {
-                set(connection);
+                set(connectionEntities);
             }
         },
         
@@ -1518,7 +1512,7 @@ nf.Connection = (function () {
                     url: connection.uri,
                     dataType: 'json'
                 }).done(function (response) {
-                    nf.Connection.set(response.connection);
+                    nf.Connection.set(response);
                 });
             }
         },
@@ -1532,11 +1526,9 @@ nf.Connection = (function () {
         getComponentConnections: function (id) {
             var connections = [];
             connectionMap.forEach(function (_, entry) {
-                var connection = entry.component;
-
                 // see if this component is the source or destination of this connection
-                if (nf.CanvasUtils.getConnectionSourceComponentId(connection) === id || nf.CanvasUtils.getConnectionDestinationComponentId(connection) === id) {
-                    connections.push(connection);
+                if (nf.CanvasUtils.getConnectionSourceComponentId(entry) === id || nf.CanvasUtils.getConnectionDestinationComponentId(entry) === id) {
+                    connections.push(entry);
                 }
             });
             return connections;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
index f841e51..90863d5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-context-menu.js
@@ -38,6 +38,9 @@ nf.ContextMenu = (function () {
         if (selection.size() !== 1) {
             return false;
         }
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
 
         var isConfigurableComponent = nf.CanvasUtils.isLabel(selection) || nf.CanvasUtils.isProcessGroup(selection);
         if (!isConfigurableComponent) {
@@ -46,7 +49,7 @@ nf.ContextMenu = (function () {
             }
         }
 
-        return isConfigurableComponent && nf.Common.isDFM();
+        return isConfigurableComponent;
     };
 
     /**
@@ -59,8 +62,11 @@ nf.ContextMenu = (function () {
         if (selection.size() !== 1) {
             return false;
         }
+        if (nf.CanvasUtils.canRead(selection) === false) {
+            return false;
+        }
 
-        if (nf.Common.isDFM()) {
+        if (nf.CanvasUtils.canModify(selection)) {
             if (nf.CanvasUtils.isProcessor(selection) || nf.CanvasUtils.isInputPort(selection) || nf.CanvasUtils.isOutputPort(selection) || nf.CanvasUtils.isRemoteProcessGroup(selection) || nf.CanvasUtils.isConnection(selection)) {
                 return !nf.CanvasUtils.supportsModification(selection);
             }
@@ -77,7 +83,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection         The selection of currently selected components 
      */
     var isDeletable = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.isDeletable(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.isDeletable(selection);
     };
 
     /**
@@ -86,7 +96,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection         The selection of currently selected components 
      */
     var isRunnable = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.areRunnable(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.areRunnable(selection);
     };
 
     /**
@@ -95,7 +109,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection         The selection of currently selected components 
      */
     var isStoppable = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.areStoppable(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.areStoppable(selection);
     };
 
     /**
@@ -141,7 +159,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection         The selection of currently selected components
      */
     var isCopyable = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.isCopyable(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.isCopyable(selection);
     };
 
     /**
@@ -172,8 +194,11 @@ nf.ContextMenu = (function () {
         if (selection.size() !== 1) {
             return false;
         }
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
 
-        return nf.Common.isDFM() && nf.CanvasUtils.isConnection(selection);
+        return nf.CanvasUtils.isConnection(selection);
     };
 
     /**
@@ -182,7 +207,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection          The selection
      */
     var isColorable = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.isColorable(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.isColorable(selection);
     };
 
     /**
@@ -205,14 +234,16 @@ nf.ContextMenu = (function () {
      * @param {selection} selection         The selection
      */
     var hasDownstream = function (selection) {
-        // ensure the correct number of components are selected
-        if (selection.size() !== 1) {
-            return false;
-        }
-
-        return nf.CanvasUtils.isFunnel(selection) || nf.CanvasUtils.isProcessor(selection) || nf.CanvasUtils.isProcessGroup(selection) ||
-                nf.CanvasUtils.isRemoteProcessGroup(selection) || nf.CanvasUtils.isInputPort(selection) ||
-                (nf.CanvasUtils.isOutputPort(selection) && nf.Canvas.getParentGroupId() !== null);
+        // TODO
+        // // ensure the correct number of components are selected
+        // if (selection.size() !== 1) {
+        //     return false;
+        // }
+        //
+        // return nf.CanvasUtils.isFunnel(selection) || nf.CanvasUtils.isProcessor(selection) || nf.CanvasUtils.isProcessGroup(selection) ||
+        //         nf.CanvasUtils.isRemoteProcessGroup(selection) || nf.CanvasUtils.isInputPort(selection) ||
+        //         (nf.CanvasUtils.isOutputPort(selection) && nf.Canvas.getParentGroupId() !== null);
+        return false;
     };
 
     /**
@@ -221,14 +252,16 @@ nf.ContextMenu = (function () {
      * @param {selection} selection         The selection
      */
     var hasUpstream = function (selection) {
-        // ensure the correct number of components are selected
-        if (selection.size() !== 1) {
-            return false;
-        }
-
-        return nf.CanvasUtils.isFunnel(selection) || nf.CanvasUtils.isProcessor(selection) || nf.CanvasUtils.isProcessGroup(selection) ||
-                nf.CanvasUtils.isRemoteProcessGroup(selection) || nf.CanvasUtils.isOutputPort(selection) ||
-                (nf.CanvasUtils.isInputPort(selection) && nf.Canvas.getParentGroupId() !== null);
+        // TODO
+        // // ensure the correct number of components are selected
+        // if (selection.size() !== 1) {
+        //     return false;
+        // }
+        //
+        // return nf.CanvasUtils.isFunnel(selection) || nf.CanvasUtils.isProcessor(selection) || nf.CanvasUtils.isProcessGroup(selection) ||
+        //         nf.CanvasUtils.isRemoteProcessGroup(selection) || nf.CanvasUtils.isOutputPort(selection) ||
+        //         (nf.CanvasUtils.isInputPort(selection) && nf.Canvas.getParentGroupId() !== null);
+        return false;
     };
 
     /**
@@ -241,9 +274,7 @@ nf.ContextMenu = (function () {
         if (selection.size() !== 1) {
             return false;
         }
-
-        // ensure the user is DFM
-        if (nf.Common.isDFM() === false) {
+        if (nf.CanvasUtils.canModify(selection) === false) {
             return false;
         }
 
@@ -304,7 +335,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection
      */
     var canStartTransmission = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.canAllStartTransmitting(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.canAllStartTransmitting(selection);
     };
 
     /**
@@ -313,7 +348,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection
      */
     var canStopTransmission = function (selection) {
-        return nf.Common.isDFM() && nf.CanvasUtils.canAllStopTransmitting(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return nf.CanvasUtils.canAllStopTransmitting(selection);
     };
     
     /**
@@ -322,7 +361,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection
      */
     var canEmptyQueue = function (selection) {
-        return nf.Common.isDFM() && isConnection(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return isConnection(selection);
     };
 
     /**
@@ -331,7 +374,11 @@ nf.ContextMenu = (function () {
      * @param {selection} selection
      */
     var canListQueue = function (selection) {
-        return nf.Common.isDFM() && isConnection(selection);
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+        
+        return isConnection(selection);
     };
     
     /**
@@ -340,6 +387,12 @@ nf.ContextMenu = (function () {
      * @param {type} selection
      */
     var canMoveToParent = function (selection) {
+        if (nf.CanvasUtils.canModify(selection) === false) {
+            return false;
+        }
+
+        // TODO - also check can modify in parent
+        
         return !selection.empty() && nf.CanvasUtils.isDisconnected(selection) && nf.Canvas.getParentGroupId() !== null;
     };
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
index d4dd1de..ab3078f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-draggable.js
@@ -43,19 +43,17 @@ nf.Draggable = (function () {
         
         var updateComponentPosition = function(d) {
             var newPosition = {
-                'x': d.component.position.x + delta.x,
-                'y': d.component.position.y + delta.y
+                'x': d.position.x + delta.x,
+                'y': d.position.y + delta.y
             };
 
             // build the entity
             var entity = {
-                'revision': nf.Client.getRevision()
-            };
-
-            // use bracket notation to dynamic get the key based on the entity type
-            entity[nf[d.type].getEntityKey(d)] = {
-                'id': d.component.id,
-                'position': newPosition
+                'revision': nf.Client.getRevision(),
+                'component': {
+                    'id': d.id,
+                    'position': newPosition
+                }
             };
 
             // update the component positioning
@@ -70,13 +68,13 @@ nf.Draggable = (function () {
                     // update the revision
                     nf.Client.setRevision(response.revision);
 
-                    // store the updated location
-                    d.component.position = newPosition;
+                    // update the component
+                    nf[d.type].set(response);
 
                     // resolve with an object so we can refresh when finished
                     deferred.resolve({
                         type: d.type,
-                        id: d.component.id
+                        id: d.id
                     });
                 }).fail(function (xhr, status, error) {
                     if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
@@ -95,12 +93,12 @@ nf.Draggable = (function () {
         
         var updateConnectionPosition = function(d) {
             // only update if necessary
-            if (d.component.bends.length === 0) {
+            if (d.bends.length === 0) {
                 return null;
             }
 
             // calculate the new bend points
-            var newBends = $.map(d.component.bends, function (bend) {
+            var newBends = $.map(d.bends, function (bend) {
                 return {
                     x: bend.x + delta.x,
                     y: bend.y + delta.y
@@ -108,9 +106,9 @@ nf.Draggable = (function () {
             });
 
             var entity = {
-                revision: revision,
-                connection: {
-                    id: d.component.id,
+                'revision': revision,
+                'component': {
+                    id: d.id,
                     bends: newBends
                 }
             };
@@ -127,19 +125,13 @@ nf.Draggable = (function () {
                     // update the revision
                     nf.Client.setRevision(response.revision);
 
-                    // store the updated bend points
-                    d.component.bends = response.connection.bends;
-                    d.bends = $.map(d.component.bends, function (bend) {
-                        return {
-                            x: bend.x,
-                            y: bend.y
-                        };
-                    });
+                    // update the component
+                    nf.Connection.set(response);
 
                     // resolve with an object so we can refresh when finished
                     deferred.resolve({
                         type: d.type,
-                        id: d.component.id
+                        id: d.id
                     });
                 }).fail(function (xhr, status, error) {
                     if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
@@ -160,14 +152,14 @@ nf.Draggable = (function () {
         d3.selectAll('g.connection.selected').each(function (d) {
             var connectionUpdate = updateConnectionPosition(d);
             if (connectionUpdate !== null) {
-                updates.set(d.component.id, connectionUpdate);
+                updates.set(d.id, connectionUpdate);
             }
         });
         
         // go through each selected component
         d3.selectAll('g.component.selected').each(function (d) {
             // consider any self looping connections
-            var connections = nf.Connection.getComponentConnections(d.component.id);
+            var connections = nf.Connection.getComponentConnections(d.id);
             $.each(connections, function(_, connection) {
                 if (!updates.has(connection.id) && nf.CanvasUtils.getConnectionSourceComponentId(connection) === nf.CanvasUtils.getConnectionDestinationComponentId(connection)) {
                     var connectionUpdate = updateConnectionPosition(nf.Connection.get(connection.id));
@@ -178,7 +170,7 @@ nf.Draggable = (function () {
             });
             
             // consider the component itself
-            updates.set(d.component.id, updateComponentPosition(d));
+            updates.set(d.id, updateComponentPosition(d));
         });
 
         // wait for all updates to complete
@@ -240,14 +232,14 @@ nf.Draggable = (function () {
                             // determine the appropriate bounding box
                             var minX = null, maxX = null, minY = null, maxY = null;
                             selection.each(function (d) {
-                                if (minX === null || d.component.position.x < minX) {
-                                    minX = d.component.position.x;
+                                if (minX === null || d.position.x < minX) {
+                                    minX = d.position.x;
                                 }
-                                if (minY === null || d.component.position.y < minY) {
-                                    minY = d.component.position.y;
+                                if (minY === null || d.position.y < minY) {
+                                    minY = d.position.y;
                                 }
-                                var componentMaxX = d.component.position.x + d.dimensions.width;
-                                var componentMaxY = d.component.position.y + d.dimensions.height;
+                                var componentMaxX = d.position.x + d.dimensions.width;
+                                var componentMaxY = d.position.y + d.dimensions.height;
                                 if (maxX === null || componentMaxX > maxX) {
                                     maxX = componentMaxX;
                                 }


[05/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/StandardOptimisticLockingManager.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/StandardOptimisticLockingManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/StandardOptimisticLockingManager.java
index 16b55ee..3bc22f7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/StandardOptimisticLockingManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/StandardOptimisticLockingManager.java
@@ -18,9 +18,10 @@ package org.apache.nifi.web;
 
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
+
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.context.ClusterContext;
 import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
index 931f682..97a90d3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/pom.xml
@@ -78,6 +78,10 @@
             <artifactId>nifi-framework-core</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-framework-authorization</artifactId>
+        </dependency>
+        <dependency>
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt</artifactId>
             <version>0.6.0</version>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
index 7108edb..817480f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/NiFiAuthenticationFilter.java
@@ -25,8 +25,8 @@ import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.authentication.AuthenticationManager;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
index 1b2f28a..605e98b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/ProxiedEntitiesUtils.java
@@ -23,7 +23,7 @@ import java.util.regex.Pattern;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
index 3de5a2d..6c14ca5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/anonymous/NiFiAnonymousUserFilter.java
@@ -16,9 +16,9 @@
  */
 package org.apache.nifi.web.security.anonymous;
 
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.security.core.Authentication;
@@ -41,6 +41,7 @@ public class NiFiAnonymousUserFilter extends AnonymousAuthenticationFilter {
 
     @Override
     protected Authentication createAuthentication(HttpServletRequest request) {
+        // TODO - conditional anonymous authentication
         return new NiFiAuthenticationToken(new NiFiUserDetails(NiFiUser.ANONYMOUS));
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
index 289cc87..7634123 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/jwt/JwtAuthenticationProvider.java
@@ -17,10 +17,10 @@
 package org.apache.nifi.web.security.jwt;
 
 import io.jsonwebtoken.JwtException;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.web.security.InvalidAuthenticationException;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/node/NodeAuthorizedUserFilter.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/node/NodeAuthorizedUserFilter.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/node/NodeAuthorizedUserFilter.java
index 03e1400..8451c7c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/node/NodeAuthorizedUserFilter.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/node/NodeAuthorizedUserFilter.java
@@ -24,11 +24,12 @@ import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
+
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.controller.FlowController;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authentication.AuthenticationResponse;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
 import org.apache.nifi.web.security.x509.X509CertificateExtractor;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
index 411efc1..8f2712c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/otp/OtpAuthenticationProvider.java
@@ -16,10 +16,10 @@
  */
 package org.apache.nifi.web.security.otp;
 
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.web.security.InvalidAuthenticationException;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserDetails.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserDetails.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserDetails.java
deleted file mode 100644
index 86668fe..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserDetails.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.web.security.user;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.user.NiFiUser;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-
-import java.util.Collection;
-import java.util.Collections;
-
-/**
- * User details for a NiFi user.
- */
-public class NiFiUserDetails implements UserDetails {
-
-    private final NiFiUser user;
-
-    /**
-     * Creates a new NiFiUserDetails.
-     *
-     * @param user user
-     */
-    public NiFiUserDetails(NiFiUser user) {
-        this.user = user;
-    }
-
-    /**
-     * Get the user for this UserDetails.
-     *
-     * @return user
-     */
-    public NiFiUser getNiFiUser() {
-        return user;
-    }
-
-    /**
-     * Returns the authorities that this NiFi user has.
-     *
-     * @return authorities
-     */
-    @Override
-    public Collection<? extends GrantedAuthority> getAuthorities() {
-        return Collections.EMPTY_SET;
-    }
-
-    @Override
-    public String getPassword() {
-        return StringUtils.EMPTY;
-    }
-
-    @Override
-    public String getUsername() {
-        return user.getIdentity();
-    }
-
-    @Override
-    public boolean isAccountNonExpired() {
-        return true;
-    }
-
-    @Override
-    public boolean isAccountNonLocked() {
-        return true;
-    }
-
-    @Override
-    public boolean isCredentialsNonExpired() {
-        return true;
-    }
-
-    @Override
-    public boolean isEnabled() {
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserUtils.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserUtils.java
deleted file mode 100644
index 255b3d5..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/user/NiFiUserUtils.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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.web.security.user;
-
-import java.util.HashSet;
-import java.util.Set;
-import org.apache.nifi.user.NiFiUser;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.context.SecurityContext;
-import org.springframework.security.core.context.SecurityContextHolder;
-
-/**
- * Utility methods for retrieving information about the current application user.
- *
- */
-public final class NiFiUserUtils {
-
-    /**
-     * Return the authorities for the current user.
-     *
-     * @return authorities
-     */
-    public static Set<String> getAuthorities() {
-        Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
-
-        SecurityContext context = SecurityContextHolder.getContext();
-        if (context != null) {
-            Authentication authentication = context.getAuthentication();
-            if (authentication != null) {
-                // get the authorities for the user of the current request
-                grantedAuthorities.addAll(authentication.getAuthorities());
-            }
-        }
-
-        // convert to a list of authorities
-        Set<String> authorities = new HashSet<>(grantedAuthorities.size());
-        for (GrantedAuthority grantedAuthority : grantedAuthorities) {
-            authorities.add(grantedAuthority.getAuthority());
-        }
-
-        return authorities;
-    }
-
-    /**
-     * Returns the current NiFiUser or null if the current user is not a NiFiUser.
-     *
-     * @return user
-     */
-    public static NiFiUser getNiFiUser() {
-        NiFiUser user = null;
-
-        // obtain the principal in the current authentication
-        final SecurityContext context = SecurityContextHolder.getContext();
-        final Authentication authentication = context.getAuthentication();
-        if (authentication != null) {
-            Object principal = authentication.getPrincipal();
-            if (principal instanceof NiFiUserDetails) {
-                user = ((NiFiUserDetails) principal).getNiFiUser();
-            }
-        }
-
-        return user;
-    }
-
-    public static String getNiFiUserName() {
-        // get the nifi user to extract the username
-        NiFiUser user = NiFiUserUtils.getNiFiUser();
-        if (user == null) {
-            return "unknown";
-        } else {
-            return user.getUserName();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
index 2593f92..43d6958 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/x509/X509AuthenticationProvider.java
@@ -18,11 +18,18 @@ package org.apache.nifi.web.security.x509;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authentication.AuthenticationResponse;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.web.security.InvalidAuthenticationException;
 import org.apache.nifi.web.security.ProxiedEntitiesUtils;
+import org.apache.nifi.web.security.UntrustedProxyException;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.springframework.security.authentication.AuthenticationProvider;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
@@ -37,9 +44,11 @@ import java.util.ListIterator;
 public class X509AuthenticationProvider implements AuthenticationProvider {
 
     private X509IdentityProvider certificateIdentityProvider;
+    private Authorizer authorizer;
 
-    public X509AuthenticationProvider(X509IdentityProvider certificateIdentityProvider) {
+    public X509AuthenticationProvider(final X509IdentityProvider certificateIdentityProvider, final Authorizer authorizer) {
         this.certificateIdentityProvider = certificateIdentityProvider;
+        this.authorizer = authorizer;
     }
 
     @Override
@@ -64,6 +73,24 @@ public class X509AuthenticationProvider implements AuthenticationProvider {
             // add the chain as appropriate to each proxy
             NiFiUser proxy = null;
             for (final ListIterator<String> chainIter = proxyChain.listIterator(proxyChain.size()); chainIter.hasPrevious();) {
+                final String identity = chainIter.previous();
+
+                if (chainIter.hasPrevious()) {
+                    // authorize this proxy in order to authenticate this user
+                    final AuthorizationRequest proxyAuthorizationRequest = new AuthorizationRequest.Builder()
+                        .identity(identity)
+                        .anonymous(false)
+                        .accessAttempt(true)
+                        .action(RequestAction.WRITE)
+                        .resource(ResourceFactory.getProxyResource())
+                        .build();
+
+                    final AuthorizationResult proxyAuthorizationResult = authorizer.authorize(proxyAuthorizationRequest);
+                    if (!Result.Approved.equals(proxyAuthorizationResult.getResult())) {
+                        throw new UntrustedProxyException(String.format("Untrusted proxy %s", identity));
+                    }
+                }
+
                 proxy = new NiFiUser(chainIter.previous(), proxy);
             }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
index 12d8594..b4c3176 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/resources/nifi-web-security-context.xml
@@ -41,7 +41,8 @@
 
     <!-- otp authentication provider -->
     <bean id="x509AuthenticationProvider" class="org.apache.nifi.web.security.x509.X509AuthenticationProvider">
-        <constructor-arg ref="certificateIdentityProvider"/>
+        <constructor-arg ref="certificateIdentityProvider" index="0"/>
+        <constructor-arg ref="authorizer" index="1"/>
     </bean>
 
     <!-- jwt service -->

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/otp/OtpAuthenticationProviderTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/otp/OtpAuthenticationProviderTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/otp/OtpAuthenticationProviderTest.java
index a95c1a0..3fffad1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/otp/OtpAuthenticationProviderTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/test/java/org/apache/nifi/web/security/otp/OtpAuthenticationProviderTest.java
@@ -16,8 +16,8 @@
  */
 package org.apache.nifi.web.security.otp;
 
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.invocation.InvocationOnMock;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js
index 6f27e41..1785ce3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/controllers/nf-ng-breadcrumbs-controller.js
@@ -38,15 +38,15 @@ nf.ng.BreadcrumbsCtrl = (function () {
             /**
              * Generate the breadcrumbs.
              *
-             * @param {object} processGroup  The process group used to generate breadcrumbs
+             * @param {object} breadcrumb  The breadcrumb
              */
-            generateBreadcrumbs: function (processGroup) {
+            generateBreadcrumbs: function (breadcrumb) {
                 //explicitly sanitize processGroup.name
-                processGroup.name = $sanitize(processGroup.name);
-                this.breadcrumbs.unshift(processGroup);
+                breadcrumb.name = $sanitize(breadcrumb.name);
+                this.breadcrumbs.unshift(breadcrumb);
 
-                if (nf.Common.isDefinedAndNotNull(processGroup.parent)) {
-                    this.generateBreadcrumbs(processGroup.parent);
+                if (nf.Common.isDefinedAndNotNull(breadcrumb.parentBreadcrumb)) {
+                    this.generateBreadcrumbs(breadcrumb.parentBreadcrumb);
                 }
             },
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
index e950080..59f56fc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-actions.js
@@ -87,23 +87,16 @@ nf.Actions = (function () {
 
     // create a method for updating process groups and processors
     var updateProcessGroup = function (response) {
-        if (nf.Common.isDefinedAndNotNull(response.processGroup)) {
-            if (nf.Common.isDefinedAndNotNull(response.processGroup.contents)) {
-                var contents = response.processGroup.contents;
-
-                // update all the components in the contents
-                nf.Graph.set(contents);
-
-                // update each process group
-                $.each(contents.processGroups, function (_, processGroup) {
-                    // reload the group's connections
-                    var connections = nf.Connection.getComponentConnections(processGroup.id);
-                    $.each(connections, function (_, connection) {
-                        nf.Connection.reload(connection);
-                    });
-                });
-            }
-        }
+        $.ajax({
+            type: 'GET',
+            url: config.urls.api + '/flow/process-groups/' + encodeURIComponent(response.id),
+            data: {
+                verbose: true
+            },
+            dataType: 'json'
+        }).done(function (response) {
+            nf.Graph.set(response.processGroupFlow.flow);
+        });
     };
 
     return {
@@ -122,7 +115,7 @@ nf.Actions = (function () {
         enterGroup: function (selection) {
             if (selection.size() === 1 && nf.CanvasUtils.isProcessGroup(selection)) {
                 var selectionData = selection.datum();
-                nf.CanvasUtils.enterGroup(selectionData.component.id);
+                nf.CanvasUtils.enterGroup(selectionData.id);
             }
         },
         
@@ -168,7 +161,7 @@ nf.Actions = (function () {
                         if (refreshTimestamp === remoteProcessGroup.flowRefreshed) {
                             schedule(nextDelay);
                         } else {
-                            nf.RemoteProcessGroup.set(response.remoteProcessGroup);
+                            nf.RemoteProcessGroup.set(response);
 
                             // reload the group's connections
                             var connections = nf.Connection.getComponentConnections(remoteProcessGroup.id);
@@ -372,7 +365,7 @@ nf.Actions = (function () {
                     };
                 } else {
                     var selectionData = selection.datum();
-                    var selectionPosition = selectionData.component.position;
+                    var selectionPosition = selectionData.position;
 
                     box = {
                         x: selectionPosition.x,
@@ -413,20 +406,15 @@ nf.Actions = (function () {
                     var selected = d3.select(this);
 
                     // build the entity
-                    var entity = {};
-                    entity[nf[d.type].getEntityKey(d)] = {
-                        'id': d.component.id,
-                        'state': 'STOPPED'
+                    var entity = {
+                        'component': {
+                            'id': d.id,
+                            'state': 'STOPPED'
+                        }
                     };
 
                     enableRequests.push(updateResource(d.component.uri, entity).done(function (response) {
-                        if (nf.CanvasUtils.isProcessor(selected)) {
-                            nf.Processor.set(response.processor);
-                        } else if (nf.CanvasUtils.isInputPort(selected)) {
-                            nf.Port.set(response.inputPort);
-                        } else if (nf.CanvasUtils.isOutputPort(selected)) {
-                            nf.Port.set(response.outputPort);
-                        }
+                        nf[d.type].set(response);
                     }));
                 });
 
@@ -460,20 +448,15 @@ nf.Actions = (function () {
                     var selected = d3.select(this);
 
                     // build the entity
-                    var entity = {};
-                    entity[nf[d.type].getEntityKey(d)] = {
-                        'id': d.component.id,
-                        'state': 'DISABLED'
+                    var entity = {
+                        'component': {
+                            'id': d.id,
+                            'state': 'DISABLED'
+                        }
                     };
 
                     disableRequests.push(updateResource(d.component.uri, entity).done(function (response) {
-                        if (nf.CanvasUtils.isProcessor(selected)) {
-                            nf.Processor.set(response.processor);
-                        } else if (nf.CanvasUtils.isInputPort(selected)) {
-                            nf.Port.set(response.inputPort);
-                        } else if (nf.CanvasUtils.isOutputPort(selected)) {
-                            nf.Port.set(response.outputPort);
-                        }
+                        nf[d.type].set(response);
                     }));
                 });
 
@@ -497,7 +480,7 @@ nf.Actions = (function () {
 
                 // open the provenance page with the specified component
                 nf.Shell.showPage('provenance?' + $.param({
-                    componentId: selectionData.component.id
+                    componentId: selectionData.id
                 }));
             }
         },
@@ -511,7 +494,7 @@ nf.Actions = (function () {
             if (selection.empty()) {
                 // build the entity
                 var entity = {
-                    'processGroup': {
+                    'component': {
                         'id': nf.Canvas.getGroupId(),
                         'running': true
                     }
@@ -538,7 +521,7 @@ nf.Actions = (function () {
 
                         // processor endpoint does not use running flag...
                         var component = {
-                            'id': d.component.id,
+                            'id': d.id,
                         };
                         if (nf.CanvasUtils.isProcessor(selected) || nf.CanvasUtils.isInputPort(selected) || nf.CanvasUtils.isOutputPort(selected)) {
                             component['state'] = 'RUNNING';
@@ -547,24 +530,21 @@ nf.Actions = (function () {
                         }
 
                         // build the entity
-                        var entity = {};
-                        entity[nf[d.type].getEntityKey(d)] = component;
+                        var entity = {
+                            'component': component
+                        };
 
                         startRequests.push(updateResource(d.component.uri, entity).done(function (response) {
-                            if (nf.CanvasUtils.isProcessor(selected)) {
-                                nf.Processor.set(response.processor);
-                            } else if (nf.CanvasUtils.isProcessGroup(selected)) {
-                                nf.ProcessGroup.set(response.processGroup);
+                            if (nf.CanvasUtils.isProcessGroup(selected)) {
+                                nf.ProcessGroup.set(response);
 
                                 // reload the group's connections
-                                var connections = nf.Connection.getComponentConnections(response.processGroup.id);
+                                var connections = nf.Connection.getComponentConnections(response.id);
                                 $.each(connections, function (_, connection) {
                                     nf.Connection.reload(connection);
                                 });
-                            } else if (nf.CanvasUtils.isInputPort(selected)) {
-                                nf.Port.set(response.inputPort);
-                            } else if (nf.CanvasUtils.isOutputPort(selected)) {
-                                nf.Port.set(response.outputPort);
+                            } else {
+                                nf[d.type].set(response);
                             }
                         }));
                     });
@@ -588,7 +568,7 @@ nf.Actions = (function () {
             if (selection.empty()) {
                 // build the entity
                 var entity = {
-                    'processGroup': {
+                    'component': {
                         'id': nf.Canvas.getGroupId(),
                         'running': false
                     }
@@ -615,7 +595,7 @@ nf.Actions = (function () {
 
                         // processor endpoint does not use running flag...
                         var component = {
-                            'id': d.component.id,
+                            'id': d.id,
                         };
                         if (nf.CanvasUtils.isProcessor(selected) || nf.CanvasUtils.isInputPort(selected) || nf.CanvasUtils.isOutputPort(selected)) {
                             component['state'] = 'STOPPED';
@@ -624,24 +604,21 @@ nf.Actions = (function () {
                         }
 
                         // build the entity
-                        var entity = {};
-                        entity[nf[d.type].getEntityKey(d)] = component;
+                        var entity = {
+                            'component': component
+                        };
 
                         stopRequests.push(updateResource(d.component.uri, entity).done(function (response) {
-                            if (nf.CanvasUtils.isProcessor(selected)) {
-                                nf.Processor.set(response.processor);
-                            } else if (nf.CanvasUtils.isProcessGroup(selected)) {
-                                nf.ProcessGroup.set(response.processGroup);
+                            if (nf.CanvasUtils.isProcessGroup(selected)) {
+                                nf.ProcessGroup.set(response);
 
                                 // reload the group's connections
-                                var connections = nf.Connection.getComponentConnections(response.processGroup.id);
+                                var connections = nf.Connection.getComponentConnections(response.id);
                                 $.each(connections, function (_, connection) {
                                     nf.Connection.reload(connection);
                                 });
-                            } else if (nf.CanvasUtils.isInputPort(selected)) {
-                                nf.Port.set(response.inputPort);
-                            } else if (nf.CanvasUtils.isOutputPort(selected)) {
-                                nf.Port.set(response.outputPort);
+                            } else {
+                                nf[d.type].set(response);
                             }
                         }));
                     });
@@ -669,15 +646,16 @@ nf.Actions = (function () {
             // start each selected component
             componentsToEnable.each(function (d) {
                 // build the entity
-                var entity = {};
-                entity[nf[d.type].getEntityKey()] = {
-                    'id': d.component.id,
-                    'transmitting': true
+                var entity = {
+                    'component': {
+                        'id': d.id,
+                        'transmitting': true
+                    }
                 };
 
                 // start transmitting
                 updateResource(d.component.uri, entity).done(function (response) {
-                    nf.RemoteProcessGroup.set(response.remoteProcessGroup);
+                    nf.RemoteProcessGroup.set(response);
                 });
             });
         },
@@ -695,14 +673,15 @@ nf.Actions = (function () {
             // stop each selected component
             componentsToDisable.each(function (d) {
                 // build the entity
-                var entity = {};
-                entity[nf[d.type].getEntityKey()] = {
-                    'id': d.component.id,
-                    'transmitting': false
+                var entity = {
+                    'component': {
+                        'id': d.id,
+                        'transmitting': false
+                    }
                 };
 
                 updateResource(d.component.uri, entity).done(function (response) {
-                    nf.RemoteProcessGroup.set(response.remoteProcessGroup);
+                    nf.RemoteProcessGroup.set(response);
                 });
             });
         },
@@ -735,7 +714,7 @@ nf.Actions = (function () {
             if (selection.size() === 1) {
                 var selectionData = selection.datum();
                 if (nf.CanvasUtils.isProcessor(selection)) {
-                    nf.ProcessorDetails.showDetails(nf.Canvas.getGroupId(), selectionData.component.id);
+                    nf.ProcessorDetails.showDetails(nf.Canvas.getGroupId(), selectionData.id);
                 } else if (nf.CanvasUtils.isProcessGroup(selection)) {
                     nf.ProcessGroupDetails.showDetails(selection);
                 } else if (nf.CanvasUtils.isRemoteProcessGroup(selection)) {
@@ -743,7 +722,7 @@ nf.Actions = (function () {
                 } else if (nf.CanvasUtils.isInputPort(selection) || nf.CanvasUtils.isOutputPort(selection)) {
                     nf.PortDetails.showDetails(selection);
                 } else if (nf.CanvasUtils.isConnection(selection)) {
-                    nf.ConnectionDetails.showDetails(nf.Canvas.getGroupId(), selectionData.component.id);
+                    nf.ConnectionDetails.showDetails(nf.Canvas.getGroupId(), selectionData.id);
                 }
             }
         },
@@ -771,13 +750,13 @@ nf.Actions = (function () {
             if (selection.size() === 1) {
                 var selectionData = selection.datum();
                 if (nf.CanvasUtils.isProcessor(selection)) {
-                    nf.StatusHistory.showProcessorChart(nf.Canvas.getGroupId(), selectionData.component.id);
+                    nf.StatusHistory.showProcessorChart(nf.Canvas.getGroupId(), selectionData.id);
                 } else if (nf.CanvasUtils.isProcessGroup(selection)) {
-                    nf.StatusHistory.showProcessGroupChart(nf.Canvas.getGroupId(), selectionData.component.id);
+                    nf.StatusHistory.showProcessGroupChart(nf.Canvas.getGroupId(), selectionData.id);
                 } else if (nf.CanvasUtils.isRemoteProcessGroup(selection)) {
-                    nf.StatusHistory.showRemoteProcessGroupChart(nf.Canvas.getGroupId(), selectionData.component.id);
+                    nf.StatusHistory.showRemoteProcessGroupChart(nf.Canvas.getGroupId(), selectionData.id);
                 } else if (nf.CanvasUtils.isConnection(selection)) {
-                    nf.StatusHistory.showConnectionChart(nf.Canvas.getGroupId(), selectionData.component.id);
+                    nf.StatusHistory.showConnectionChart(nf.Canvas.getGroupId(), selectionData.id);
                 }
             }
         },
@@ -828,11 +807,11 @@ nf.Actions = (function () {
                         nf.Client.setRevision(response.revision);
 
                         // remove the component/connection in question
-                        nf[selectionData.type].remove(selectionData.component.id);
+                        nf[selectionData.type].remove(selectionData.id);
 
                         // if the selection is a connection, reload the source and destination accordingly
                         if (nf.CanvasUtils.isConnection(selection) === false) {
-                            var connections = nf.Connection.getComponentConnections(selectionData.component.id);
+                            var connections = nf.Connection.getComponentConnections(selectionData.id);
                             if (connections.length > 0) {
                                 var ids = [];
                                 $.each(connections, function (_, connection) {
@@ -869,11 +848,11 @@ nf.Actions = (function () {
                             // go through each component being removed
                             selection.each(function (d) {
                                 // remove the corresponding entry
-                                addComponent(d.type, d.component.id);
+                                addComponent(d.type, d.id);
 
                                 // if this is not a connection, see if it has any connections that need to be removed
                                 if (d.type !== 'Connection') {
-                                    var connections = nf.Connection.getComponentConnections(d.component.id);
+                                    var connections = nf.Connection.getComponentConnections(d.id);
                                     if (connections.length > 0) {
                                         $.each(connections, function (_, connection) {
                                             addComponent('Connection', connection.id);
@@ -1065,7 +1044,7 @@ nf.Actions = (function () {
                     // issue the request to delete the flow files
                     $.ajax({
                         type: 'POST',
-                        url: '../nifi-api/flowfile-queues/' + connection.component.id + '/drop-requests',
+                        url: '../nifi-api/flowfile-queues/' + connection.id + '/drop-requests',
                         dataType: 'json',
                         contentType: 'application/json'
                     }).done(function(response) {
@@ -1365,10 +1344,10 @@ nf.Actions = (function () {
 
                         // copy the snippet to the new location
                         nf.Snippet.copy(snippet.id, origin).done(function (copyResponse) {
-                            var snippetContents = copyResponse.contents;
+                            var snippetFlow = copyResponse.flow;
 
                             // update the graph accordingly
-                            nf.Graph.add(snippetContents, true);
+                            nf.Graph.add(snippetFlow, true);
 
                             // update component visibility
                             nf.Canvas.View.updateVisibility();
@@ -1424,7 +1403,7 @@ nf.Actions = (function () {
             // determine the current max zIndex
             var maxZIndex = -1;
             $.each(nf.Connection.get(), function (_, otherConnection) {
-                if (connection.component.id !== otherConnection.component.id && otherConnection.component.zIndex > maxZIndex) {
+                if (connection.id !== otherConnection.id && otherConnection.component.zIndex > maxZIndex) {
                     maxZIndex = otherConnection.component.zIndex;
                 }
             });
@@ -1437,8 +1416,8 @@ nf.Actions = (function () {
                 // build the connection entity
                 var connectionEntity = {
                     'revision': nf.Client.getRevision(),
-                    'connection': {
-                        'id': connection.component.id,
+                    'component': {
+                        'id': connection.id,
                         'zIndex': zIndex
                     }
                 };
@@ -1452,7 +1431,7 @@ nf.Actions = (function () {
                     contentType: 'application/json'
                 }).done(function (response) {
                     // update the edge's zIndex
-                    nf.Connection.set(response.connection);
+                    nf.Connection.set(response);
                     nf.Connection.reorder();
 
                     // update the revision

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js
index 01abd31..1b23262 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-birdseye.js
@@ -151,50 +151,54 @@ nf.Birdseye = (function () {
         $.each(components.labels, function (_, d) {
             var color = nf.Label.defaultColor();
 
-            // use the specified color if appropriate
-            if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
-                color = d.component.style['background-color'];
+            if (d.accessPolicy.canRead) {
+                // use the specified color if appropriate
+                if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
+                    color = d.component.style['background-color'];
+                }
             }
 
             context.fillStyle = color;
-            context.fillRect(d.component.position.x, d.component.position.y, d.dimensions.width, d.dimensions.height);
+            context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
         });
 
         // funnels
         context.fillStyle = '#9f6000';
         $.each(components.funnels, function (_, d) {
-            context.fillRect(d.component.position.x, d.component.position.y, d.dimensions.width, d.dimensions.height);
+            context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
         });
 
         // ports
         context.fillStyle = '#aaa';
         $.each(components.ports, function (_, d) {
-            context.fillRect(d.component.position.x, d.component.position.y, d.dimensions.width, d.dimensions.height);
+            context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
         });
 
         // remote process groups
         context.fillStyle = '#294c58';
         $.each(components.remoteProcessGroups, function (_, d) {
-            context.fillRect(d.component.position.x, d.component.position.y, d.dimensions.width, d.dimensions.height);
+            context.fillRect(d.position.x, d.position.y, d.dimensions.width, d.dimensions.height);
         });
 
         // process groups
         context.fillStyle = '#294c58';
         $.each(components.processGroups, function (_, d) {
-            context.fillRect(d.component.position.x, d.component.position.y, d.dimensions.width, d.dimensions.height);
+            context.fillRect(d.x, d.y, d.dimensions.width, d.dimensions.height);
         });
 
         // processors
         $.each(components.processors, function (_, d) {
             var color = nf.Processor.defaultColor();
 
-            // use the specified color if appropriate
-            if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
-                color = d.component.style['background-color'];
+            if (d.accessPolicy.canRead) {
+                // use the specified color if appropriate
+                if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
+                    color = d.component.style['background-color'];
+                }
             }
 
             context.fillStyle = color;
-            context.fillRect(d.component.position.x, d.component.position.y, d.dimensions.width, d.dimensions.height);
+            context.fillRect(d.x, d.y, d.dimensions.width, d.dimensions.height);
         });
 
         context.restore();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.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-header.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
index 6ed6c5d..fbe4b7d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-header.js
@@ -166,12 +166,12 @@ nf.CanvasHeader = (function () {
                                     if (color !== selectedData.component.style['background-color']) {
                                         // build the request entity
                                         var entity = {
-                                            'revision': nf.Client.getRevision()
-                                        };
-                                        entity[nf[selectedData.type].getEntityKey()] = {
-                                            'id': selectedData.component.id,
-                                            'style': {
-                                                'background-color': color
+                                            'revision': nf.Client.getRevision(),
+                                            'component': {
+                                                'id': selectedData.id,
+                                                'style': {
+                                                    'background-color': color
+                                                }
                                             }
                                         };
 
@@ -186,12 +186,8 @@ nf.CanvasHeader = (function () {
                                             // update the revision
                                             nf.Client.setRevision(response.revision);
 
-                                            // update the processor
-                                            if (nf.CanvasUtils.isProcessor(selected)) {
-                                                nf.Processor.set(response.processor);
-                                            } else {
-                                                nf.Label.set(response.label);
-                                            }
+                                            // update the component
+                                            nf[selectedData.type].set(response);
                                         }).fail(function (xhr, status, error) {
                                             if (xhr.status === 400 || xhr.status === 404 || xhr.status === 409) {
                                                 nf.Dialog.showOkDialog({

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbar.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-toolbar.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbar.js
index 8aade5c..9cae764 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbar.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbar.js
@@ -109,61 +109,62 @@ nf.CanvasToolbar = (function () {
             }
 
             // only refresh the toolbar if DFM
-            if (nf.Common.isDFM()) {
-                var selection = nf.CanvasUtils.getSelection();
+            var selection = nf.CanvasUtils.getSelection();
+            if (nf.CanvasUtils.canModify(selection) === false) {
+                return;
+            }
 
-                // if all selected components are deletable enable the delete button
-                if (!selection.empty()) {
-                    var enableDelete = true;
-                    selection.each(function (d) {
-                        if (!nf.CanvasUtils.isDeletable(d3.select(this))) {
-                            enableDelete = false;
-                            return false;
-                        }
-                    });
-                    if (enableDelete) {
-                        actions['delete'].enable();
-                    } else {
-                        actions['delete'].disable();
+            // if all selected components are deletable enable the delete button
+            if (!selection.empty()) {
+                var enableDelete = true;
+                selection.each(function (d) {
+                    if (!nf.CanvasUtils.isDeletable(d3.select(this))) {
+                        enableDelete = false;
+                        return false;
                     }
+                });
+                if (enableDelete) {
+                    actions['delete'].enable();
                 } else {
                     actions['delete'].disable();
                 }
+            } else {
+                actions['delete'].disable();
+            }
 
-                // if there are any copyable components enable the button
-                if (nf.CanvasUtils.isCopyable(selection)) {
-                    actions['copy'].enable();
-                } else {
-                    actions['copy'].disable();
-                }
+            // if there are any copyable components enable the button
+            if (nf.CanvasUtils.isCopyable(selection)) {
+                actions['copy'].enable();
+            } else {
+                actions['copy'].disable();
+            }
 
-                // determine if the selection is groupable
-                if (!selection.empty() && nf.CanvasUtils.isDisconnected(selection)) {
-                    actions['group'].enable();
-                } else {
-                    actions['group'].disable();
-                }
+            // determine if the selection is groupable
+            if (!selection.empty() && nf.CanvasUtils.isDisconnected(selection)) {
+                actions['group'].enable();
+            } else {
+                actions['group'].disable();
+            }
 
-                // if there are any colorable components enable the fill button
-                if (nf.CanvasUtils.isColorable(selection)) {
-                    actions['fill'].enable();
-                } else {
-                    actions['fill'].disable();
-                }
-                
-                // ensure the selection supports enable
-                if (nf.CanvasUtils.canEnable(selection)) {
-                    actions['enable'].enable();
-                } else {
-                    actions['enable'].disable();
-                }
+            // if there are any colorable components enable the fill button
+            if (nf.CanvasUtils.isColorable(selection)) {
+                actions['fill'].enable();
+            } else {
+                actions['fill'].disable();
+            }
+            
+            // ensure the selection supports enable
+            if (nf.CanvasUtils.canEnable(selection)) {
+                actions['enable'].enable();
+            } else {
+                actions['enable'].disable();
+            }
 
-                // ensure the selection supports disable
-                if (nf.CanvasUtils.canDisable(selection)) {
-                    actions['disable'].enable();
-                } else {
-                    actions['disable'].disable();
-                }
+            // ensure the selection supports disable
+            if (nf.CanvasUtils.canDisable(selection)) {
+                actions['disable'].enable();
+            } else {
+                actions['disable'].disable();
             }
         }
     };

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.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-toolbox.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
index de40653..aca5a9e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-toolbox.js
@@ -363,7 +363,7 @@ nf.CanvasToolbox = (function () {
     var createProcessor = function (name, processorType, pt) {
         var processorEntity = {
             'revision': nf.Client.getRevision(),
-            'processor': {
+            'component': {
                 'type': processorType,
                 'name': name,
                 'position': {
@@ -381,13 +381,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.processor)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
                 // add the processor to the graph
                 nf.Graph.add({
-                    'processors': [response.processor]
+                    'processors': [response]
                 }, true);
 
                 // update component visibility
@@ -454,7 +454,7 @@ nf.CanvasToolbox = (function () {
     var createInputPort = function (portName, pt) {
         var inputPortEntity = {
             'revision': nf.Client.getRevision(),
-            'inputPort': {
+            'component': {
                 'name': portName,
                 'position': {
                     'x': pt.x,
@@ -471,13 +471,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.inputPort)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
                 // add the port to the graph
                 nf.Graph.add({
-                    'inputPorts': [response.inputPort]
+                    'inputPorts': [response]
                 }, true);
 
                 // update component visibility
@@ -544,7 +544,7 @@ nf.CanvasToolbox = (function () {
     var createOutputPort = function (portName, pt) {
         var outputPortEntity = {
             'revision': nf.Client.getRevision(),
-            'outputPort': {
+            'component': {
                 'name': portName,
                 'position': {
                     'x': pt.x,
@@ -561,13 +561,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.outputPort)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
                 // add the port to the graph
                 nf.Graph.add({
-                    'outputPorts': [response.outputPort]
+                    'outputPorts': [response]
                 }, true);
 
                 // update component visibility
@@ -588,7 +588,7 @@ nf.CanvasToolbox = (function () {
     var createGroup = function (groupName, pt) {
         var processGroupEntity = {
             'revision': nf.Client.getRevision(),
-            'processGroup': {
+            'component': {
                 'name': groupName,
                 'position': {
                     'x': pt.x,
@@ -605,13 +605,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.processGroup)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
-                // add the processor to the graph
+                // add the process group to the graph
                 nf.Graph.add({
-                    'processGroups': [response.processGroup]
+                    'processGroups': [response]
                 }, true);
 
                 // update component visibility
@@ -675,7 +675,7 @@ nf.CanvasToolbox = (function () {
     var createRemoteProcessGroup = function (remoteProcessGroupUri, pt) {
         var remoteProcessGroupEntity = {
             'revision': nf.Client.getRevision(),
-            'remoteProcessGroup': {
+            'component': {
                 'targetUri': remoteProcessGroupUri,
                 'position': {
                     'x': pt.x,
@@ -684,7 +684,7 @@ nf.CanvasToolbox = (function () {
             }
         };
 
-        // create a new processor of the defined type
+        // create a new remote process group of the defined type
         $.ajax({
             type: 'POST',
             url: config.urls.api + '/process-groups/' + encodeURIComponent(nf.Canvas.getGroupId()) + '/remote-process-groups',
@@ -692,13 +692,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.remoteProcessGroup)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
                 // add the processor to the graph
                 nf.Graph.add({
-                    'remoteProcessGroups': [response.remoteProcessGroup]
+                    'remoteProcessGroups': [response]
                 }, true);
 
                 // update component visibility
@@ -718,7 +718,7 @@ nf.CanvasToolbox = (function () {
     var createFunnel = function (pt) {
         var outputPortEntity = {
             'revision': nf.Client.getRevision(),
-            'funnel': {
+            'component': {
                 'position': {
                     'x': pt.x,
                     'y': pt.y
@@ -734,13 +734,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.funnel)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
                 // add the funnel to the graph
                 nf.Graph.add({
-                    'funnels': [response.funnel]
+                    'funnels': [response]
                 }, true);
 
                 // update the birdseye
@@ -841,7 +841,7 @@ nf.CanvasToolbox = (function () {
             nf.Client.setRevision(response.revision);
 
             // populate the graph accordingly
-            nf.Graph.add(response.contents, true);
+            nf.Graph.add(response.flow, true);
 
             // update component visibility
             nf.Canvas.View.updateVisibility();
@@ -859,7 +859,7 @@ nf.CanvasToolbox = (function () {
     var createLabel = function (pt) {
         var labelEntity = {
             'revision': nf.Client.getRevision(),
-            'label': {
+            'component': {
                 'width': nf.Label.config.width,
                 'height': nf.Label.config.height,
                 'position': {
@@ -877,13 +877,13 @@ nf.CanvasToolbox = (function () {
             dataType: 'json',
             contentType: 'application/json'
         }).done(function (response) {
-            if (nf.Common.isDefinedAndNotNull(response.label)) {
+            if (nf.Common.isDefinedAndNotNull(response.component)) {
                 // update the revision
                 nf.Client.setRevision(response.revision);
 
                 // add the label to the graph
                 nf.Graph.add({
-                    'labels': [response.label]
+                    'labels': [response]
                 }, true);
 
                 // update the birdseye
@@ -1135,7 +1135,7 @@ nf.CanvasToolbox = (function () {
 
                     // create the group and resolve the deferred accordingly
                     createGroup(groupName, pt).done(function (response) {
-                        deferred.resolve(response.processGroup);
+                        deferred.resolve(response.component);
                     }).fail(function () {
                         deferred.reject();
                     });

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.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-utils.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
index 0a9cf28..55c4b49 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-canvas-utils.js
@@ -74,7 +74,7 @@ nf.CanvasUtils = (function () {
 
                         // go through each component being removed
                         components.each(function (d) {
-                            addComponent(d.type, d.component.id);
+                            addComponent(d.type, d.id);
                         });
 
                         // refresh all component types as necessary (handle components that have been removed)
@@ -271,7 +271,7 @@ nf.CanvasUtils = (function () {
 
             // update the processors positioning
             updated.attr('transform', function (d) {
-                return 'translate(' + d.component.position.x + ', ' + d.component.position.y + ')';
+                return 'translate(' + d.position.x + ', ' + d.position.y + ')';
             });
         },
         
@@ -467,7 +467,7 @@ nf.CanvasUtils = (function () {
             offset = nf.Common.isDefinedAndNotNull(offset) ? offset : 0;
 
             // remove any existing tip if necessary
-            var tip = d3.select('#bulletin-tip-' + d.component.id);
+            var tip = d3.select('#bulletin-tip-' + d.id);
             if (!tip.empty()) {
                 tip.remove();
             }
@@ -488,7 +488,7 @@ nf.CanvasUtils = (function () {
                             // if there are bulletins generate a tooltip
                             tip = getTooltipContainer().append('div')
                                     .attr('id', function () {
-                                        return 'bulletin-tip-' + d.component.id;
+                                        return 'bulletin-tip-' + d.id;
                                     })
                                     .attr('class', 'tooltip nifi-tooltip')
                                     .html(function () {
@@ -843,6 +843,36 @@ nf.CanvasUtils = (function () {
 
             return nf.CanvasUtils.supportsModification(selection);
         },
+
+        /**
+         * Determines whether the components in the specified selection are writable.
+         *
+         * @argument {selection} selection      The selection
+         * @return {boolean}            Whether the selection is writable
+         */
+        canModify: function (selection) {
+            var selectionSize = selection.size();
+            var writableSize = selection.filter(function (d) {
+                return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+            }).size();
+            
+            return selectionSize === writableSize;
+        },
+
+        /**
+         * Determines whether the components in the specified selection are readable.
+         *
+         * @argument {selection} selection      The selection
+         * @return {boolean}            Whether the selection is readable
+         */
+        canRead: function (selection) {
+            var selectionSize = selection.size();
+            var readableSize = selection.filter(function (d) {
+                return d.accessPolicy.canRead;
+            }).size();
+
+            return selectionSize === readableSize;
+        },
         
         /**
          * Determines whether the specified selection is in a state to support modification.
@@ -875,7 +905,7 @@ nf.CanvasUtils = (function () {
                 var isSourceConfigurable = false;
                 var isDestinationConfigurable = false;
 
-                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(selectionData.component);
+                var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(selectionData);
                 var source = d3.select('#id-' + sourceComponentId);
                 if (!source.empty()) {
                     if (nf.CanvasUtils.isRemoteProcessGroup(source) || nf.CanvasUtils.isProcessGroup(source)) {
@@ -885,7 +915,7 @@ nf.CanvasUtils = (function () {
                     }
                 }
 
-                var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(selectionData.component);
+                var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(selectionData);
                 var destination = d3.select('#id-' + destinationComponentId);
                 if (!destination.empty()) {
                     if (nf.CanvasUtils.isRemoteProcessGroup(destination) || nf.CanvasUtils.isProcessGroup(destination)) {
@@ -958,12 +988,12 @@ nf.CanvasUtils = (function () {
                 var selected = d3.select(this);
                 if (nf.CanvasUtils.isConnection(selected)) {
                     var sourceIncluded = !selection.filter(function (source) {
-                        var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d.component);
-                        return sourceComponentId === source.component.id;
+                        var sourceComponentId = nf.CanvasUtils.getConnectionSourceComponentId(d);
+                        return sourceComponentId === source.id;
                     }).empty();
                     var destinationIncluded = !selection.filter(function (destination) {
-                        var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d.component);
-                        return destinationComponentId === destination.component.id;
+                        var destinationComponentId = nf.CanvasUtils.getConnectionDestinationComponentId(d);
+                        return destinationComponentId === destination.id;
                     }).empty();
                     return sourceIncluded && destinationIncluded;
                 } else {
@@ -1026,13 +1056,15 @@ nf.CanvasUtils = (function () {
                 if (source.empty() === false) {
                     var sourceData = source.datum();
 
-                    // update the source status if necessary
-                    if (nf.CanvasUtils.isProcessor(source)) {
-                        nf.Processor.reload(sourceData.component);
-                    } else if (nf.CanvasUtils.isInputPort(source)) {
-                        nf.Port.reload(sourceData.component);
-                    } else if (nf.CanvasUtils.isRemoteProcessGroup(source)) {
-                        nf.RemoteProcessGroup.reload(sourceData.component);
+                    if (sourceData.accessPolicy.canRead) {
+                        // update the source status if necessary
+                        if (nf.CanvasUtils.isProcessor(source)) {
+                            nf.Processor.reload(sourceData.component);
+                        } else if (nf.CanvasUtils.isInputPort(source)) {
+                            nf.Port.reload(sourceData.component);
+                        } else if (nf.CanvasUtils.isRemoteProcessGroup(source)) {
+                            nf.RemoteProcessGroup.reload(sourceData.component);
+                        }
                     }
                 }
             }
@@ -1042,11 +1074,13 @@ nf.CanvasUtils = (function () {
                 if (destination.empty() === false) {
                     var destinationData = destination.datum();
 
-                    // update the destination component accordingly
-                    if (nf.CanvasUtils.isProcessor(destination)) {
-                        nf.Processor.reload(destinationData.component);
-                    } else if (nf.CanvasUtils.isRemoteProcessGroup(destination)) {
-                        nf.RemoteProcessGroup.reload(destinationData.component);
+                    if (destinationData.accessPolicy.canRead) {
+                        // update the destination component accordingly
+                        if (nf.CanvasUtils.isProcessor(destination)) {
+                            nf.Processor.reload(destinationData.component);
+                        } else if (nf.CanvasUtils.isRemoteProcessGroup(destination)) {
+                            nf.RemoteProcessGroup.reload(destinationData.component);
+                        }
                     }
                 }
             }
@@ -1060,9 +1094,9 @@ nf.CanvasUtils = (function () {
          * @param {object} connection   The connection in question
          */
         getConnectionSourceComponentId: function (connection) {
-            var sourceId = connection.source.id;
-            if (connection.source.groupId !== nf.Canvas.getGroupId()) {
-                sourceId = connection.source.groupId;
+            var sourceId = connection.sourceId;
+            if (connection.sourceGroupId !== nf.Canvas.getGroupId()) {
+                sourceId = connection.sourceGroupId;
             }
             return sourceId;
         },
@@ -1075,9 +1109,9 @@ nf.CanvasUtils = (function () {
          * @param {object} connection   The connection in question
          */
         getConnectionDestinationComponentId: function (connection) {
-            var destinationId = connection.destination.id;
-            if (connection.destination.groupId !== nf.Canvas.getGroupId()) {
-                destinationId = connection.destination.groupId;
+            var destinationId = connection.destinationId;
+            if (connection.destinationGroupId !== nf.Canvas.getGroupId()) {
+                destinationId = connection.destinationGroupId;
             }
             return destinationId;
         },
@@ -1162,11 +1196,11 @@ nf.CanvasUtils = (function () {
             selection.each(function (d) {
                 var selected = d3.select(this);
                 if (!nf.CanvasUtils.isConnection(selected)) {
-                    if (nf.Common.isUndefined(origin.x) || d.component.position.x < origin.x) {
-                        origin.x = d.component.position.x;
+                    if (nf.Common.isUndefined(origin.x) || d.position.x < origin.x) {
+                        origin.x = d.position.x;
                     }
-                    if (nf.Common.isUndefined(origin.y) || d.component.position.y < origin.y) {
-                        origin.y = d.component.position.y;
+                    if (nf.Common.isUndefined(origin.y) || d.position.y < origin.y) {
+                        origin.y = d.position.y;
                     }
                 }
             });
@@ -1200,7 +1234,7 @@ nf.CanvasUtils = (function () {
             var groupData = group.datum();
             
             // move the components into the destination and...
-            moveComponents(components, groupData.component.id).done(function () {
+            moveComponents(components, groupData.id).done(function () {
                 // reload the target group
                 nf.ProcessGroup.reload(groupData.component);
             });
@@ -1223,10 +1257,10 @@ nf.CanvasUtils = (function () {
                 var includesSource = false;
                 var includesDestination = false;
                 selection.each(function (d) {
-                    if (d.component.id === sourceComponentId) {
+                    if (d.id === sourceComponentId) {
                         includesSource = true;
                     }
-                    if (d.component.id === destinationComponentId) {
+                    if (d.id === destinationComponentId) {
                         includesDestination = true;
                     }
                 });
@@ -1237,7 +1271,7 @@ nf.CanvasUtils = (function () {
             // include all components and connections whose source/destination are also selected
             return selection.filter(function (d) {
                 if (d.type === 'Connection') {
-                    return keepConnection(d.component);
+                    return keepConnection(d);
                 } else {
                     return true;
                 }
@@ -1258,17 +1292,17 @@ nf.CanvasUtils = (function () {
             selection.filter(function (d) {
                 return d.type === 'Connection';
             }).each(function (d) {
-                connections.set(d.component.id, d.component);
+                connections.set(d.id, d);
             });
 
             // include components and ensure their connections are included
             selection.filter(function (d) {
                 return d.type !== 'Connection';
             }).each(function (d) {
-                components.set(d.component.id, d.component);
+                components.set(d.id, d.component);
 
                 // check all connections of this component
-                $.each(nf.Connection.getComponentConnections(d.component.id), function (_, connection) {
+                $.each(nf.Connection.getComponentConnections(d.id), function (_, connection) {
                     if (!connections.has(connection.id)) {
                         isDisconnected = false;
                         return false;
@@ -1338,7 +1372,7 @@ nf.CanvasUtils = (function () {
                                         // check the input ports
                                         $.each(inputPorts, function (i, inputPort) {
                                             $.each(connections, function (j, connection) {
-                                                if (inputPort.component.id === connection.destination.id) {
+                                                if (inputPort.id === connection.destination.id) {
                                                     conflictingPorts.push(nf.Common.escapeHtml(inputPort.component.name));
                                                 }
                                             });
@@ -1347,7 +1381,7 @@ nf.CanvasUtils = (function () {
                                         // check the output ports
                                         $.each(outputPorts, function (i, outputPort) {
                                             $.each(connections, function (j, connection) {
-                                                if (outputPort.component.id === connection.source.id) {
+                                                if (outputPort.id === connection.source.id) {
                                                     conflictingPorts.push(nf.Common.escapeHtml(outputPort.component.name));
                                                 }
                                             });
@@ -1385,7 +1419,7 @@ nf.CanvasUtils = (function () {
                                 },
                                 dataType: 'json'
                             }).done(function (response) {
-                                var processGroup = response.processGroup;
+                                var processGroup = response.component;
                                 var processGroupContents = processGroup.contents;
 
                                 var conflictingPorts = [];


[12/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java
index b041e51..ed4a38f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionEntity.java
@@ -16,26 +16,119 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import javax.xml.bind.annotation.XmlRootElement;
+import com.wordnik.swagger.annotations.ApiModelProperty;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
+import org.apache.nifi.web.api.dto.PositionDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
 
 /**
  * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a ConnectionDTO.
  */
 @XmlRootElement(name = "connectionEntity")
-public class ConnectionEntity extends Entity {
+public class ConnectionEntity extends ComponentEntity {
 
-    private ConnectionDTO connection;
+    private ConnectionDTO component;
+    private List<PositionDTO> bends;
+    private Integer labelIndex;
+    private String sourceId;
+    private String sourceGroupId;
+    private String destinationId;
+    private String destinationGroupId;
 
     /**
      * @return RelationshipDTO that is being serialized
      */
-    public ConnectionDTO getConnection() {
-        return connection;
+    public ConnectionDTO getComponent() {
+        return component;
+    }
+
+    public void setComponent(ConnectionDTO component) {
+        this.component = component;
+    }
+
+    /**
+     * @return position of the bend points on this connection
+     */
+    @ApiModelProperty(
+        value = "The bend points on the connection."
+    )
+    public List<PositionDTO> getBends() {
+        return bends;
+    }
+
+    public void setBends(List<PositionDTO> bends) {
+        this.bends = bends;
+    }
+
+    /**
+     * @return The index of control point that the connection label should be placed over
+     */
+    @ApiModelProperty(
+        value = "The index of the bend point where to place the connection label."
+    )
+    public Integer getLabelIndex() {
+        return labelIndex;
+    }
+
+    public void setLabelIndex(Integer labelIndex) {
+        this.labelIndex = labelIndex;
+    }
+
+    /**
+     * @return The identifier of the source of this connection
+     */
+    @ApiModelProperty(
+        value = "The identifier of the source of this connection."
+    )
+    public String getSourceId() {
+        return sourceId;
+    }
+
+    public void setSourceId(String sourceId) {
+        this.sourceId = sourceId;
+    }
+
+    /**
+     * @return The identifier of the destination of this connection
+     */
+    @ApiModelProperty(
+        value = "The identifier of the destination of this connection."
+    )
+    public String getDestinationId() {
+        return destinationId;
     }
 
-    public void setConnection(ConnectionDTO connection) {
-        this.connection = connection;
+    public void setDestinationId(String destinationId) {
+        this.destinationId = destinationId;
     }
 
+    /**
+     * @return The identifier of the group of the source of this connection
+     */
+    @ApiModelProperty(
+        value = "The identifier of the group of the source of this connection."
+    )
+    public String getSourceGroupId() {
+        return sourceGroupId;
+    }
+
+    public void setSourceGroupId(String sourceGroupId) {
+        this.sourceGroupId = sourceGroupId;
+    }
+
+    /**
+     * @return The identifier of the group of the destination of this connection
+     */
+    @ApiModelProperty(
+        value = "The identifier of the group of the destination of this connection."
+    )
+    public String getDestinationGroupId() {
+        return destinationGroupId;
+    }
+
+    public void setDestinationGroupId(String destinationGroupId) {
+        this.destinationGroupId = destinationGroupId;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionsEntity.java
index 5b2b1b0..51f17b9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ConnectionsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.ConnectionDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of ConnectionDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of ConnectionEntitys.
  */
 @XmlRootElement(name = "connectionsEntity")
 public class ConnectionsEntity extends Entity {
 
-    private Set<ConnectionDTO> connections;
+    private Set<ConnectionEntity> connections;
 
     /**
-     * @return list of ConnectionDTOs that are being serialized
+     * @return list of ConnectionEntitys that are being serialized
      */
-    public Set<ConnectionDTO> getConnections() {
+    public Set<ConnectionEntity> getConnections() {
         return connections;
     }
 
-    public void setConnections(Set<ConnectionDTO> connections) {
+    public void setConnections(Set<ConnectionEntity> connections) {
         this.connections = connections;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
index 8f217b5..8e96e48 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ControllerServiceEntity.java
@@ -23,7 +23,7 @@ import org.apache.nifi.web.api.dto.ControllerServiceDTO;
  * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a controller service.
  */
 @XmlRootElement(name = "controllerServiceEntity")
-public class ControllerServiceEntity extends Entity {
+public class ControllerServiceEntity extends ComponentEntity {
 
     private ControllerServiceDTO controllerService;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/Entity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/Entity.java
index 13c7a70..a961d14 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/Entity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/Entity.java
@@ -17,9 +17,10 @@
 package org.apache.nifi.web.api.entity;
 
 import com.wordnik.swagger.annotations.ApiModelProperty;
-import javax.xml.bind.annotation.XmlRootElement;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 
+import javax.xml.bind.annotation.XmlRootElement;
+
 /**
  * A base type for request/response entities.
  */
@@ -34,6 +35,7 @@ public class Entity {
     @ApiModelProperty(
             value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses."
     )
+    @Deprecated
     public RevisionDTO getRevision() {
         if (revision == null) {
             return new RevisionDTO();
@@ -42,6 +44,7 @@ public class Entity {
         }
     }
 
+    @Deprecated
     public void setRevision(RevisionDTO revision) {
         this.revision = revision;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowEntity.java
new file mode 100644
index 0000000..d9c22b7
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FlowEntity.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a FlowDTO.
+ */
+@XmlRootElement(name = "flowEntity")
+public class FlowEntity extends Entity {
+
+    private FlowDTO flow;
+
+    /**
+     * The FlowDTO that is being serialized.
+     *
+     * @return The FlowDTO object
+     */
+    public FlowDTO getFlow() {
+        return flow;
+    }
+
+    public void setFlow(FlowDTO flow) {
+        this.flow = flow;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelEntity.java
index 241ac51..54ff2ed 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelEntity.java
@@ -23,21 +23,21 @@ import org.apache.nifi.web.api.dto.FunnelDTO;
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a FunnelDTO.
  */
 @XmlRootElement(name = "funnelEntity")
-public class FunnelEntity extends Entity {
+public class FunnelEntity extends ComponentEntity {
 
-    private FunnelDTO funnel;
+    private FunnelDTO component;
 
     /**
      * The FunnelDTO that is being serialized.
      *
      * @return The FunnelDTO object
      */
-    public FunnelDTO getFunnel() {
-        return funnel;
+    public FunnelDTO getComponent() {
+        return component;
     }
 
-    public void setFunnel(FunnelDTO funnel) {
-        this.funnel = funnel;
+    public void setComponent(FunnelDTO component) {
+        this.component = component;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelsEntity.java
index 34426db..246f222 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/FunnelsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.FunnelDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of FunnelDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of FunnelEntitys.
  */
 @XmlRootElement(name = "funnelsEntity")
 public class FunnelsEntity extends Entity {
 
-    private Set<FunnelDTO> funnels;
+    private Set<FunnelEntity> funnels;
 
     /**
-     * @return collection of FunnelDTOs that are being serialized
+     * @return collection of FunnelEntitys that are being serialized
      */
-    public Set<FunnelDTO> getFunnels() {
+    public Set<FunnelEntity> getFunnels() {
         return funnels;
     }
 
-    public void setFunnels(Set<FunnelDTO> labels) {
+    public void setFunnels(Set<FunnelEntity> labels) {
         this.funnels = labels;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortEntity.java
deleted file mode 100644
index f92c478..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortEntity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.web.api.entity;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.PortDTO;
-
-/**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to an input PortDTO.
- */
-@XmlRootElement(name = "inputPortEntity")
-public class InputPortEntity extends Entity {
-
-    private PortDTO inputPort;
-
-    /**
-     * @return input PortDTO that are being serialized
-     */
-    public PortDTO getInputPort() {
-        return inputPort;
-    }
-
-    public void setInputPort(PortDTO inputPort) {
-        this.inputPort = inputPort;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortsEntity.java
index 93a03e7..ba18881 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/InputPortsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.PortDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of input PortDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of input InputPortEntitys.
  */
 @XmlRootElement(name = "inputPortsEntity")
 public class InputPortsEntity extends Entity {
 
-    private Set<PortDTO> inputPorts;
+    private Set<PortEntity> inputPorts;
 
     /**
-     * @return collection of input PortDTOs that are being serialized
+     * @return collection of input InputPortEntitys that are being serialized
      */
-    public Set<PortDTO> getInputPorts() {
+    public Set<PortEntity> getInputPorts() {
         return inputPorts;
     }
 
-    public void setInputPorts(Set<PortDTO> inputPorts) {
+    public void setInputPorts(Set<PortEntity> inputPorts) {
         this.inputPorts = inputPorts;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java
index 535240c..48e2aa7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelEntity.java
@@ -16,28 +16,43 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.nifi.web.api.dto.DimensionsDTO;
 import org.apache.nifi.web.api.dto.LabelDTO;
 
+import javax.xml.bind.annotation.XmlRootElement;
+
 /**
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a LabelDTO.
  */
 @XmlRootElement(name = "labelEntity")
-public class LabelEntity extends Entity {
+public class LabelEntity extends ComponentEntity {
 
-    private LabelDTO label;
+    private DimensionsDTO dimensions;
+    private LabelDTO component;
 
     /**
      * The LabelDTO that is being serialized.
      *
      * @return The LabelDTO object
      */
-    public LabelDTO getLabel() {
-        return label;
+    public LabelDTO getComponent() {
+        return component;
     }
 
-    public void setLabel(LabelDTO label) {
-        this.label = label;
+    public void setComponent(LabelDTO component) {
+        this.component = component;
     }
 
+    /**
+     * The dimensions of this label.
+     *
+     * @return The dimensions
+     */
+    public DimensionsDTO getDimensions() {
+        return dimensions;
+    }
+
+    public void setDimensions(DimensionsDTO dimensions) {
+        this.dimensions = dimensions;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelsEntity.java
index 05dab6c..855ce6c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/LabelsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.LabelDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of LabelDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of LabelEntity's.
  */
 @XmlRootElement(name = "labelsEntity")
 public class LabelsEntity extends Entity {
 
-    private Set<LabelDTO> labels;
+    private Set<LabelEntity> labels;
 
     /**
-     * @return collection of LabelDTOs that are being serialized
+     * @return collection of LabelEntity's that are being serialized
      */
-    public Set<LabelDTO> getLabels() {
+    public Set<LabelEntity> getLabels() {
         return labels;
     }
 
-    public void setLabels(Set<LabelDTO> labels) {
+    public void setLabels(Set<LabelEntity> labels) {
         this.labels = labels;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortEntity.java
deleted file mode 100644
index 4f40aec..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortEntity.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.web.api.entity;
-
-import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.PortDTO;
-
-/**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to an output PortDTO.
- */
-@XmlRootElement(name = "outputPortEntity")
-public class OutputPortEntity extends Entity {
-
-    private PortDTO outputPort;
-
-    /**
-     * @return output PortDTO that are being serialized
-     */
-    public PortDTO getOutputPort() {
-        return outputPort;
-    }
-
-    public void setOutputPort(PortDTO outputPort) {
-        this.outputPort = outputPort;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortsEntity.java
index e624c52..9b98414 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/OutputPortsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.PortDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of output PortDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of output OutputPortEntitys.
  */
 @XmlRootElement(name = "outputPortsEntity")
 public class OutputPortsEntity extends Entity {
 
-    private Set<PortDTO> outputPorts;
+    private Set<PortEntity> outputPorts;
 
     /**
-     * @return collection of output PortDTOs that are being serialized
+     * @return collection of output OutputPortEntitys that are being serialized
      */
-    public Set<PortDTO> getOutputPorts() {
+    public Set<PortEntity> getOutputPorts() {
         return outputPorts;
     }
 
-    public void setOutputPorts(Set<PortDTO> outputPorts) {
+    public void setOutputPorts(Set<PortEntity> outputPorts) {
         this.outputPorts = outputPorts;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
new file mode 100644
index 0000000..0dc4fdc
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/PortEntity.java
@@ -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.web.api.entity;
+
+import org.apache.nifi.web.api.dto.PortDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to an input PortDTO.
+ */
+@XmlRootElement(name = "portEntity")
+public class PortEntity extends ComponentEntity {
+
+    private PortDTO component;
+    private String portType;
+
+    /**
+     * @return input PortDTO that are being serialized
+     */
+    public PortDTO getComponent() {
+        return component;
+    }
+
+    public void setComponent(PortDTO component) {
+        this.component = component;
+    }
+
+    public String getPortType() {
+        return portType;
+    }
+
+    public void setPortType(String portType) {
+        this.portType = portType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java
index d1ec034..06e78e5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupEntity.java
@@ -23,21 +23,21 @@ import org.apache.nifi.web.api.dto.ProcessGroupDTO;
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a ProcessGroupDTO.
  */
 @XmlRootElement(name = "processGroupEntity")
-public class ProcessGroupEntity extends Entity {
+public class ProcessGroupEntity extends ComponentEntity {
 
-    private ProcessGroupDTO processGroup;
+    private ProcessGroupDTO component;
 
     /**
      * The ProcessGroupDTO that is being serialized.
      *
      * @return The ControllerDTO object
      */
-    public ProcessGroupDTO getProcessGroup() {
-        return processGroup;
+    public ProcessGroupDTO getComponent() {
+        return component;
     }
 
-    public void setProcessGroup(ProcessGroupDTO controller) {
-        this.processGroup = controller;
+    public void setComponent(ProcessGroupDTO component) {
+        this.component = component;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java
new file mode 100644
index 0000000..8ab1327
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupFlowEntity.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.entity;
+
+import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a ProcessGroupFlowDTO.
+ */
+@XmlRootElement(name = "processGroupFlowEntity")
+public class ProcessGroupFlowEntity extends Entity {
+
+    private ProcessGroupFlowDTO processGroupFlow;
+
+    /**
+     * The ProcessGroupFlowDTO that is being serialized.
+     *
+     * @return The ProcessGroupFlowDTO object
+     */
+    public ProcessGroupFlowDTO getProcessGroupFlow() {
+        return processGroupFlow;
+    }
+
+    public void setProcessGroupFlow(ProcessGroupFlowDTO flow) {
+        this.processGroupFlow = flow;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupsEntity.java
index 7acf650..4f222e3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupsEntity.java
@@ -16,28 +16,27 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.ProcessGroupDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a set of ProcessGroupDTOs.
+ * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a set of ProcessGroupEntitys.
  */
 @XmlRootElement(name = "processGroupsEntity")
 public class ProcessGroupsEntity extends Entity {
 
-    private Set<ProcessGroupDTO> processGroups;
+    private Set<ProcessGroupEntity> processGroups;
 
     /**
-     * The ProcessGroupDTO that is being serialized.
+     * The ProcessGroupEntity that is being serialized.
      *
-     * @return The ProcessGroupDTOs
+     * @return The ProcessGroupEntitys
      */
-    public Set<ProcessGroupDTO> getProcessGroups() {
+    public Set<ProcessGroupEntity> getProcessGroups() {
         return processGroups;
     }
 
-    public void setProcessGroups(Set<ProcessGroupDTO> processGroups) {
+    public void setProcessGroups(Set<ProcessGroupEntity> processGroups) {
         this.processGroups = processGroups;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
index e03bb85..edf3c5e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorEntity.java
@@ -16,28 +16,29 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import javax.xml.bind.annotation.XmlRootElement;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 
+import javax.xml.bind.annotation.XmlRootElement;
+
 /**
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a ProcessorDTO.
  */
 @XmlRootElement(name = "processorEntity")
-public class ProcessorEntity extends Entity {
+public class ProcessorEntity extends ComponentEntity {
 
-    private ProcessorDTO processor;
+    private ProcessorDTO component;
 
     /**
      * The ProcessorDTO that is being serialized.
      *
      * @return The ProcessorDTO object
      */
-    public ProcessorDTO getProcessor() {
-        return processor;
+    public ProcessorDTO getComponent() {
+        return component;
     }
 
-    public void setProcessor(ProcessorDTO processor) {
-        this.processor = processor;
+    public void setComponent(ProcessorDTO component) {
+        this.component = component;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorsEntity.java
index 04db99f..06ed8f5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessorsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.ProcessorDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of ProcessorDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of ProcessorEntity's.
  */
 @XmlRootElement(name = "processorsEntity")
 public class ProcessorsEntity extends Entity {
 
-    private Set<ProcessorDTO> processors;
+    private Set<ProcessorEntity> processors;
 
     /**
-     * @return collection of ProcessorDTOs that are being serialized
+     * @return collection of ProcessorEntity's that are being serialized
      */
-    public Set<ProcessorDTO> getProcessors() {
+    public Set<ProcessorEntity> getProcessors() {
         return processors;
     }
 
-    public void setProcessors(Set<ProcessorDTO> processors) {
+    public void setProcessors(Set<ProcessorEntity> processors) {
         this.processors = processors;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
index ba12f40..3183cde 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupEntity.java
@@ -23,21 +23,21 @@ import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
  * A serialized representation of this class can be placed in the entity body of a request or response to or from the API. This particular entity holds a reference to a RemoteProcessGroupDTO.
  */
 @XmlRootElement(name = "remoteProcessGroupEntity")
-public class RemoteProcessGroupEntity extends Entity {
+public class RemoteProcessGroupEntity extends ComponentEntity {
 
-    private RemoteProcessGroupDTO remoteProcessGroup;
+    private RemoteProcessGroupDTO component;
 
     /**
      * The RemoteProcessGroupDTO that is being serialized.
      *
      * @return The RemoteProcessGroupDTO object
      */
-    public RemoteProcessGroupDTO getRemoteProcessGroup() {
-        return remoteProcessGroup;
+    public RemoteProcessGroupDTO getComponent() {
+        return component;
     }
 
-    public void setRemoteProcessGroup(RemoteProcessGroupDTO remoteProcessGroup) {
-        this.remoteProcessGroup = remoteProcessGroup;
+    public void setComponent(RemoteProcessGroupDTO component) {
+        this.component = component;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupsEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupsEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupsEntity.java
index 42abf23..c8fc695 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupsEntity.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/RemoteProcessGroupsEntity.java
@@ -16,27 +16,25 @@
  */
 package org.apache.nifi.web.api.entity;
 
-import java.util.Set;
-
 import javax.xml.bind.annotation.XmlRootElement;
-import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
+import java.util.Set;
 
 /**
- * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of RemoteProcessGroupDTOs.
+ * A serialized representation of this class can be placed in the entity body of a response to the API. This particular entity holds a reference to a list of RemoteProcessGroupEntitys.
  */
 @XmlRootElement(name = "remoteProcessGroupsEntity")
 public class RemoteProcessGroupsEntity extends Entity {
 
-    private Set<RemoteProcessGroupDTO> remoteProcessGroups;
+    private Set<RemoteProcessGroupEntity> remoteProcessGroups;
 
     /**
-     * @return collection of RemoteProcessGroupDTOs that are being serialized
+     * @return collection of RemoteProcessGroupEntitys that are being serialized
      */
-    public Set<RemoteProcessGroupDTO> getRemoteProcessGroups() {
+    public Set<RemoteProcessGroupEntity> getRemoteProcessGroups() {
         return remoteProcessGroups;
     }
 
-    public void setRemoteProcessGroups(Set<RemoteProcessGroupDTO> remoteProcessGroups) {
+    public void setRemoteProcessGroups(Set<RemoteProcessGroupEntity> remoteProcessGroups) {
         this.remoteProcessGroups = remoteProcessGroups;
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
index dc17265..f659b27 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/xsd/authorizations.xsd
@@ -28,7 +28,6 @@
             <xs:simpleType>
                 <xs:restriction base="xs:string">
                     <xs:enumeration value="R"/>
-                    <xs:enumeration value="W"/>
                     <xs:enumeration value="RW"/>
                 </xs:restriction>
             </xs:simpleType>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
index 8532ec5..918c6cf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml
@@ -21,11 +21,68 @@
         <version>1.0.0-SNAPSHOT</version>
     </parent>
     <artifactId>nifi-framework-authorization</artifactId>
-
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <directory>src/main/xsd</directory>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>jaxb2-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>current</id>
+                        <goals>
+                            <goal>xjc</goal>
+                        </goals>
+                        <configuration>
+                            <packageName>org.apache.nifi.authorization.generated</packageName>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-checkstyle-plugin</artifactId>
+                <configuration>
+                    <excludes>**/authorization/generated/*.java,</excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
     <dependencies>
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-expression-language</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-properties</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-nar-utils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-beans</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
new file mode 100644
index 0000000..092e80c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AccessDeniedException.java
@@ -0,0 +1,39 @@
+/*
+ * 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.authorization;
+
+/**
+ * Represents any error that might occur while authorizing user requests.
+ */
+public class AccessDeniedException extends RuntimeException {
+
+    public AccessDeniedException(Throwable cause) {
+        super(cause);
+    }
+
+    public AccessDeniedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public AccessDeniedException(String message) {
+        super(message);
+    }
+
+    public AccessDeniedException() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
new file mode 100644
index 0000000..423ae25
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
@@ -0,0 +1,341 @@
+/*
+ * 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.authorization;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.annotation.AuthorizerContext;
+import org.apache.nifi.authorization.exception.AuthorizationAccessException;
+import org.apache.nifi.authorization.exception.AuthorizerCreationException;
+import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
+import org.apache.nifi.authorization.generated.Authorizers;
+import org.apache.nifi.authorization.generated.Property;
+import org.apache.nifi.nar.ExtensionManager;
+import org.apache.nifi.nar.NarCloseable;
+import org.apache.nifi.util.NiFiProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Factory bean for loading the configured authorizer.
+ */
+public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, AuthorizerLookup {
+
+    private static final Logger logger = LoggerFactory.getLogger(AuthorizerFactoryBean.class);
+    private static final String AUTHORIZERS_XSD = "/authorizers.xsd";
+    private static final String JAXB_GENERATED_PATH = "org.apache.nifi.authorization.generated";
+    private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
+
+    /**
+     * Load the JAXBContext.
+     */
+    private static JAXBContext initializeJaxbContext() {
+        try {
+            return JAXBContext.newInstance(JAXB_GENERATED_PATH, AuthorizerFactoryBean.class.getClassLoader());
+        } catch (JAXBException e) {
+            throw new RuntimeException("Unable to create JAXBContext.");
+        }
+    }
+
+    private Authorizer authorizer;
+    private NiFiProperties properties;
+    private final Map<String, Authorizer> authorizers = new HashMap<>();
+
+    @Override
+    public Authorizer getAuthorizer(String identifier) {
+        return authorizers.get(identifier);
+    }
+
+    @Override
+    public Object getObject() throws Exception {
+        if (authorizer == null) {
+            if (properties.getSslPort() == null) {
+                // use a default authorizer... only allowable when running not securely
+                authorizer = createDefaultAuthorizer();
+            } else {
+                // look up the authorizer to use
+                final String authorizerIdentifier = properties.getProperty(NiFiProperties.SECURITY_USER_AUTHORIZER);
+
+                // ensure the authorizer class name was specified
+                if (StringUtils.isBlank(authorizerIdentifier)) {
+                    throw new Exception("When running securely, the authorizer identifier must be specified in the nifi properties file.");
+                } else {
+                    final Authorizers authorizerConfiguration = loadAuthorizersConfiguration();
+
+                    // create each authorizer
+                    for (final org.apache.nifi.authorization.generated.Authorizer authorizer : authorizerConfiguration.getAuthorizer()) {
+                        authorizers.put(authorizer.getIdentifier(), createAuthorizer(authorizer.getIdentifier(), authorizer.getClazz()));
+                    }
+
+                    // configure each authorizer
+                    for (final org.apache.nifi.authorization.generated.Authorizer provider : authorizerConfiguration.getAuthorizer()) {
+                        final Authorizer instance = authorizers.get(provider.getIdentifier());
+                        instance.onConfigured(loadAuthorizerConfiguration(provider));
+                    }
+
+                    // get the authorizer instance
+                    authorizer = getAuthorizer(authorizerIdentifier);
+
+                    // ensure it was found
+                    if (authorizer == null) {
+                        throw new Exception(String.format("The specified authorizer '%s' could not be found.", authorizerIdentifier));
+                    }
+                }
+            }
+        }
+
+        return authorizer;
+    }
+
+    private Authorizers loadAuthorizersConfiguration() throws Exception {
+        final File authorizersConfigurationFile = properties.getAuthorizerConfiguraitonFile();
+
+        // load the authorizers from the specified file
+        if (authorizersConfigurationFile.exists()) {
+            try {
+                // find the schema
+                final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+                final Schema schema = schemaFactory.newSchema(Authorizers.class.getResource(AUTHORIZERS_XSD));
+
+                // attempt to unmarshal
+                final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
+                unmarshaller.setSchema(schema);
+                final JAXBElement<Authorizers> element = unmarshaller.unmarshal(new StreamSource(authorizersConfigurationFile), Authorizers.class);
+                return element.getValue();
+            } catch (SAXException | JAXBException e) {
+                throw new Exception("Unable to load the authorizer configuration file at: " + authorizersConfigurationFile.getAbsolutePath(), e);
+            }
+        } else {
+            throw new Exception("Unable to find the authorizer configuration file at " + authorizersConfigurationFile.getAbsolutePath());
+        }
+    }
+
+    private Authorizer createAuthorizer(final String identifier, final String authorizerClassName) throws Exception {
+        // get the classloader for the specified authorizer
+        final ClassLoader authorizerClassLoader = ExtensionManager.getClassLoader(authorizerClassName);
+        if (authorizerClassLoader == null) {
+            throw new Exception(String.format("The specified authorizer class '%s' is not known to this nifi.", authorizerClassName));
+        }
+
+        // get the current context classloader
+        final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
+
+        final Authorizer instance;
+        try {
+            // set the appropriate class loader
+            Thread.currentThread().setContextClassLoader(authorizerClassLoader);
+
+            // attempt to load the class
+            Class<?> rawAuthorizerClass = Class.forName(authorizerClassName, true, authorizerClassLoader);
+            Class<? extends Authorizer> authorizerClass = rawAuthorizerClass.asSubclass(Authorizer.class);
+
+            // otherwise create a new instance
+            Constructor constructor = authorizerClass.getConstructor();
+            instance = (Authorizer) constructor.newInstance();
+
+            // method injection
+            performMethodInjection(instance, authorizerClass);
+
+            // field injection
+            performFieldInjection(instance, authorizerClass);
+
+            // call post construction lifecycle event
+            instance.initialize(new StandardAuthorizerInitializationContext(identifier, this));
+        } finally {
+            if (currentClassLoader != null) {
+                Thread.currentThread().setContextClassLoader(currentClassLoader);
+            }
+        }
+
+        return withNarLoader(instance);
+    }
+
+    private AuthorizerConfigurationContext loadAuthorizerConfiguration(final org.apache.nifi.authorization.generated.Authorizer authorizer) {
+        final Map<String, String> authorizerProperties = new HashMap<>();
+
+        for (final Property property : authorizer.getProperty()) {
+            authorizerProperties.put(property.getName(), property.getValue());
+        }
+
+        return new StandardAuthorizerConfigurationContext(authorizer.getIdentifier(), authorizerProperties);
+    }
+
+    private void performMethodInjection(final Authorizer instance, final Class authorizerClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        for (final Method method : authorizerClass.getMethods()) {
+            if (method.isAnnotationPresent(AuthorizerContext.class)) {
+                // make the method accessible
+                final boolean isAccessible = method.isAccessible();
+                method.setAccessible(true);
+
+                try {
+                    final Class<?>[] argumentTypes = method.getParameterTypes();
+
+                    // look for setters (single argument)
+                    if (argumentTypes.length == 1) {
+                        final Class<?> argumentType = argumentTypes[0];
+
+                        // look for well known types
+                        if (NiFiProperties.class.isAssignableFrom(argumentType)) {
+                            // nifi properties injection
+                            method.invoke(instance, properties);
+                        }
+                    }
+                } finally {
+                    method.setAccessible(isAccessible);
+                }
+            }
+        }
+
+        final Class parentClass = authorizerClass.getSuperclass();
+        if (parentClass != null && Authorizer.class.isAssignableFrom(parentClass)) {
+            performMethodInjection(instance, parentClass);
+        }
+    }
+
+    private void performFieldInjection(final Authorizer instance, final Class authorizerClass) throws IllegalArgumentException, IllegalAccessException {
+        for (final Field field : authorizerClass.getDeclaredFields()) {
+            if (field.isAnnotationPresent(AuthorizerContext.class)) {
+                // make the method accessible
+                final boolean isAccessible = field.isAccessible();
+                field.setAccessible(true);
+
+                try {
+                    // get the type
+                    final Class<?> fieldType = field.getType();
+
+                    // only consider this field if it isn't set yet
+                    if (field.get(instance) == null) {
+                        // look for well known types
+                        if (NiFiProperties.class.isAssignableFrom(fieldType)) {
+                            // nifi properties injection
+                            field.set(instance, properties);
+                        }
+                    }
+
+                } finally {
+                    field.setAccessible(isAccessible);
+                }
+            }
+        }
+
+        final Class parentClass = authorizerClass.getSuperclass();
+        if (parentClass != null && Authorizer.class.isAssignableFrom(parentClass)) {
+            performFieldInjection(instance, parentClass);
+        }
+    }
+
+    /**
+     * @return a default Authorizer to use when running unsecurely with no authorizer configured
+     */
+    private Authorizer createDefaultAuthorizer() {
+        return new Authorizer() {
+            @Override
+            public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
+                return AuthorizationResult.approved();
+            }
+
+            @Override
+            public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
+            }
+
+            @Override
+            public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+            }
+
+            @Override
+            public void preDestruction() throws AuthorizerDestructionException {
+            }
+        };
+    }
+
+    /**
+     * Decorates the base authorizer to ensure the nar context classloader is used when invoking the underlying methods.
+     *
+     * @param baseAuthorizer base authorizer
+     * @return authorizer
+     */
+    public Authorizer withNarLoader(final Authorizer baseAuthorizer) {
+        return new Authorizer() {
+            @Override
+            public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
+                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+                    return baseAuthorizer.authorize(request);
+                }
+            }
+
+            @Override
+            public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
+                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+                    baseAuthorizer.initialize(initializationContext);
+                }
+            }
+
+            @Override
+            public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
+                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+                    baseAuthorizer.onConfigured(configurationContext);
+                }
+            }
+
+            @Override
+            public void preDestruction() throws AuthorizerDestructionException {
+                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
+                    baseAuthorizer.preDestruction();
+                }
+            }
+        };
+    }
+
+    @Override
+    public Class getObjectType() {
+        return Authorizer.class;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    @Override
+    public void destroy() throws Exception {
+        if (authorizer != null) {
+            authorizer.preDestruction();
+        }
+    }
+
+    public void setProperties(NiFiProperties properties) {
+        this.properties = properties;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java
new file mode 100644
index 0000000..3010c92
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
+import org.apache.nifi.components.PropertyValue;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class StandardAuthorizerConfigurationContext implements AuthorizerConfigurationContext {
+
+    private final String identifier;
+    private final Map<String, String> properties;
+
+    public StandardAuthorizerConfigurationContext(String identifier, Map<String, String> properties) {
+        this.identifier = identifier;
+        this.properties = Collections.unmodifiableMap(new HashMap<String, String>(properties));
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return properties;
+    }
+
+    @Override
+    public PropertyValue getProperty(String property) {
+        return new StandardPropertyValue(properties.get(property), null);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java
new file mode 100644
index 0000000..344f49c
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.authorization;
+
+/**
+ *
+ */
+public class StandardAuthorizerInitializationContext implements AuthorizerInitializationContext {
+
+    private final String identifier;
+    private final AuthorizerLookup authorizerLookup;
+
+    public StandardAuthorizerInitializationContext(String identifier, AuthorizerLookup authorizerLookup) {
+        this.identifier = identifier;
+        this.authorizerLookup = authorizerLookup;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    public AuthorizerLookup getAuthorizerLookup() {
+        return authorizerLookup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
new file mode 100644
index 0000000..c897be2
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/Authorizable.java
@@ -0,0 +1,129 @@
+/*
+ * 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.authorization.resource;
+
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+
+public interface Authorizable {
+
+    /**
+     * The parent for this Authorizable. May be null.
+     *
+     * @return the parent authorizable or null
+     */
+    Authorizable getParentAuthorizable();
+
+    /**
+     * The Resource for this Authorizable.
+     *
+     * @return the parent resource
+     */
+    Resource getResource();
+
+    /**
+     * Returns whether the current user is authorized for the specified action on the specified resource. This
+     * method does not imply the user is directly attempting to access the specified resource. If the user is
+     * attempting a direct access use Authorizable.authorize().
+     *
+     * @param authorizer authorizer
+     * @param action action
+     * @return is authorized
+     */
+    default boolean isAuthorized(Authorizer authorizer, RequestAction action) {
+        return Result.Approved.equals(checkAuthorization(authorizer, action).getResult());
+    }
+
+    /**
+     * Returns the result of an authorization request for the current user for the specified action on the specified
+     * resource. This method does not imply the user is directly attempting to access the specified resource. If the user is
+     * attempting a direct access use Authorizable.authorize().
+     *
+     * @param authorizer authorizer
+     * @param action action
+     * @return is authorized
+     */
+    default AuthorizationResult checkAuthorization(Authorizer authorizer, RequestAction action) {
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+        // TODO - include user details context
+
+        // build the request
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+            .identity(user.getIdentity())
+            .anonymous(user.isAnonymous())
+            .accessAttempt(false)
+            .action(action)
+            .resource(getResource())
+            .build();
+
+        // perform the authorization
+        final AuthorizationResult result = authorizer.authorize(request);
+
+        // verify the results
+        if (Result.ResourceNotFound.equals(result.getResult())) {
+            final Authorizable parent = getParentAuthorizable();
+            if (parent == null) {
+                return AuthorizationResult.denied();
+            } else {
+                return parent.checkAuthorization(authorizer, action);
+            }
+        } else {
+            return result;
+        }
+    }
+
+    /**
+     * Authorizes the current user for the specified action on the specified resource. This method does imply the user is
+     * directly accessing the specified resource.
+     *
+     * @param authorizer authorizer
+     * @param action action
+     */
+    default void authorize(Authorizer authorizer, RequestAction action) throws AccessDeniedException {
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+        // TODO - include user details context
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+            .identity(user.getIdentity())
+            .anonymous(user.isAnonymous())
+            .accessAttempt(true)
+            .action(action)
+            .resource(getResource())
+            .build();
+
+        final AuthorizationResult result = authorizer.authorize(request);
+        if (Result.ResourceNotFound.equals(result.getResult())) {
+            final Authorizable parent = getParentAuthorizable();
+            if (parent == null) {
+                throw new AccessDeniedException("Access is denied");
+            } else {
+                parent.authorize(authorizer, action);
+            }
+        } else if (Result.Denied.equals(result.getResult())) {
+            throw new AccessDeniedException(result.getExplanation());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
index a641810..ce8f1bf 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java
@@ -203,7 +203,6 @@ public final class ResourceFactory {
     public static Resource getComponentResource(final ResourceType resourceType, final String identifier, final String name) {
         Objects.requireNonNull(resourceType, "The resource must be specified.");
         Objects.requireNonNull(identifier, "The component identifier must be specified.");
-        Objects.requireNonNull(name, "The component name must be specified.");
 
         return new Resource() {
             @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
index 20ace59..f3e9b6c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java
@@ -20,6 +20,7 @@ public enum ResourceType {
     Processor("/processors"),
     InputPort("/input-ports"),
     OutputPort("/output-ports"),
+    Funnel("/funnel"),
     Connection("/connections"),
     ProcessGroup("/process-groups"),
     RemoteProcessGroup("/remote-process-groups"),

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
new file mode 100644
index 0000000..80e7406
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUser.java
@@ -0,0 +1,97 @@
+/*
+ * 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.authorization.user;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * An NiFiUser.
+ */
+public class NiFiUser implements Serializable {
+
+    public static final NiFiUser ANONYMOUS = new NiFiUser("anonymous");
+
+    private String identity;
+    private String userName;
+
+    private NiFiUser chain;
+
+    public NiFiUser(String identity) {
+        this(identity, identity, null);
+    }
+
+    public NiFiUser(String identity, String userName) {
+        this(identity, userName, null);
+    }
+
+    public NiFiUser(String identity, NiFiUser chain) {
+        this(identity, identity, chain);
+    }
+
+    public NiFiUser(String identity, String userName, NiFiUser chain) {
+        this.identity = identity;
+        this.userName = userName;
+        this.chain = chain;
+    }
+
+    /* getters / setters */
+
+    public String getIdentity() {
+        return identity;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public NiFiUser getChain() {
+        return chain;
+    }
+
+    public boolean isAnonymous() {
+        return this == ANONYMOUS;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final NiFiUser other = (NiFiUser) obj;
+        if (!Objects.equals(this.identity, other.identity)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 53 * hash + Objects.hashCode(this.identity);
+        return hash;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("identity[%s], userName[%s]", getIdentity(), getUserName(), ", ");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserDetails.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserDetails.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserDetails.java
new file mode 100644
index 0000000..f8b7c18
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserDetails.java
@@ -0,0 +1,91 @@
+/*
+ * 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.authorization.user;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * User details for a NiFi user.
+ */
+public class NiFiUserDetails implements UserDetails {
+
+    private final NiFiUser user;
+
+    /**
+     * Creates a new NiFiUserDetails.
+     *
+     * @param user user
+     */
+    public NiFiUserDetails(NiFiUser user) {
+        this.user = user;
+    }
+
+    /**
+     * Get the user for this UserDetails.
+     *
+     * @return user
+     */
+    public NiFiUser getNiFiUser() {
+        return user;
+    }
+
+    /**
+     * Returns the authorities that this NiFi user has.
+     *
+     * @return authorities
+     */
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return Collections.EMPTY_SET;
+    }
+
+    @Override
+    public String getPassword() {
+        return StringUtils.EMPTY;
+    }
+
+    @Override
+    public String getUsername() {
+        return user.getIdentity();
+    }
+
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+}


[07/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
index 208d30d..49a3264 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
@@ -32,34 +32,31 @@ import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.ControllerServiceDTO;
-import org.apache.nifi.web.api.dto.FlowSnippetDTO;
-import org.apache.nifi.web.api.dto.FunnelDTO;
-import org.apache.nifi.web.api.dto.LabelDTO;
-import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.ProcessGroupDTO;
-import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.dto.SnippetDTO;
 import org.apache.nifi.web.api.dto.TemplateDTO;
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
 import org.apache.nifi.web.api.entity.ConnectionEntity;
 import org.apache.nifi.web.api.entity.ConnectionsEntity;
 import org.apache.nifi.web.api.entity.ControllerServiceEntity;
 import org.apache.nifi.web.api.entity.ControllerServicesEntity;
 import org.apache.nifi.web.api.entity.CopySnippetRequestEntity;
 import org.apache.nifi.web.api.entity.CreateTemplateRequestEntity;
+import org.apache.nifi.web.api.entity.FlowEntity;
 import org.apache.nifi.web.api.entity.FlowSnippetEntity;
 import org.apache.nifi.web.api.entity.FunnelEntity;
 import org.apache.nifi.web.api.entity.FunnelsEntity;
-import org.apache.nifi.web.api.entity.InputPortEntity;
 import org.apache.nifi.web.api.entity.InputPortsEntity;
 import org.apache.nifi.web.api.entity.InstantiateTemplateRequestEntity;
 import org.apache.nifi.web.api.entity.LabelEntity;
 import org.apache.nifi.web.api.entity.LabelsEntity;
-import org.apache.nifi.web.api.entity.OutputPortEntity;
 import org.apache.nifi.web.api.entity.OutputPortsEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupsEntity;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
@@ -141,6 +138,32 @@ public class ProcessGroupResource extends ApplicationResource {
     /**
      * Populates the remaining fields in the specified process groups.
      *
+     * @param processGroupEntities groups
+     * @return group dto
+     */
+    public Set<ProcessGroupEntity> populateRemainingProcessGroupEntitiesContent(Set<ProcessGroupEntity> processGroupEntities) {
+        for (ProcessGroupEntity processGroupEntity : processGroupEntities) {
+            populateRemainingProcessGroupEntityContent(processGroupEntity);
+        }
+        return processGroupEntities;
+    }
+
+    /**
+     * Populates the remaining fields in the specified process group.
+     *
+     * @param processGroupEntity group
+     * @return group dto
+     */
+    public ProcessGroupEntity populateRemainingProcessGroupEntityContent(ProcessGroupEntity processGroupEntity) {
+        if (processGroupEntity.getComponent() != null) {
+            populateRemainingProcessGroupContent(processGroupEntity.getComponent());
+        }
+        return processGroupEntity;
+    }
+
+    /**
+     * Populates the remaining fields in the specified process groups.
+     *
      * @param processGroups groups
      * @return group dto
      */
@@ -158,37 +181,28 @@ public class ProcessGroupResource extends ApplicationResource {
      * @return group dto
      */
     private ProcessGroupDTO populateRemainingProcessGroupContent(ProcessGroupDTO processGroup) {
-        FlowSnippetDTO flowSnippet = processGroup.getContents();
-
-        // populate the remaining fields for the processors, connections, process group refs, remote process groups, and labels if appropriate
-        if (flowSnippet != null) {
-            populateRemainingSnippetContent(flowSnippet);
-        }
-
-        // set the process group uri
         processGroup.setUri(generateResourceUri("process-groups",  processGroup.getId()));
-
         return processGroup;
     }
 
     /**
      * Populates the remaining content of the specified snippet.
      */
-    private FlowSnippetDTO populateRemainingSnippetContent(FlowSnippetDTO snippet) {
-        processorResource.populateRemainingProcessorsContent(snippet.getProcessors());
-        connectionResource.populateRemainingConnectionsContent(snippet.getConnections());
-        inputPortResource.populateRemainingInputPortsContent(snippet.getInputPorts());
-        outputPortResource.populateRemainingOutputPortsContent(snippet.getOutputPorts());
-        remoteProcessGroupResource.populateRemainingRemoteProcessGroupsContent(snippet.getRemoteProcessGroups());
-        funnelResource.populateRemainingFunnelsContent(snippet.getFunnels());
-        labelResource.populateRemainingLabelsContent(snippet.getLabels());
+    private FlowDTO populateRemainingSnippetContent(FlowDTO flow) {
+        processorResource.populateRemainingProcessorEntitiesContent(flow.getProcessors());
+        connectionResource.populateRemainingConnectionEntitiesContent(flow.getConnections());
+        inputPortResource.populateRemainingInputPortEntitiesContent(flow.getInputPorts());
+        outputPortResource.populateRemainingOutputPortEntitiesContent(flow.getOutputPorts());
+        remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntitiesContent(flow.getRemoteProcessGroups());
+        funnelResource.populateRemainingFunnelEntitiesContent(flow.getFunnels());
+        labelResource.populateRemainingLabelEntitiesContent(flow.getLabels());
 
         // go through each process group child and populate its uri
-        if (snippet.getProcessGroups() != null) {
-            populateRemainingProcessGroupsContent(snippet.getProcessGroups());
+        if (flow.getProcessGroups() != null) {
+            populateRemainingProcessGroupEntitiesContent(flow.getProcessGroups());
         }
 
-        return snippet;
+        return flow;
     }
 
     /**
@@ -196,26 +210,17 @@ public class ProcessGroupResource extends ApplicationResource {
      */
     private SnippetDTO populateRemainingSnippetContent(SnippetDTO snippet) {
         String snippetGroupId = snippet.getParentGroupId();
-        FlowSnippetDTO snippetContents = snippet.getContents();
 
         // populate the snippet href
         snippet.setUri(generateResourceUri("process-groups", snippetGroupId, "snippets", snippet.getId()));
 
-        // populate the snippet content uris
-        if (snippet.getContents() != null) {
-            populateRemainingSnippetContent(snippetContents);
-        }
-
         return snippet;
     }
 
     /**
      * Retrieves the contents of the specified group.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
-     * @param recursive Optional recursive flag that defaults to false. If set to true, all descendent groups and their content will be included if the verbose flag is also set to true.
      * @param groupId The id of the process group.
-     * @param verbose Optional verbose flag that defaults to false. If the verbose flag is set to true processor configuration and property details will be included in the response.
      * @return A processGroupEntity.
      */
     @GET
@@ -243,54 +248,26 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getProcessGroup(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The process group id.",
                     required = false
             )
-            @PathParam("id") String groupId,
-            @ApiParam(
-                    value = "Whether the response should contain all encapsulated components or just the immediate children.",
-                    required = false
-            )
-            @QueryParam("recursive") @DefaultValue(RECURSIVE) Boolean recursive,
-            @ApiParam(
-                    value = "Whether to include any encapulated components or just details about the process group.",
-                    required = false
-            )
-            @QueryParam("verbose") @DefaultValue(VERBOSE) Boolean verbose) {
+            @PathParam("id") String groupId) {
 
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
         }
 
-        // only recurse if the request is verbose and recursive
-        final boolean recurse = verbose && recursive;
-
         // get this process group contents
-        final ConfigurationSnapshot<ProcessGroupDTO> controllerResponse = serviceFacade.getProcessGroup(groupId, recurse);
-        final ProcessGroupDTO processGroup = controllerResponse.getConfiguration();
+        final ProcessGroupEntity entity = serviceFacade.getProcessGroup(groupId);
+        populateRemainingProcessGroupEntityContent(entity);
 
-        // prune the response if necessary
-        if (!verbose) {
-            processGroup.setContents(null);
+        if (entity.getComponent() != null) {
+            entity.getComponent().setContents(null);
         }
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // create the response entity
-        final ProcessGroupEntity processGroupEntity = new ProcessGroupEntity();
-        processGroupEntity.setRevision(revision);
-        processGroupEntity.setProcessGroup(populateRemainingProcessGroupContent(processGroup));
 
-        return clusterContext(generateOkResponse(processGroupEntity)).build();
+        return clusterContext(generateOkResponse(entity)).build();
     }
 
     /**
@@ -335,7 +312,7 @@ public class ProcessGroupResource extends ApplicationResource {
             )
             ProcessGroupEntity processGroupEntity) {
 
-        if (processGroupEntity == null || processGroupEntity.getProcessGroup() == null) {
+        if (processGroupEntity == null || processGroupEntity.getComponent() == null) {
             throw new IllegalArgumentException("Process group details must be specified.");
         }
 
@@ -344,7 +321,7 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // ensure the same id is being used
-        final ProcessGroupDTO requestProcessGroupDTO = processGroupEntity.getProcessGroup();
+        final ProcessGroupDTO requestProcessGroupDTO = processGroupEntity.getComponent();
         if (!id.equals(requestProcessGroupDTO.getId())) {
             throw new IllegalArgumentException(String.format("The process group id (%s) in the request body does "
                     + "not equal the process group id of the requested resource (%s).", requestProcessGroupDTO.getId(), id));
@@ -363,22 +340,12 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // update the process group
         final RevisionDTO revision = processGroupEntity.getRevision();
-        final ConfigurationSnapshot<ProcessGroupDTO> response = serviceFacade.updateProcessGroup(
-                new Revision(revision.getVersion(), revision.getClientId()), requestProcessGroupDTO);
-        final ProcessGroupDTO processGroup = response.getConfiguration();
+        final UpdateResult<ProcessGroupEntity> updateResult = serviceFacade.updateProcessGroup(new Revision(revision.getVersion(), revision.getClientId()), requestProcessGroupDTO);
+        final ProcessGroupEntity entity = updateResult.getResult();
+        populateRemainingProcessGroupEntityContent(entity);
 
-        // create the revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(response.getVersion());
-
-        // create the response entity
-        final ProcessGroupEntity entity = new ProcessGroupEntity();
-        entity.setRevision(updatedRevision);
-        entity.setProcessGroup(populateRemainingProcessGroupContent(processGroup));
-
-        if (response.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(processGroup.getUri()), entity)).build();
+        if (updateResult.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -451,16 +418,7 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // delete the process group
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteProcessGroup(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // create the response entity
-        final ProcessGroupEntity entity = new ProcessGroupEntity();
-        entity.setRevision(revision);
+        final ProcessGroupEntity entity = serviceFacade.deleteProcessGroup(new Revision(clientVersion, clientId.getClientId()), id);
 
         // create the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -508,7 +466,7 @@ public class ProcessGroupResource extends ApplicationResource {
         )
             ProcessGroupEntity processGroupEntity) {
 
-        if (processGroupEntity == null || processGroupEntity.getProcessGroup() == null) {
+        if (processGroupEntity == null || processGroupEntity.getComponent() == null) {
             throw new IllegalArgumentException("Process group details must be specified.");
         }
 
@@ -516,10 +474,16 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (processGroupEntity.getProcessGroup().getId() != null) {
+        if (processGroupEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Process group ID cannot be specified.");
         }
 
+        if (processGroupEntity.getComponent().getParentGroupId() != null && !groupId.equals(processGroupEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                processGroupEntity.getComponent().getParentGroupId(), groupId));
+        }
+        processGroupEntity.getComponent().setParentGroupId(groupId);
+
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(processGroupEntity), getHeaders()).getResponse();
         }
@@ -533,36 +497,24 @@ public class ProcessGroupResource extends ApplicationResource {
         // set the processor id as appropriate
         final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
         if (clusterContext != null) {
-            processGroupEntity.getProcessGroup().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
+            processGroupEntity.getComponent().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
         } else {
-            processGroupEntity.getProcessGroup().setId(UUID.randomUUID().toString());
+            processGroupEntity.getComponent().setId(UUID.randomUUID().toString());
         }
 
         // create the process group contents
         final RevisionDTO revision = processGroupEntity.getRevision();
-        final ConfigurationSnapshot<ProcessGroupDTO> controllerResponse = serviceFacade.createProcessGroup(groupId,
-            new Revision(revision.getVersion(), revision.getClientId()), processGroupEntity.getProcessGroup());
-        final ProcessGroupDTO processGroup = controllerResponse.getConfiguration();
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // create the response entity
-        final ProcessGroupEntity entity = new ProcessGroupEntity();
-        entity.setRevision(updatedRevision);
-        entity.setProcessGroup(populateRemainingProcessGroupContent(processGroup));
+        final ProcessGroupEntity entity = serviceFacade.createProcessGroup(groupId, new Revision(revision.getVersion(), revision.getClientId()), processGroupEntity.getComponent());
+        populateRemainingProcessGroupEntityContent(entity);
 
         // generate a 201 created response
-        String uri = processGroup.getUri();
+        String uri = entity.getComponent().getUri();
         return clusterContext(generateCreatedResponse(URI.create(uri), entity)).build();
     }
 
     /**
      * Retrieves all the processors in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @return A processorsEntity.
      */
     @GET
@@ -589,7 +541,6 @@ public class ProcessGroupResource extends ApplicationResource {
         }
     )
     public Response getProcessGroups(
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
         @ApiParam(
             value = "The process group id.",
             required = true
@@ -602,16 +553,18 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // get the process groups
-        final Set<ProcessGroupDTO> processGroupDTOs = serviceFacade.getProcessGroups(groupId);
+        final Set<ProcessGroupEntity> entities = serviceFacade.getProcessGroups(groupId);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
+        // always prune the contents
+        for (final ProcessGroupEntity entity : entities) {
+            if (entity.getComponent() != null) {
+                entity.getComponent().setContents(null);
+            }
+        }
 
         // create the response entity
         final ProcessGroupsEntity entity = new ProcessGroupsEntity();
-        entity.setRevision(revision);
-        entity.setProcessGroups(populateRemainingProcessGroupsContent(processGroupDTOs));
+        entity.setProcessGroups(populateRemainingProcessGroupEntitiesContent(entities));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -663,7 +616,7 @@ public class ProcessGroupResource extends ApplicationResource {
             )
             ProcessorEntity processorEntity) {
 
-        if (processorEntity == null || processorEntity.getProcessor() == null) {
+        if (processorEntity == null || processorEntity.getComponent() == null) {
             throw new IllegalArgumentException("Processor details must be specified.");
         }
 
@@ -671,14 +624,20 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (processorEntity.getProcessor().getId() != null) {
+        if (processorEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Processor ID cannot be specified.");
         }
 
-        if (StringUtils.isBlank(processorEntity.getProcessor().getType())) {
+        if (StringUtils.isBlank(processorEntity.getComponent().getType())) {
             throw new IllegalArgumentException("The type of processor to create must be specified.");
         }
 
+        if (processorEntity.getComponent().getParentGroupId() != null && !groupId.equals(processorEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                processorEntity.getComponent().getParentGroupId(), groupId));
+        }
+        processorEntity.getComponent().setParentGroupId(groupId);
+
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(processorEntity), getHeaders()).getResponse();
         }
@@ -692,37 +651,25 @@ public class ProcessGroupResource extends ApplicationResource {
         // set the processor id as appropriate
         final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
         if (clusterContext != null) {
-            processorEntity.getProcessor().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
+            processorEntity.getComponent().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
         } else {
-            processorEntity.getProcessor().setId(UUID.randomUUID().toString());
+            processorEntity.getComponent().setId(UUID.randomUUID().toString());
         }
 
         // create the new processor
         final RevisionDTO revision = processorEntity.getRevision();
-        final ConfigurationSnapshot<ProcessorDTO> controllerResponse = serviceFacade.createProcessor(
-            new Revision(revision.getVersion(), revision.getClientId()), groupId, processorEntity.getProcessor());
-        final ProcessorDTO processor = controllerResponse.getConfiguration();
-        processorResource.populateRemainingProcessorContent(processor);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // generate the response entity
-        final ProcessorEntity entity = new ProcessorEntity();
-        entity.setRevision(updatedRevision);
-        entity.setProcessor(processor);
+        final ProcessorEntity entity = serviceFacade.createProcessor(new Revision(revision.getVersion(), revision.getClientId()), groupId, processorEntity.getComponent());
+        processorResource.populateRemainingProcessorEntityContent(entity);
 
         // generate a 201 created response
-        String uri = processor.getUri();
+        String uri = entity.getComponent().getUri();
         return clusterContext(generateCreatedResponse(URI.create(uri), entity)).build();
     }
 
     /**
      * Retrieves all the processors in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
+     * @param groupId group id
      * @return A processorsEntity.
      */
     @GET
@@ -749,7 +696,6 @@ public class ProcessGroupResource extends ApplicationResource {
         }
     )
     public Response getProcessors(
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
         @ApiParam(
             value = "The process group id.",
             required = true
@@ -762,16 +708,11 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // get the processors
-        final Set<ProcessorDTO> processorDTOs = serviceFacade.getProcessors(groupId);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
+        final Set<ProcessorEntity> processors = serviceFacade.getProcessors(groupId);
 
         // create the response entity
         final ProcessorsEntity entity = new ProcessorsEntity();
-        entity.setRevision(revision);
-        entity.setProcessors(processorResource.populateRemainingProcessorsContent(processorDTOs));
+        entity.setProcessors(processorResource.populateRemainingProcessorEntitiesContent(processors));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -796,7 +737,7 @@ public class ProcessGroupResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
         value = "Creates an input port",
-        response = InputPortEntity.class,
+        response = PortEntity.class,
         authorizations = {
             @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
         }
@@ -820,9 +761,9 @@ public class ProcessGroupResource extends ApplicationResource {
         @ApiParam(
             value = "The input port configuration details.",
             required = true
-        ) InputPortEntity portEntity) {
+        ) PortEntity portEntity) {
 
-        if (portEntity == null || portEntity.getInputPort() == null) {
+        if (portEntity == null || portEntity.getComponent() == null) {
             throw new IllegalArgumentException("Port details must be specified.");
         }
 
@@ -830,10 +771,16 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (portEntity.getInputPort().getId() != null) {
+        if (portEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Input port ID cannot be specified.");
         }
 
+        if (portEntity.getComponent().getParentGroupId() != null && !groupId.equals(portEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                portEntity.getComponent().getParentGroupId(), groupId));
+        }
+        portEntity.getComponent().setParentGroupId(groupId);
+
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(portEntity), getHeaders()).getResponse();
         }
@@ -847,36 +794,23 @@ public class ProcessGroupResource extends ApplicationResource {
         // set the processor id as appropriate
         final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
         if (clusterContext != null) {
-            portEntity.getInputPort().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
+            portEntity.getComponent().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
         } else {
-            portEntity.getInputPort().setId(UUID.randomUUID().toString());
+            portEntity.getComponent().setId(UUID.randomUUID().toString());
         }
 
         // create the input port and generate the json
         final RevisionDTO revision = portEntity.getRevision();
-        final ConfigurationSnapshot<PortDTO> controllerResponse = serviceFacade.createInputPort(
-            new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getInputPort());
-        final PortDTO port = controllerResponse.getConfiguration();
-        inputPortResource.populateRemainingInputPortContent(port);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final InputPortEntity entity = new InputPortEntity();
-        entity.setRevision(updatedRevision);
-        entity.setInputPort(port);
+        final PortEntity entity = serviceFacade.createInputPort(new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getComponent());
+        inputPortResource.populateRemainingInputPortEntityContent(entity);
 
         // build the response
-        return clusterContext(generateCreatedResponse(URI.create(port.getUri()), entity)).build();
+        return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
     }
 
     /**
      * Retrieves all the of input ports in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @return A inputPortsEntity.
      */
     @GET
@@ -904,11 +838,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getInputPorts(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -920,16 +849,10 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // get all the input ports
-        final Set<PortDTO> inputPorts = inputPortResource.populateRemainingInputPortsContent(serviceFacade.getInputPorts(groupId));
+        final Set<PortEntity> inputPorts = serviceFacade.getInputPorts(groupId);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
         final InputPortsEntity entity = new InputPortsEntity();
-        entity.setRevision(revision);
-        entity.setInputPorts(inputPorts);
+        entity.setInputPorts(inputPortResource.populateRemainingInputPortEntitiesContent(inputPorts));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -954,7 +877,7 @@ public class ProcessGroupResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
         value = "Creates an output port",
-        response = OutputPortEntity.class,
+        response = PortEntity.class,
         authorizations = {
             @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
         }
@@ -978,9 +901,9 @@ public class ProcessGroupResource extends ApplicationResource {
         @ApiParam(
             value = "The output port configuration.",
             required = true
-        ) OutputPortEntity portEntity) {
+        ) PortEntity portEntity) {
 
-        if (portEntity == null || portEntity.getOutputPort() == null) {
+        if (portEntity == null || portEntity.getComponent() == null) {
             throw new IllegalArgumentException("Port details must be specified.");
         }
 
@@ -988,10 +911,16 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (portEntity.getOutputPort().getId() != null) {
+        if (portEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Output port ID cannot be specified.");
         }
 
+        if (portEntity.getComponent().getParentGroupId() != null && !groupId.equals(portEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                portEntity.getComponent().getParentGroupId(), groupId));
+        }
+        portEntity.getComponent().setParentGroupId(groupId);
+
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(portEntity), getHeaders()).getResponse();
         }
@@ -1005,36 +934,24 @@ public class ProcessGroupResource extends ApplicationResource {
         // set the processor id as appropriate
         final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
         if (clusterContext != null) {
-            portEntity.getOutputPort().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
+            portEntity.getComponent().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
         } else {
-            portEntity.getOutputPort().setId(UUID.randomUUID().toString());
+            portEntity.getComponent().setId(UUID.randomUUID().toString());
         }
 
         // create the output port and generate the json
         final RevisionDTO revision = portEntity.getRevision();
-        final ConfigurationSnapshot<PortDTO> controllerResponse = serviceFacade.createOutputPort(
-            new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getOutputPort());
-        final PortDTO port = controllerResponse.getConfiguration();
-        outputPortResource.populateRemainingOutputPortContent(port);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final OutputPortEntity entity = new OutputPortEntity();
-        entity.setRevision(updatedRevision);
-        entity.setOutputPort(port);
+        final PortEntity entity = serviceFacade.createOutputPort(
+            new Revision(revision.getVersion(), revision.getClientId()), groupId, portEntity.getComponent());
+        outputPortResource.populateRemainingOutputPortEntityContent(entity);
 
         // build the response
-        return clusterContext(generateCreatedResponse(URI.create(port.getUri()), entity)).build();
+        return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
     }
 
     /**
      * Retrieves all the of output ports in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @return A outputPortsEntity.
      */
     @GET
@@ -1062,11 +979,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getOutputPorts(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -1078,16 +990,11 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // get all the output ports
-        final Set<PortDTO> outputPorts = outputPortResource.populateRemainingOutputPortsContent(serviceFacade.getOutputPorts(groupId));
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
+        final Set<PortEntity> outputPorts = serviceFacade.getOutputPorts(groupId);
 
         // create the response entity
         final OutputPortsEntity entity = new OutputPortsEntity();
-        entity.setRevision(revision);
-        entity.setOutputPorts(outputPorts);
+        entity.setOutputPorts(outputPortResource.populateRemainingOutputPortEntitiesContent(outputPorts));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -1138,7 +1045,7 @@ public class ProcessGroupResource extends ApplicationResource {
             required = true
         ) FunnelEntity funnelEntity) {
 
-        if (funnelEntity == null || funnelEntity.getFunnel() == null) {
+        if (funnelEntity == null || funnelEntity.getComponent() == null) {
             throw new IllegalArgumentException("Funnel details must be specified.");
         }
 
@@ -1146,17 +1053,18 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (funnelEntity.getFunnel().getId() != null) {
+        if (funnelEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Funnel ID cannot be specified.");
         }
 
-        if (properties.isClusterManager()) {
-            // change content type to JSON for serializing entity if request came through overloaded endpoint
-            final Map<String, String> headersToOverride = new HashMap<>();
-            headersToOverride.put("content-type", MediaType.APPLICATION_JSON);
+        if (funnelEntity.getComponent().getParentGroupId() != null && !groupId.equals(funnelEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                funnelEntity.getComponent().getParentGroupId(), groupId));
+        }
+        funnelEntity.getComponent().setParentGroupId(groupId);
 
-            // replicate the request
-            return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(funnelEntity), getHeaders(headersToOverride)).getResponse();
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(funnelEntity), getHeaders()).getResponse();
         }
 
         // handle expects request (usually from the cluster manager)
@@ -1168,38 +1076,23 @@ public class ProcessGroupResource extends ApplicationResource {
         // set the processor id as appropriate
         final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
         if (clusterContext != null) {
-            funnelEntity.getFunnel().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
+            funnelEntity.getComponent().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
         } else {
-            funnelEntity.getFunnel().setId(UUID.randomUUID().toString());
+            funnelEntity.getComponent().setId(UUID.randomUUID().toString());
         }
 
         // create the funnel and generate the json
         final RevisionDTO revision = funnelEntity.getRevision();
-        final ConfigurationSnapshot<FunnelDTO> controllerResponse = serviceFacade.createFunnel(
-            new Revision(revision.getVersion(), revision.getClientId()), groupId, funnelEntity.getFunnel());
-        final FunnelDTO funnel = controllerResponse.getConfiguration();
-        funnelResource.populateRemainingFunnelContent(funnel);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final FunnelEntity entity = new FunnelEntity();
-        entity.setRevision(updatedRevision);
-        entity.setFunnel(funnel);
+        final FunnelEntity entity = serviceFacade.createFunnel(new Revision(revision.getVersion(), revision.getClientId()), groupId, funnelEntity.getComponent());
+        funnelResource.populateRemainingFunnelEntityContent(entity);
 
         // build the response
-        return clusterContext(generateCreatedResponse(URI.create(funnel.getUri()), entity)).build();
+        return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
     }
 
     /**
      * Retrieves all the of funnels in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @return A funnelsEntity.
      */
     @GET
@@ -1227,11 +1120,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getFunnels(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -1243,16 +1131,11 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // get all the funnels
-        final Set<FunnelDTO> funnels = funnelResource.populateRemainingFunnelsContent(serviceFacade.getFunnels(groupId));
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
+        final Set<FunnelEntity> funnels = serviceFacade.getFunnels(groupId);
 
         // create the response entity
         final FunnelsEntity entity = new FunnelsEntity();
-        entity.setRevision(revision);
-        entity.setFunnels(funnels);
+        entity.setFunnels(funnelResource.populateRemainingFunnelEntitiesContent(funnels));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -1303,7 +1186,7 @@ public class ProcessGroupResource extends ApplicationResource {
             required = true
         ) LabelEntity labelEntity) {
 
-        if (labelEntity == null || labelEntity.getLabel() == null) {
+        if (labelEntity == null || labelEntity.getComponent() == null) {
             throw new IllegalArgumentException("Label details must be specified.");
         }
 
@@ -1311,10 +1194,16 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (labelEntity.getLabel().getId() != null) {
+        if (labelEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Label ID cannot be specified.");
         }
 
+        if (labelEntity.getComponent().getParentGroupId() != null && !groupId.equals(labelEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                labelEntity.getComponent().getParentGroupId(), groupId));
+        }
+        labelEntity.getComponent().setParentGroupId(groupId);
+
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(labelEntity), getHeaders()).getResponse();
         }
@@ -1328,41 +1217,29 @@ public class ProcessGroupResource extends ApplicationResource {
         // set the processor id as appropriate
         final ClusterContext clusterContext = ClusterContextThreadLocal.getContext();
         if (clusterContext != null) {
-            labelEntity.getLabel().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
+            labelEntity.getComponent().setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString());
         } else {
-            labelEntity.getLabel().setId(UUID.randomUUID().toString());
+            labelEntity.getComponent().setId(UUID.randomUUID().toString());
         }
 
         // create the label and generate the json
         final RevisionDTO revision = labelEntity.getRevision();
-        final ConfigurationSnapshot<LabelDTO> controllerResponse = serviceFacade.createLabel(
-            new Revision(revision.getVersion(), revision.getClientId()), groupId, labelEntity.getLabel());
-        final LabelDTO label = controllerResponse.getConfiguration();
-        labelResource.populateRemainingLabelContent(label);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final LabelEntity entity = new LabelEntity();
-        entity.setRevision(updatedRevision);
-        entity.setLabel(label);
+        final LabelEntity entity = serviceFacade.createLabel(
+            new Revision(revision.getVersion(), revision.getClientId()), groupId, labelEntity.getComponent());
+        labelResource.populateRemainingLabelEntityContent(entity);
 
         // build the response
-        return clusterContext(generateCreatedResponse(URI.create(label.getUri()), entity)).build();
+        return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
     }
 
     /**
      * Retrieves all the of labels in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @return A labelsEntity.
      */
     @GET
     @Consumes(MediaType.WILDCARD)
-    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+    @Produces(MediaType.APPLICATION_JSON)
     @Path("{id}/labels")
     // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
     @ApiOperation(
@@ -1385,11 +1262,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getLabels(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -1401,16 +1273,11 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // get all the labels
-        final Set<LabelDTO> labels = labelResource.populateRemainingLabelsContent(serviceFacade.getLabels(groupId));
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
+        final Set<LabelEntity> labels = serviceFacade.getLabels(groupId);
 
         // create the response entity
         final LabelsEntity entity = new LabelsEntity();
-        entity.setRevision(revision);
-        entity.setLabels(labels);
+        entity.setLabels(labelResource.populateRemainingLabelEntitiesContent(labels));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -1461,7 +1328,7 @@ public class ProcessGroupResource extends ApplicationResource {
             required = true
         ) RemoteProcessGroupEntity remoteProcessGroupEntity) {
 
-        if (remoteProcessGroupEntity == null || remoteProcessGroupEntity.getRemoteProcessGroup() == null) {
+        if (remoteProcessGroupEntity == null || remoteProcessGroupEntity.getComponent() == null) {
             throw new IllegalArgumentException("Remote process group details must be specified.");
         }
 
@@ -1469,7 +1336,7 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        final RemoteProcessGroupDTO requestProcessGroupDTO = remoteProcessGroupEntity.getRemoteProcessGroup();
+        final RemoteProcessGroupDTO requestProcessGroupDTO = remoteProcessGroupEntity.getComponent();
 
         if (requestProcessGroupDTO.getId() != null) {
             throw new IllegalArgumentException("Remote process group ID cannot be specified.");
@@ -1479,14 +1346,14 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("The URI of the process group must be specified.");
         }
 
-        // if cluster manager, convert POST to PUT (to maintain same ID across nodes) and replicate
-        if (properties.isClusterManager()) {
-            // change content type to JSON for serializing entity if request came through overloaded endpoint
-            final Map<String, String> headersToOverride = new HashMap<>();
-            headersToOverride.put("content-type", MediaType.APPLICATION_JSON);
+        if (requestProcessGroupDTO.getParentGroupId() != null && !groupId.equals(requestProcessGroupDTO.getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                requestProcessGroupDTO.getParentGroupId(), groupId));
+        }
+        requestProcessGroupDTO.setParentGroupId(groupId);
 
-            // replicate the request
-            return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(remoteProcessGroupEntity), getHeaders(headersToOverride)).getResponse();
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(remoteProcessGroupEntity), getHeaders()).getResponse();
         }
 
         // handle expects request (usually from the cluster manager)
@@ -1531,30 +1398,15 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // create the remote process group
         final RevisionDTO revision = remoteProcessGroupEntity.getRevision();
-        final ConfigurationSnapshot<RemoteProcessGroupDTO> controllerResponse
-            = serviceFacade.createRemoteProcessGroup(new Revision(revision.getVersion(), revision.getClientId()), groupId, requestProcessGroupDTO);
-
-        // prepare the response
-        final RemoteProcessGroupDTO remoteProcessGroup = controllerResponse.getConfiguration();
-        remoteProcessGroupResource.populateRemainingRemoteProcessGroupContent(remoteProcessGroup);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
+        final RemoteProcessGroupEntity entity = serviceFacade.createRemoteProcessGroup(new Revision(revision.getVersion(), revision.getClientId()), groupId, requestProcessGroupDTO);
+        remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntityContent(entity);
 
-        // build the response entity
-        final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
-        entity.setRevision(updatedRevision);
-        entity.setRemoteProcessGroup(remoteProcessGroup);
-
-        return clusterContext(generateCreatedResponse(URI.create(remoteProcessGroup.getUri()), entity)).build();
+        return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
     }
 
     /**
      * Retrieves all the of remote process groups in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param verbose Optional verbose flag that defaults to false. If the verbose flag is set to true remote group contents (ports) will be included.
      * @return A remoteProcessGroupEntity.
      */
@@ -1583,11 +1435,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getRemoteProcessGroups(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "Whether to include any encapulated ports or just details about the remote process group.",
             required = false
         )
@@ -1603,24 +1450,21 @@ public class ProcessGroupResource extends ApplicationResource {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
         }
 
-        // get all the labels
-        final Set<RemoteProcessGroupDTO> remoteProcessGroups = serviceFacade.getRemoteProcessGroups(groupId);
+        // get all the remote process groups
+        final Set<RemoteProcessGroupEntity> remoteProcessGroups = serviceFacade.getRemoteProcessGroups(groupId);
 
         // prune response as necessary
         if (!verbose) {
-            for (RemoteProcessGroupDTO remoteProcessGroup : remoteProcessGroups) {
-                remoteProcessGroup.setContents(null);
+            for (RemoteProcessGroupEntity remoteProcessGroupEntity : remoteProcessGroups) {
+                if (remoteProcessGroupEntity.getComponent() != null) {
+                    remoteProcessGroupEntity.getComponent().setContents(null);
+                }
             }
         }
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // create the response entity
         final RemoteProcessGroupsEntity entity = new RemoteProcessGroupsEntity();
-        entity.setRevision(revision);
-        entity.setRemoteProcessGroups(remoteProcessGroupResource.populateRemainingRemoteProcessGroupsContent(remoteProcessGroups));
+        entity.setRemoteProcessGroups(remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntitiesContent(remoteProcessGroups));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -1671,11 +1515,11 @@ public class ProcessGroupResource extends ApplicationResource {
             required = true
         ) ConnectionEntity connectionEntity) {
 
-        if (connectionEntity == null || connectionEntity.getConnection() == null) {
+        if (connectionEntity == null || connectionEntity.getComponent() == null) {
             throw new IllegalArgumentException("Connection details must be specified.");
         }
 
-        if (connectionEntity.getConnection().getId() != null) {
+        if (connectionEntity.getComponent().getId() != null) {
             throw new IllegalArgumentException("Connection ID cannot be specified.");
         }
 
@@ -1683,17 +1527,18 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("Revision must be specified.");
         }
 
-        if (properties.isClusterManager()) {
-            // change content type to JSON for serializing entity if request came through overloaded endpoint
-            final Map<String, String> headersToOverride = new HashMap<>();
-            headersToOverride.put("content-type", MediaType.APPLICATION_JSON);
+        if (connectionEntity.getComponent().getParentGroupId() != null && !groupId.equals(connectionEntity.getComponent().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                connectionEntity.getComponent().getParentGroupId(), groupId));
+        }
+        connectionEntity.getComponent().setParentGroupId(groupId);
 
-            // replicate the request
-            return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(connectionEntity), getHeaders(headersToOverride)).getResponse();
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(connectionEntity), getHeaders()).getResponse();
         }
 
         // get the connection
-        final ConnectionDTO connection = connectionEntity.getConnection();
+        final ConnectionDTO connection = connectionEntity.getComponent();
 
         // handle expects request (usually from the cluster manager)
         final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
@@ -1712,33 +1557,17 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // create the new relationship target
         final RevisionDTO revision = connectionEntity.getRevision();
-        final ConfigurationSnapshot<ConnectionDTO> controllerResponse = serviceFacade.createConnection(
-            new Revision(revision.getVersion(), revision.getClientId()), groupId, connection);
-        ConnectionDTO connectionDTO = controllerResponse.getConfiguration();
-
-        // marshall the target and add the source processor
-        connectionResource.populateRemainingConnectionContent(connectionDTO);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // create the response entity
-        ConnectionEntity entity = new ConnectionEntity();
-        entity.setRevision(updatedRevision);
-        entity.setConnection(connectionDTO);
+        final ConnectionEntity entity = serviceFacade.createConnection(new Revision(revision.getVersion(), revision.getClientId()), groupId, connection);
+        connectionResource.populateRemainingConnectionEntityContent(entity);
 
         // extract the href and build the response
-        String href = connectionDTO.getUri();
-
-        return clusterContext(generateCreatedResponse(URI.create(href), entity)).build();
+        String uri = entity.getComponent().getUri();
+        return clusterContext(generateCreatedResponse(URI.create(uri), entity)).build();
     }
 
     /**
      * Gets all the connections.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @return A connectionsEntity.
      */
     @GET
@@ -1766,11 +1595,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getConnections(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -1782,16 +1606,11 @@ public class ProcessGroupResource extends ApplicationResource {
         }
 
         // all of the relationships for the specified source processor
-        Set<ConnectionDTO> connections = serviceFacade.getConnections(groupId);
-
-        // create the revision
-        RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
+        Set<ConnectionEntity> connections = serviceFacade.getConnections(groupId);
 
         // create the client response entity
         ConnectionsEntity entity = new ConnectionsEntity();
-        entity.setRevision(revision);
-        entity.setConnections(connectionResource.populateRemainingConnectionsContent(connections));
+        entity.setConnections(connectionResource.populateRemainingConnectionEntitiesContent(connections));
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -1861,6 +1680,12 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("The group id must be specified when creating a snippet.");
         }
 
+        if (snippetEntity.getSnippet().getParentGroupId() != null && !groupId.equals(snippetEntity.getSnippet().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                snippetEntity.getSnippet().getParentGroupId(), groupId));
+        }
+        snippetEntity.getSnippet().setParentGroupId(groupId);
+
         if (properties.isClusterManager()) {
             return (Response) clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(snippetEntity), getHeaders()).getResponse();
         }
@@ -1886,9 +1711,6 @@ public class ProcessGroupResource extends ApplicationResource {
         // get the snippet
         final SnippetDTO snippet = response.getConfiguration();
 
-        // always prune the response when creating
-        snippet.setContents(null);
-
         // get the updated revision
         final RevisionDTO updatedRevision = new RevisionDTO();
         updatedRevision.setClientId(revision.getClientId());
@@ -1906,11 +1728,6 @@ public class ProcessGroupResource extends ApplicationResource {
     /**
      * Retrieves the specified snippet.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
-     * @param verbose Whether or not to include the contents of the snippet in
-     * the response.
      * @param id The id of the snippet to retrieve.
      * @return A snippetEntity.
      */
@@ -1939,16 +1756,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getSnippet(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
-            value = "Whether to include configuration details for the components specified in the snippet.",
-            required = false
-        )
-        @QueryParam("verbose") @DefaultValue(VERBOSE) Boolean verbose,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -1967,14 +1774,8 @@ public class ProcessGroupResource extends ApplicationResource {
         // get the snippet
         final SnippetDTO snippet = serviceFacade.getSnippet(id);
 
-        // prune the response if necessary
-        if (!verbose) {
-            snippet.setContents(null);
-        }
-
         // create the revision
         final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
 
         // create the response entity
         final SnippetEntity entity = new SnippetEntity();
@@ -2066,9 +1867,6 @@ public class ProcessGroupResource extends ApplicationResource {
         // get the results
         final SnippetDTO snippet = controllerResponse.getConfiguration();
 
-        // always prune update responses
-        snippet.setContents(null);
-
         // get the updated revision
         final RevisionDTO updatedRevision = new RevisionDTO();
         updatedRevision.setClientId(revision.getClientId());
@@ -2241,18 +2039,16 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // copy the specified snippet
         final RevisionDTO requestRevision = copySnippetEntity.getRevision();
-        final ConfigurationSnapshot<FlowSnippetDTO> controllerResponse = serviceFacade.copySnippet(
+        final ConfigurationSnapshot<FlowDTO> controllerResponse = serviceFacade.copySnippet(
             new Revision(requestRevision.getVersion(), requestRevision.getClientId()),
             groupId, copySnippetEntity.getSnippetId(), copySnippetEntity.getOriginX(), copySnippetEntity.getOriginY());
 
         // get the snippet
-        final FlowSnippetDTO flowSnippet = controllerResponse.getConfiguration();
+        final FlowDTO flow = controllerResponse.getConfiguration();
 
         // prune response as necessary
-        for (ProcessGroupDTO group : flowSnippet.getProcessGroups()) {
-            if (group.getContents() != null) {
-                group.setContents(null);
-            }
+        for (ProcessGroupEntity childGroupEntity : flow.getProcessGroups()) {
+            childGroupEntity.getComponent().setContents(null);
         }
 
         // get the updated revision
@@ -2261,9 +2057,9 @@ public class ProcessGroupResource extends ApplicationResource {
         revision.setVersion(controllerResponse.getVersion());
 
         // create the response entity
-        final FlowSnippetEntity entity = new FlowSnippetEntity();
+        final FlowEntity entity = new FlowEntity();
         entity.setRevision(revision);
-        entity.setContents(populateRemainingSnippetContent(flowSnippet));
+        entity.setFlow(populateRemainingSnippetContent(flow));
 
         // generate the response
         return clusterContext(generateCreatedResponse(getAbsolutePath(), entity)).build();
@@ -2282,7 +2078,7 @@ public class ProcessGroupResource extends ApplicationResource {
      * @param httpServletRequest request
      * @param groupId The group id
      * @param instantiateTemplateRequestEntity The instantiate template request
-     * @return A flowSnippetEntity.
+     * @return A flowEntity.
      */
     @POST
     @Consumes(MediaType.APPLICATION_JSON)
@@ -2291,7 +2087,7 @@ public class ProcessGroupResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
         value = "Instantiates a template",
-        response = FlowSnippetEntity.class,
+        response = FlowEntity.class,
         authorizations = {
             @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
         }
@@ -2335,17 +2131,15 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // create the template and generate the json
         final RevisionDTO requestRevision = instantiateTemplateRequestEntity.getRevision();
-        final ConfigurationSnapshot<FlowSnippetDTO> response = serviceFacade.createTemplateInstance(
+        final ConfigurationSnapshot<FlowDTO> response = serviceFacade.createTemplateInstance(
             new Revision(requestRevision.getVersion(), requestRevision.getClientId()), groupId, instantiateTemplateRequestEntity.getOriginX(),
             instantiateTemplateRequestEntity.getOriginY(), instantiateTemplateRequestEntity.getTemplateId());
 
-        final FlowSnippetDTO flowSnippet = response.getConfiguration();
+        final FlowDTO flowSnippet = response.getConfiguration();
 
         // prune response as necessary
-        for (ProcessGroupDTO group : flowSnippet.getProcessGroups()) {
-            if (group.getContents() != null) {
-                group.setContents(null);
-            }
+        for (ProcessGroupEntity childGroupEntity : flowSnippet.getProcessGroups()) {
+            childGroupEntity.getComponent().setContents(null);
         }
 
         // get the updated revision
@@ -2354,9 +2148,9 @@ public class ProcessGroupResource extends ApplicationResource {
         revision.setVersion(response.getVersion());
 
         // create the response entity
-        final FlowSnippetEntity entity = new FlowSnippetEntity();
+        final FlowEntity entity = new FlowEntity();
         entity.setRevision(revision);
-        entity.setContents(populateRemainingSnippetContent(flowSnippet));
+        entity.setFlow(populateRemainingSnippetContent(flowSnippet));
 
         // generate the response
         return clusterContext(generateCreatedResponse(getAbsolutePath(), entity)).build();
@@ -2369,9 +2163,6 @@ public class ProcessGroupResource extends ApplicationResource {
     /**
      * Retrieves all the of templates in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @return A templatesEntity.
      */
     @GET
@@ -2401,12 +2192,7 @@ public class ProcessGroupResource extends ApplicationResource {
             value = "The process group id.",
             required = true
         )
-        @PathParam("id") String groupId,
-        @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
+        @PathParam("id") String groupId) {
 
         // replicate if cluster manager
         if (properties.isClusterManager()) {
@@ -2418,7 +2204,6 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // create the revision
         final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
 
         // create the response entity
         final TemplatesEntity entity = new TemplatesEntity();
@@ -2470,6 +2255,8 @@ public class ProcessGroupResource extends ApplicationResource {
             required = true
         ) CreateTemplateRequestEntity createTemplateRequestEntity) {
 
+        // TODO - verify parent group id
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.POST, getAbsolutePath(), updateClientId(createTemplateRequestEntity), getHeaders()).getResponse();
@@ -2716,6 +2503,12 @@ public class ProcessGroupResource extends ApplicationResource {
             throw new IllegalArgumentException("The type of controller service to create must be specified.");
         }
 
+        if (controllerServiceEntity.getControllerService().getParentGroupId() != null && !groupId.equals(controllerServiceEntity.getControllerService().getParentGroupId())) {
+            throw new IllegalArgumentException(String.format("If specified, the parent process group id %s must be the same as specified in the URI %s",
+                controllerServiceEntity.getControllerService().getParentGroupId(), groupId));
+        }
+        controllerServiceEntity.getControllerService().setParentGroupId(groupId);
+
         // get the revision
         final RevisionDTO revision = controllerServiceEntity.getRevision();
 
@@ -2749,8 +2542,8 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // build the response entity
         final ControllerServiceEntity entity = new ControllerServiceEntity();
-        entity.setRevision(updatedRevision);
         entity.setControllerService(controllerServiceResource.populateRemainingControllerServiceContent(availability, controllerService));
+        entity.setRevision(updatedRevision);
 
         // build the response
         return clusterContext(generateCreatedResponse(URI.create(controllerService.getUri()), entity)).build();
@@ -2759,9 +2552,6 @@ public class ProcessGroupResource extends ApplicationResource {
     /**
      * Retrieves all the of controller services in this NiFi.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @param availability Whether the controller service is available on the
      * NCM only (ncm) or on the nodes only (node). If this instance is not
      * clustered all services should use the node availability.
@@ -2791,11 +2581,6 @@ public class ProcessGroupResource extends ApplicationResource {
     )
     public Response getControllerServices(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The process group id.",
             required = true
         )
@@ -2819,7 +2604,6 @@ public class ProcessGroupResource extends ApplicationResource {
 
         // create the revision
         final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
 
         // create the response entity
         final ControllerServicesEntity entity = new ControllerServicesEntity();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
index 6202561..9dddd70 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
@@ -34,6 +34,7 @@ import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.UiExtensionType;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.ComponentStateDTO;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
@@ -89,6 +90,34 @@ public class ProcessorResource extends ApplicationResource {
     /**
      * Populate the uri's for the specified processors and their relationships.
      *
+     * @param processorEntities processors
+     * @return dtos
+     */
+    public Set<ProcessorEntity> populateRemainingProcessorEntitiesContent(Set<ProcessorEntity> processorEntities) {
+        for (ProcessorEntity processorEntity : processorEntities) {
+            if (processorEntity.getComponent() != null) {
+                populateRemainingProcessorContent(processorEntity.getComponent());
+            }
+        }
+        return processorEntities;
+    }
+
+    /**
+     * Populate the uri's for the specified processors and their relationships.
+     *
+     * @param processorEntity processors
+     * @return dtos
+     */
+    public ProcessorEntity populateRemainingProcessorEntityContent(ProcessorEntity processorEntity) {
+        if (processorEntity.getComponent() != null) {
+            populateRemainingProcessorContent(processorEntity.getComponent());
+        }
+        return processorEntity;
+    }
+
+    /**
+     * Populate the uri's for the specified processors and their relationships.
+     *
      * @param processors processors
      * @return dtos
      */
@@ -133,7 +162,6 @@ public class ProcessorResource extends ApplicationResource {
     /**
      * Retrieves the specified processor.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the processor to retrieve.
      * @return A processorEntity.
      */
@@ -162,11 +190,6 @@ public class ProcessorResource extends ApplicationResource {
     )
     public Response getProcessor(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The processor id.",
                     required = true
             )
@@ -178,16 +201,8 @@ public class ProcessorResource extends ApplicationResource {
         }
 
         // get the specified processor
-        final ProcessorDTO processor = serviceFacade.getProcessor(id);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // generate the response entity
-        final ProcessorEntity entity = new ProcessorEntity();
-        entity.setRevision(revision);
-        entity.setProcessor(populateRemainingProcessorContent(processor));
+        final ProcessorEntity entity = serviceFacade.getProcessor(id);
+        populateRemainingProcessorEntityContent(entity);
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -196,7 +211,6 @@ public class ProcessorResource extends ApplicationResource {
     /**
      * Returns the descriptor for the specified property.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the processor
      * @param propertyName The property
      * @return a propertyDescriptorEntity
@@ -254,13 +268,8 @@ public class ProcessorResource extends ApplicationResource {
         // get the property descriptor
         final PropertyDescriptorDTO descriptor = serviceFacade.getProcessorPropertyDescriptor(id, propertyName);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // generate the response entity
         final PropertyDescriptorEntity entity = new PropertyDescriptorEntity();
-        entity.setRevision(revision);
         entity.setPropertyDescriptor(descriptor);
 
         // generate the response
@@ -270,7 +279,6 @@ public class ProcessorResource extends ApplicationResource {
     /**
      * Gets the state for a processor.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the processor
      * @return a componentStateEntity
      */
@@ -297,11 +305,6 @@ public class ProcessorResource extends ApplicationResource {
     )
     public Response getState(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "The processor id.",
             required = true
         )
@@ -315,13 +318,8 @@ public class ProcessorResource extends ApplicationResource {
         // get the component state
         final ComponentStateDTO state = serviceFacade.getProcessorState(id);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // generate the response entity
         final ComponentStateEntity entity = new ComponentStateEntity();
-        entity.setRevision(revision);
         entity.setComponentState(state);
 
         // generate the response
@@ -446,7 +444,7 @@ public class ProcessorResource extends ApplicationResource {
             )
             ProcessorEntity processorEntity) {
 
-        if (processorEntity == null || processorEntity.getProcessor() == null) {
+        if (processorEntity == null || processorEntity.getComponent() == null) {
             throw new IllegalArgumentException("Processor details must be specified.");
         }
 
@@ -455,7 +453,7 @@ public class ProcessorResource extends ApplicationResource {
         }
 
         // ensure the same id is being used
-        final ProcessorDTO requestProcessorDTO = processorEntity.getProcessor();
+        final ProcessorDTO requestProcessorDTO = processorEntity.getComponent();
         if (!id.equals(requestProcessorDTO.getId())) {
             throw new IllegalArgumentException(String.format("The processor id (%s) in the request body does "
                     + "not equal the processor id of the requested resource (%s).", requestProcessorDTO.getId(), id));
@@ -485,25 +483,12 @@ public class ProcessorResource extends ApplicationResource {
 
         // update the processor
         final RevisionDTO revision = processorEntity.getRevision();
-        final ConfigurationSnapshot<ProcessorDTO> controllerResponse = serviceFacade.updateProcessor(
-                new Revision(revision.getVersion(), revision.getClientId()), requestProcessorDTO);
-
-        // get the processor dto
-        final ProcessorDTO responseProcessorDTO = controllerResponse.getConfiguration();
-        populateRemainingProcessorContent(responseProcessorDTO);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
+        final UpdateResult<ProcessorEntity> result = serviceFacade.updateProcessor(new Revision(revision.getVersion(), revision.getClientId()), requestProcessorDTO);
+        final ProcessorEntity entity = result.getResult();
+        populateRemainingProcessorEntityContent(entity);
 
-        // generate the response entity
-        final ProcessorEntity entity = new ProcessorEntity();
-        entity.setRevision(updatedRevision);
-        entity.setProcessor(responseProcessorDTO);
-
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(responseProcessorDTO.getUri()), entity)).build();
+        if (result.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -576,16 +561,7 @@ public class ProcessorResource extends ApplicationResource {
         }
 
         // delete the processor
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteProcessor(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(clientId.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // generate the response entity
-        final ProcessorEntity entity = new ProcessorEntity();
-        entity.setRevision(updatedRevision);
+        final ProcessorEntity entity = serviceFacade.deleteProcessor(new Revision(clientVersion, clientId.getClientId()), id);
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();


[02/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 bde0f41..5af7a45 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
@@ -59,9 +59,7 @@ nf.ProcessGroup = (function () {
      * Selects the process group elements against the current process group map.
      */
     var select = function () {
-        return processGroupContainer.selectAll('g.process-group').data(processGroupMap.values(), function (d) {
-            return d.component.id;
-        });
+        return processGroupContainer.selectAll('g.process-group').data(processGroupMap.values());
     };
 
     /**
@@ -78,7 +76,7 @@ nf.ProcessGroup = (function () {
         var processGroup = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': 'process-group component'
                 })
@@ -152,45 +150,48 @@ nf.ProcessGroup = (function () {
         // always support selecting and navigation
         processGroup.on('dblclick', function (d) {
                     // enter this group on double click
-                    nf.CanvasUtils.enterGroup(d.component.id);
+                    nf.CanvasUtils.enterGroup(d.id);
                 })
                 .call(nf.Selectable.activate).call(nf.ContextMenu.activate);
 
         // only support dragging, connection, and drag and drop if appropriate
         if (nf.Common.isDFM()) {
-            processGroup
-                    // Using mouseover/out to workaround chrome issue #122746
-                    .on('mouseover.drop', function (d) {
-                        // get the target and ensure its not already been marked for drop
-                        var target = d3.select(this);
-                        if (!target.classed('drop')) {
-                            var targetData = target.datum();
-                            
-                            // see if there is a selection being dragged
-                            var drag = d3.select('rect.drag-selection');
-                            if (!drag.empty()) {
-                                // filter the current selection by this group
-                                var selection = nf.CanvasUtils.getSelection().filter(function(d) {
-                                    return targetData.component.id === d.component.id;
-                                });
-                                
-                                // ensure this group isn't in the selection
-                                if (selection.empty()) {
-                                    // mark that we are hovering over a drop area if appropriate 
-                                    target.classed('drop', function () {
-                                        // get the current selection and ensure its disconnected
-                                        return nf.CanvasUtils.isDisconnected(nf.CanvasUtils.getSelection());
-                                    });
-                                }
-                            }
+            processGroup.filter(function (d) {
+                return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+            })
+            .on('mouseover.drop', function (d) {
+                // Using mouseover/out to workaround chrome issue #122746
+
+                // get the target and ensure its not already been marked for drop
+                var target = d3.select(this);
+                if (!target.classed('drop')) {
+                    var targetData = target.datum();
+
+                    // see if there is a selection being dragged
+                    var drag = d3.select('rect.drag-selection');
+                    if (!drag.empty()) {
+                        // filter the current selection by this group
+                        var selection = nf.CanvasUtils.getSelection().filter(function(d) {
+                            return targetData.id === d.id;
+                        });
+
+                        // ensure this group isn't in the selection
+                        if (selection.empty()) {
+                            // mark that we are hovering over a drop area if appropriate
+                            target.classed('drop', function () {
+                                // get the current selection and ensure its disconnected
+                                return nf.CanvasUtils.isDisconnected(nf.CanvasUtils.getSelection());
+                            });
                         }
-                    })
-                    .on('mouseout.drop', function (d) {
-                        // mark that we are no longer hovering over a drop area unconditionally
-                        d3.select(this).classed('drop', false);
-                    })
-                    .call(nf.Draggable.activate)
-                    .call(nf.Connectable.activate);
+                    }
+                }
+            })
+            .on('mouseout.drop', function (d) {
+                // mark that we are no longer hovering over a drop area unconditionally
+                d3.select(this).classed('drop', false);
+            })
+            .call(nf.Draggable.activate)
+            .call(nf.Connectable.activate);
         }
 
         // call update to trigger some rendering
@@ -210,7 +211,7 @@ nf.ProcessGroup = (function () {
             return;
         }
 
-        updated.each(function () {
+        updated.each(function (processGroupData) {
             var processGroup = d3.select(this);
             var details = processGroup.select('g.process-group-details');
 
@@ -261,150 +262,152 @@ nf.ProcessGroup = (function () {
                     // contents
                     // --------
 
-                    // input ports icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconInputPortSmall.png',
-                                'width': 16,
-                                'height': 16,
-                                'x': 10,
-                                'y': 25
-                            });
+                    if (processGroupData.accessPolicy.canRead) {
+                        // input ports icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconInputPortSmall.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'x': 10,
+                                    'y': 25
+                                });
 
-                    // input ports count
-                    details.append('text')
-                            .attr({
-                                'x': 29,
-                                'y': 37,
-                                'class': 'process-group-input-port-count process-group-contents-count'
-                            });
+                        // input ports count
+                        details.append('text')
+                                .attr({
+                                    'x': 29,
+                                    'y': 37,
+                                    'class': 'process-group-input-port-count process-group-contents-count'
+                                });
 
-                    // output ports icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconOutputPortSmall.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-output-port'
-                            });
+                        // output ports icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconOutputPortSmall.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-output-port'
+                                });
 
-                    // output ports count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-output-port-count process-group-contents-count'
-                            });
+                        // output ports count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-output-port-count process-group-contents-count'
+                                });
 
-                    // transmitting icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconTransmissionActive.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-transmitting'
-                            });
+                        // transmitting icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconTransmissionActive.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-transmitting'
+                                });
 
-                    // transmitting count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-transmitting-count process-group-contents-count'
-                            });
+                        // transmitting count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-transmitting-count process-group-contents-count'
+                                });
 
-                    // not transmitting icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconTransmissionInactive.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-not-transmitting'
-                            });
+                        // not transmitting icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconTransmissionInactive.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-not-transmitting'
+                                });
 
-                    // not transmitting count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-not-transmitting-count process-group-contents-count'
-                            });
+                        // not transmitting count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-not-transmitting-count process-group-contents-count'
+                                });
 
-                    // running icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconRun.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-running'
-                            });
+                        // running icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconRun.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-running'
+                                });
 
-                    // running count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-running-count process-group-contents-count'
-                            });
+                        // running count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-running-count process-group-contents-count'
+                                });
 
-                    // stopped icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconStop.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-stopped'
-                            });
+                        // stopped icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconStop.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-stopped'
+                                });
 
-                    // stopped count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-stopped-count process-group-contents-count'
-                            });
+                        // stopped count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-stopped-count process-group-contents-count'
+                                });
 
-                    // invalid icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconAlert.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-invalid'
-                            });
+                        // invalid icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconAlert.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-invalid'
+                                });
 
-                    // invalid count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-invalid-count process-group-contents-count'
-                            });
+                        // invalid count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-invalid-count process-group-contents-count'
+                                });
 
-                    // disabled icon
-                    details.append('image')
-                            .call(nf.CanvasUtils.disableImageHref)
-                            .attr({
-                                'xlink:href': 'images/iconDisable.png',
-                                'width': 16,
-                                'height': 16,
-                                'y': 25,
-                                'class': 'process-group-disabled'
-                            });
+                        // disabled icon
+                        details.append('image')
+                                .call(nf.CanvasUtils.disableImageHref)
+                                .attr({
+                                    'xlink:href': 'images/iconDisable.png',
+                                    'width': 16,
+                                    'height': 16,
+                                    'y': 25,
+                                    'class': 'process-group-disabled'
+                                });
 
-                    // disabled count
-                    details.append('text')
-                            .attr({
-                                'y': 37,
-                                'class': 'process-group-disabled-count process-group-contents-count'
-                            });
+                        // disabled count
+                        details.append('text')
+                                .attr({
+                                    'y': 37,
+                                    'class': 'process-group-disabled-count process-group-contents-count'
+                                });
+                    }
 
                     // -----
                     // stats
@@ -600,157 +603,159 @@ nf.ProcessGroup = (function () {
                             });
                 }
 
-                // update the input ports
-                var inputPortCount = details.select('text.process-group-input-port-count')
-                        .text(function (d) {
-                            return d.component.inputPortCount;
-                        });
+                if (processGroupData.accessPolicy.canRead) {
+                    // update the input ports
+                    var inputPortCount = details.select('text.process-group-input-port-count')
+                            .text(function (d) {
+                                return d.component.inputPortCount;
+                            });
 
-                // update the output ports
-                var outputPort = details.select('image.process-group-output-port')
-                        .attr('x', function () {
-                            var inputPortCountX = parseInt(inputPortCount.attr('x'), 10);
-                            return inputPortCountX + inputPortCount.node().getComputedTextLength() + CONTENTS_SPACER;
-                        });
-                details.select('text.process-group-output-port-count')
-                        .attr('x', function () {
-                            var outputPortImageX = parseInt(outputPort.attr('x'), 10);
-                            var outputPortImageWidth = parseInt(outputPort.attr('width'), 10);
-                            return outputPortImageX + outputPortImageWidth + CONTENTS_SPACER;
-                        })
-                        .text(function (d) {
-                            return d.component.outputPortCount;
-                        });
+                    // update the output ports
+                    var outputPort = details.select('image.process-group-output-port')
+                            .attr('x', function () {
+                                var inputPortCountX = parseInt(inputPortCount.attr('x'), 10);
+                                return inputPortCountX + inputPortCount.node().getComputedTextLength() + CONTENTS_SPACER;
+                            });
+                    details.select('text.process-group-output-port-count')
+                            .attr('x', function () {
+                                var outputPortImageX = parseInt(outputPort.attr('x'), 10);
+                                var outputPortImageWidth = parseInt(outputPort.attr('width'), 10);
+                                return outputPortImageX + outputPortImageWidth + CONTENTS_SPACER;
+                            })
+                            .text(function (d) {
+                                return d.component.outputPortCount;
+                            });
 
-                // get the container to help right align
-                var container = details.select('rect.process-group-contents-container');
-
-                // update disabled
-                var disabledCount = details.select('text.process-group-disabled-count')
-                        .text(function (d) {
-                            return d.component.disabledCount;
-                        })
-                        .attr('x', function () {
-                            var containerX = parseInt(container.attr('x'), 10);
-                            var containerWidth = parseInt(container.attr('width'), 10);
-                            return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var disabled = details.select('image.process-group-disabled')
-                        .attr('x', function () {
-                            var disabledCountX = parseInt(disabledCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return disabledCountX - width - CONTENTS_SPACER;
-                        });
+                    // get the container to help right align
+                    var container = details.select('rect.process-group-contents-container');
 
-                // update invalid
-                var invalidCount = details.select('text.process-group-invalid-count')
-                        .text(function (d) {
-                            return d.component.invalidCount;
-                        })
-                        .attr('x', function () {
-                            var disabledX = parseInt(disabled.attr('x'), 10);
-                            return disabledX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var invalid = details.select('image.process-group-invalid')
-                        .attr('x', function () {
-                            var invalidCountX = parseInt(invalidCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return invalidCountX - width - CONTENTS_SPACER;
-                        });
+                    // update disabled
+                    var disabledCount = details.select('text.process-group-disabled-count')
+                            .text(function (d) {
+                                return d.component.disabledCount;
+                            })
+                            .attr('x', function () {
+                                var containerX = parseInt(container.attr('x'), 10);
+                                var containerWidth = parseInt(container.attr('width'), 10);
+                                return containerX + containerWidth - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var disabled = details.select('image.process-group-disabled')
+                            .attr('x', function () {
+                                var disabledCountX = parseInt(disabledCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return disabledCountX - width - CONTENTS_SPACER;
+                            });
 
-                // update stopped
-                var stoppedCount = details.select('text.process-group-stopped-count')
-                        .text(function (d) {
-                            return d.component.stoppedCount;
-                        })
-                        .attr('x', function () {
-                            var invalidX = parseInt(invalid.attr('x'), 10);
-                            return invalidX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var stopped = details.select('image.process-group-stopped')
-                        .attr('x', function () {
-                            var stoppedCountX = parseInt(stoppedCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return stoppedCountX - width - CONTENTS_SPACER;
-                        });
+                    // update invalid
+                    var invalidCount = details.select('text.process-group-invalid-count')
+                            .text(function (d) {
+                                return d.component.invalidCount;
+                            })
+                            .attr('x', function () {
+                                var disabledX = parseInt(disabled.attr('x'), 10);
+                                return disabledX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var invalid = details.select('image.process-group-invalid')
+                            .attr('x', function () {
+                                var invalidCountX = parseInt(invalidCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return invalidCountX - width - CONTENTS_SPACER;
+                            });
 
-                // update running
-                var runningCount = details.select('text.process-group-running-count')
-                        .text(function (d) {
-                            return d.component.runningCount;
-                        })
-                        .attr('x', function () {
-                            var stoppedX = parseInt(stopped.attr('x'), 10);
-                            return stoppedX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var running = details.select('image.process-group-running')
-                        .attr('x', function () {
-                            var runningCountX = parseInt(runningCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return runningCountX - width - CONTENTS_SPACER;
-                        });
+                    // update stopped
+                    var stoppedCount = details.select('text.process-group-stopped-count')
+                            .text(function (d) {
+                                return d.component.stoppedCount;
+                            })
+                            .attr('x', function () {
+                                var invalidX = parseInt(invalid.attr('x'), 10);
+                                return invalidX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var stopped = details.select('image.process-group-stopped')
+                            .attr('x', function () {
+                                var stoppedCountX = parseInt(stoppedCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return stoppedCountX - width - CONTENTS_SPACER;
+                            });
 
-                // update not transmitting
-                var notTransmittingCount = details.select('text.process-group-not-transmitting-count')
-                        .text(function (d) {
-                            return d.component.inactiveRemotePortCount;
-                        })
-                        .attr('x', function () {
-                            var runningX = parseInt(running.attr('x'), 10);
-                            return runningX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                var notTransmitting = details.select('image.process-group-not-transmitting')
-                        .attr('x', function () {
-                            var notTransmittingCountX = parseInt(notTransmittingCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return notTransmittingCountX - width - CONTENTS_SPACER;
-                        });
+                    // update running
+                    var runningCount = details.select('text.process-group-running-count')
+                            .text(function (d) {
+                                return d.component.runningCount;
+                            })
+                            .attr('x', function () {
+                                var stoppedX = parseInt(stopped.attr('x'), 10);
+                                return stoppedX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var running = details.select('image.process-group-running')
+                            .attr('x', function () {
+                                var runningCountX = parseInt(runningCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return runningCountX - width - CONTENTS_SPACER;
+                            });
 
-                // update transmitting
-                var transmittingCount = details.select('text.process-group-transmitting-count')
-                        .text(function (d) {
-                            return d.component.activeRemotePortCount;
-                        })
-                        .attr('x', function () {
-                            var notTransmittingX = parseInt(notTransmitting.attr('x'), 10);
-                            return notTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
-                        });
-                details.select('image.process-group-transmitting')
-                        .attr('x', function () {
-                            var transmittingCountX = parseInt(transmittingCount.attr('x'), 10);
-                            var width = parseInt(d3.select(this).attr('width'), 10);
-                            return transmittingCountX - width - CONTENTS_SPACER;
-                        });
+                    // update not transmitting
+                    var notTransmittingCount = details.select('text.process-group-not-transmitting-count')
+                            .text(function (d) {
+                                return d.component.inactiveRemotePortCount;
+                            })
+                            .attr('x', function () {
+                                var runningX = parseInt(running.attr('x'), 10);
+                                return runningX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    var notTransmitting = details.select('image.process-group-not-transmitting')
+                            .attr('x', function () {
+                                var notTransmittingCountX = parseInt(notTransmittingCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return notTransmittingCountX - width - CONTENTS_SPACER;
+                            });
 
-                // update the process group comments
-                details.select('text.process-group-comments')
-                        .each(function (d) {
-                            var processGroupComments = d3.select(this);
+                    // update transmitting
+                    var transmittingCount = details.select('text.process-group-transmitting-count')
+                            .text(function (d) {
+                                return d.component.activeRemotePortCount;
+                            })
+                            .attr('x', function () {
+                                var notTransmittingX = parseInt(notTransmitting.attr('x'), 10);
+                                return notTransmittingX - this.getComputedTextLength() - CONTENTS_SPACER;
+                            });
+                    details.select('image.process-group-transmitting')
+                            .attr('x', function () {
+                                var transmittingCountX = parseInt(transmittingCount.attr('x'), 10);
+                                var width = parseInt(d3.select(this).attr('width'), 10);
+                                return transmittingCountX - width - CONTENTS_SPACER;
+                            });
 
-                            // reset the process group name to handle any previous state
-                            processGroupComments.text(null).selectAll('tspan, title').remove();
+                    // update the process group comments
+                    details.select('text.process-group-comments')
+                            .each(function (d) {
+                                var processGroupComments = d3.select(this);
 
-                            // apply ellipsis to the port name as necessary
-                            nf.CanvasUtils.multilineEllipsis(processGroupComments, 2, getProcessGroupComments(d));
-                        }).classed('unset', function (d) {
-                    return nf.Common.isBlank(d.component.comments);
-                }).append('title').text(function (d) {
-                    return getProcessGroupComments(d);
-                });
+                                // reset the process group name to handle any previous state
+                                processGroupComments.text(null).selectAll('tspan, title').remove();
 
-                // update the process group name
-                processGroup.select('text.process-group-name')
-                        .each(function (d) {
-                            var processGroupName = d3.select(this);
+                                // apply ellipsis to the port name as necessary
+                                nf.CanvasUtils.multilineEllipsis(processGroupComments, 2, getProcessGroupComments(d));
+                            }).classed('unset', function (d) {
+                        return nf.Common.isBlank(d.component.comments);
+                    }).append('title').text(function (d) {
+                        return getProcessGroupComments(d);
+                    });
 
-                            // reset the process group name to handle any previous state
-                            processGroupName.text(null).selectAll('title').remove();
+                    // update the process group name
+                    processGroup.select('text.process-group-name')
+                            .each(function (d) {
+                                var processGroupName = d3.select(this);
 
-                            // apply ellipsis to the process group name as necessary
-                            nf.CanvasUtils.ellipsis(processGroupName, d.component.name);
-                        }).append('title').text(function (d) {
-                    return d.component.name;
-                });
+                                // reset the process group name to handle any previous state
+                                processGroupName.text(null).selectAll('title').remove();
+
+                                // apply ellipsis to the process group name as necessary
+                                nf.CanvasUtils.ellipsis(processGroupName, d.component.name);
+                            }).append('title').text(function (d) {
+                        return d.component.name;
+                    });
+                }
 
                 // hide the preview
                 processGroup.select('image.process-group-preview').style('display', 'none');
@@ -758,16 +763,18 @@ nf.ProcessGroup = (function () {
                 // populate the stats
                 processGroup.call(updateProcessGroupStatus);
             } else {
-                // update the process group name
-                processGroup.select('text.process-group-name')
-                        .text(function (d) {
-                            var name = d.component.name;
-                            if (name.length > PREVIEW_NAME_LENGTH) {
-                                return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
-                            } else {
-                                return name;
-                            }
-                        });
+                if (processGroupData.accessPolicy.canRead) {
+                    // update the process group name
+                    processGroup.select('text.process-group-name')
+                            .text(function (d) {
+                                var name = d.component.name;
+                                if (name.length > PREVIEW_NAME_LENGTH) {
+                                    return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
+                                } else {
+                                    return name;
+                                }
+                            });
+                }
 
                 // show the preview
                 processGroup.select('image.process-group-preview').style('display', 'block');
@@ -876,7 +883,7 @@ nf.ProcessGroup = (function () {
     var removeTooltips = function (removed) {
         removed.each(function (d) {
             // remove any associated tooltips
-            $('#bulletin-tip-' + d.component.id).remove();
+            $('#bulletin-tip-' + d.id).remove();
         });
     };
 
@@ -898,28 +905,27 @@ nf.ProcessGroup = (function () {
         /**
          * Populates the graph with the specified process groups.
          *
-         * @argument {object | array} processGroups                    The process groups to add
+         * @argument {object | array} processGroupEntities                    The process groups to add
          * @argument {boolean} selectAll                Whether or not to select the new contents
          */
-        add: function (processGroups, selectAll) {
+        add: function (processGroupEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
-            var add = function (processGroup) {
+            var add = function (processGroupEntity) {
                 // add the process group
-                processGroupMap.set(processGroup.id, {
+                processGroupMap.set(processGroupEntity.id, $.extend({
                     type: 'ProcessGroup',
-                    component: processGroup,
                     dimensions: dimensions
-                });
+                }, processGroupEntity));
             };
 
             // determine how to handle the specified process groups
-            if ($.isArray(processGroups)) {
-                $.each(processGroups, function (_, processGroup) {
-                    add(processGroup);
+            if ($.isArray(processGroupEntities)) {
+                $.each(processGroupEntities, function (_, processGroupEntity) {
+                    add(processGroupEntity);
                 });
             } else {
-                add(processGroups);
+                add(processGroupEntities);
             }
 
             // apply the selection and handle all new process group
@@ -974,7 +980,7 @@ nf.ProcessGroup = (function () {
                     url: processGroup.uri,
                     dataType: 'json'
                 }).done(function (response) {
-                    nf.ProcessGroup.set(response.processGroup);
+                    nf.ProcessGroup.set(response);
                 });
             }
         },
@@ -993,27 +999,27 @@ nf.ProcessGroup = (function () {
          * will set each process group. If it is not an array, it will
          * attempt to set the specified process group.
          *
-         * @param {object | array} processGroups
+         * @param {object | array} processGroupEntities
          */
-        set: function (processGroups) {
-            var set = function (processGroup) {
-                if (processGroupMap.has(processGroup.id)) {
+        set: function (processGroupEntities) {
+            var set = function (processGroupEntity) {
+                if (processGroupMap.has(processGroupEntity.id)) {
                     // update the current entry
-                    var processGroupEntry = processGroupMap.get(processGroup.id);
-                    processGroupEntry.component = processGroup;
-
+                    var processGroupEntry = processGroupMap.get(processGroupEntity.id);
+                    $.extend(processGroupEntry, processGroupEntity);
+                    
                     // update the process group in the UI
-                    d3.select('#id-' + processGroup.id).call(updateProcessGroups);
+                    d3.select('#id-' + processGroupEntry.id).call(updateProcessGroups);
                 }
             };
 
             // determine how to handle the specified process group
-            if ($.isArray(processGroups)) {
-                $.each(processGroups, function (_, processGroup) {
-                    set(processGroup);
+            if ($.isArray(processGroupEntities)) {
+                $.each(processGroupEntities, function (_, processGroupEntity) {
+                    set(processGroupEntity);
                 });
             } else {
-                set(processGroups);
+                set(processGroupEntities);
             }
         },
         
@@ -1040,13 +1046,6 @@ nf.ProcessGroup = (function () {
         },
 
         /**
-         * Returns the entity key when marshalling an entity of this type.
-         */
-        getEntityKey: function (d) {
-            return 'processGroup';
-        },
-        
-        /**
          * Removes the specified process group.
          *
          * @param {string} processGroups      The process group id(s)

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.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-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js
index 1271480..b6b7f34 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-processor-configuration.js
@@ -303,7 +303,7 @@ nf.ProcessorConfiguration = (function () {
         // create the processor entity
         var processorEntity = {};
         processorEntity['revision'] = nf.Client.getRevision();
-        processorEntity['processor'] = processorDto;
+        processorEntity['component'] = processorDto;
 
         // return the marshaled details
         return processorEntity;
@@ -340,7 +340,7 @@ nf.ProcessorConfiguration = (function () {
      */
     var validateDetails = function (details) {
         var errors = [];
-        var processor = details['processor'];
+        var processor = details['component'];
         var config = processor['config'];
 
         // ensure numeric fields are specified correctly
@@ -377,8 +377,10 @@ nf.ProcessorConfiguration = (function () {
     var reloadProcessorConnections = function (processor) {
         var connections = nf.Connection.getComponentConnections(processor.id);
         $.each(connections, function (_, connection) {
-            if (connection.source.id === processor.id) {
-                nf.Connection.reload(connection);
+            if (connection.accessPolicy.canRead) {
+                if (connection.sourceId === processor.id) {
+                    nf.Connection.reload(connection);
+                }
             }
         });
     };
@@ -435,7 +437,7 @@ nf.ProcessorConfiguration = (function () {
                 processData: false,
                 contentType: 'application/json'
             }).done(function (response) {
-                if (nf.Common.isDefinedAndNotNull(response.processor)) {
+                if (nf.Common.isDefinedAndNotNull(response.component)) {
                     // update the revision
                     nf.Client.setRevision(response.revision);
                 }
@@ -592,7 +594,7 @@ nf.ProcessorConfiguration = (function () {
                 // once everything is loaded, show the dialog
                 $.when.apply(window, requests).done(function (processorResponse, historyResponse) {
                     // get the updated processor
-                    processor = processorResponse[0].processor;
+                    processor = processorResponse[0].component;
                     
                     // get the processor history
                     var processorHistory = historyResponse[0].componentHistory;
@@ -717,7 +719,7 @@ nf.ProcessorConfiguration = (function () {
                                     // save the processor
                                     saveProcessor(processor).done(function (response) {
                                         // set the new processor state based on the response
-                                        nf.Processor.set(response.processor);
+                                        nf.Processor.set(response);
 
                                         // reload the processor's outgoing connections
                                         reloadProcessorConnections(processor);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 e46b462..dbe5246 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
@@ -47,9 +47,7 @@ nf.Processor = (function () {
      * Selects the processor elements against the current processor map.
      */
     var select = function () {
-        return processorContainer.selectAll('g.processor').data(processorMap.values(), function (d) {
-            return d.component.id;
-        });
+        return processorContainer.selectAll('g.processor').data(processorMap.values());
     };
 
     // renders the processors
@@ -61,7 +59,7 @@ nf.Processor = (function () {
         var processor = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': 'processor component'
                 })
@@ -138,9 +136,9 @@ nf.Processor = (function () {
         processor.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
 
         // only activate dragging and connecting if appropriate
-        if (nf.Common.isDFM()) {
-            processor.call(nf.Draggable.activate).call(nf.Connectable.activate);
-        }
+        processor.filter(function (d) {
+            return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+        }).call(nf.Draggable.activate).call(nf.Connectable.activate);
 
         // call update to trigger some rendering
         processor.call(updateProcessors);
@@ -156,7 +154,7 @@ nf.Processor = (function () {
             return;
         }
 
-        updated.each(function () {
+        updated.each(function (processorData) {
             var processor = d3.select(this);
             var details = processor.select('g.processor-details');
 
@@ -176,28 +174,30 @@ nf.Processor = (function () {
                                 'y': 5
                             });
 
-                    // processor type
-                    details.append('text')
-                            .attr({
-                                'x': 25,
-                                'y': 30,
-                                'width': 246,
-                                'height': 16,
-                                'font-size': '8pt',
-                                'font-weight': 'normal',
-                                'fill': 'black'
-                            })
-                            .each(function (d) {
-                                var processorType = d3.select(this);
-
-                                // reset the processor type to handle any previous state
-                                processorType.text(null).selectAll('title').remove();
-
-                                // apply ellipsis to the processor type as necessary
-                                nf.CanvasUtils.ellipsis(processorType, nf.Common.substringAfterLast(d.component.type, '.'));
-                            }).append('title').text(function (d) {
-                        return nf.Common.substringAfterLast(d.component.type, '.');
-                    });
+                    if (processorData.accessPolicy.canRead) {
+                        // processor type
+                        details.append('text')
+                                .attr({
+                                    'x': 25,
+                                    'y': 30,
+                                    'width': 246,
+                                    'height': 16,
+                                    'font-size': '8pt',
+                                    'font-weight': 'normal',
+                                    'fill': 'black'
+                                })
+                                .each(function (d) {
+                                    var processorType = d3.select(this);
+
+                                    // reset the processor type to handle any previous state
+                                    processorType.text(null).selectAll('title').remove();
+
+                                    // apply ellipsis to the processor type as necessary
+                                    nf.CanvasUtils.ellipsis(processorType, nf.Common.substringAfterLast(d.component.type, '.'));
+                                }).append('title').text(function (d) {
+                            return nf.Common.substringAfterLast(d.component.type, '.');
+                        });
+                    }
 
                     // -----
                     // stats
@@ -412,62 +412,64 @@ nf.Processor = (function () {
                             });
                 }
 
-                // update the run status
-                details.select('image.run-status-icon')
-                        .attr('xlink:href', function (d) {
-                            var img = '';
-                            if (d.component.state === 'DISABLED') {
-                                img = 'images/iconDisable.png';
-                            } else if (!nf.Common.isEmpty(d.component.validationErrors)) {
-                                img = 'images/iconAlert.png';
-                            } else if (d.component.state === 'RUNNING') {
-                                img = 'images/iconRun.png';
-                            } else if (d.component.state === 'STOPPED') {
-                                img = 'images/iconStop.png';
-                            }
-                            return img;
-                        })
-                        .each(function (d) {
-                            // remove the existing tip if necessary
-                            var tip = d3.select('#run-status-tip-' + d.component.id);
-                            if (!tip.empty()) {
-                                tip.remove();
-                            }
-
-                            // if there are validation errors generate a tooltip
-                            if (!nf.Common.isEmpty(d.component.validationErrors)) {
-                                tip = d3.select('#processor-tooltips').append('div')
-                                        .attr('id', function () {
-                                            return 'run-status-tip-' + d.component.id;
-                                        })
-                                        .attr('class', 'tooltip nifi-tooltip')
-                                        .html(function () {
-                                            var list = nf.Common.formatUnorderedList(d.component.validationErrors);
-                                            if (list === null || list.length === 0) {
-                                                return '';
-                                            } else {
-                                                return $('<div></div>').append(list).html();
-                                            }
-                                        });
-
-                                // add the tooltip
-                                nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
-                            }
-                        });
+                if (processorData.accessPolicy.canRead) {
+                    // update the run status
+                    details.select('image.run-status-icon')
+                            .attr('xlink:href', function (d) {
+                                var img = '';
+                                if (d.component.state === 'DISABLED') {
+                                    img = 'images/iconDisable.png';
+                                } else if (!nf.Common.isEmpty(d.component.validationErrors)) {
+                                    img = 'images/iconAlert.png';
+                                } else if (d.component.state === 'RUNNING') {
+                                    img = 'images/iconRun.png';
+                                } else if (d.component.state === 'STOPPED') {
+                                    img = 'images/iconStop.png';
+                                }
+                                return img;
+                            })
+                            .each(function (d) {
+                                // remove the existing tip if necessary
+                                var tip = d3.select('#run-status-tip-' + d.id);
+                                if (!tip.empty()) {
+                                    tip.remove();
+                                }
+
+                                // if there are validation errors generate a tooltip
+                                if (!nf.Common.isEmpty(d.component.validationErrors)) {
+                                    tip = d3.select('#processor-tooltips').append('div')
+                                            .attr('id', function () {
+                                                return 'run-status-tip-' + d.id;
+                                            })
+                                            .attr('class', 'tooltip nifi-tooltip')
+                                            .html(function () {
+                                                var list = nf.Common.formatUnorderedList(d.component.validationErrors);
+                                                if (list === null || list.length === 0) {
+                                                    return '';
+                                                } else {
+                                                    return $('<div></div>').append(list).html();
+                                                }
+                                            });
+
+                                    // add the tooltip
+                                    nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
+                                }
+                            });
 
-                // update the processor name
-                processor.select('text.processor-name')
-                        .each(function (d) {
-                            var processorName = d3.select(this);
+                    // update the processor name
+                    processor.select('text.processor-name')
+                            .each(function (d) {
+                                var processorName = d3.select(this);
 
-                            // reset the processor name to handle any previous state
-                            processorName.text(null).selectAll('title').remove();
+                                // reset the processor name to handle any previous state
+                                processorName.text(null).selectAll('title').remove();
 
-                            // apply ellipsis to the processor name as necessary
-                            nf.CanvasUtils.ellipsis(processorName, d.component.name);
-                        }).append('title').text(function (d) {
-                    return d.component.name;
-                });
+                                // apply ellipsis to the processor name as necessary
+                                nf.CanvasUtils.ellipsis(processorName, d.component.name);
+                            }).append('title').text(function (d) {
+                        return d.component.name;
+                    });
+                }
 
                 // hide the preview
                 processor.select('image.processor-stats-preview').style('display', 'none');
@@ -475,16 +477,18 @@ nf.Processor = (function () {
                 // populate the stats
                 processor.call(updateProcessorStatus);
             } else {
-                // update the processor name
-                processor.select('text.processor-name')
-                        .text(function (d) {
-                            var name = d.component.name;
-                            if (name.length > PREVIEW_NAME_LENGTH) {
-                                return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
-                            } else {
-                                return name;
-                            }
-                        });
+                if (processorData.accessPolicy.canRead) {
+                    // update the processor name
+                    processor.select('text.processor-name')
+                            .text(function (d) {
+                                var name = d.component.name;
+                                if (name.length > PREVIEW_NAME_LENGTH) {
+                                    return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
+                                } else {
+                                    return name;
+                                }
+                            });
+                }
 
                 // show the preview
                 processor.select('image.processor-stats-preview').style('display', 'block');
@@ -509,9 +513,11 @@ nf.Processor = (function () {
 
         // determine all unique colors
         processorMap.forEach(function (id, d) {
-            var color = d.component.style['background-color'];
-            if (nf.Common.isDefinedAndNotNull(color)) {
-                colors.add(nf.Common.substringAfterLast(color, '#'));
+            if (d.accessPolicy.canRead) {
+                var color = d.component.style['background-color'];
+                if (nf.Common.isDefinedAndNotNull(color)) {
+                    colors.add(nf.Common.substringAfterLast(color, '#'));
+                }
             }
         });
         nf.Canvas.defineProcessorColors(colors.values());
@@ -521,9 +527,11 @@ nf.Processor = (function () {
                 .attr('stroke', function (d) {
                     var color = nf.Processor.defaultColor();
 
-                    // use the specified color if appropriate
-                    if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
-                        color = d.component.style['background-color'];
+                    if (d.accessPolicy.canRead) {
+                        // use the specified color if appropriate
+                        if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
+                            color = d.component.style['background-color'];
+                        }
                     }
 
                     return color;
@@ -533,9 +541,11 @@ nf.Processor = (function () {
                 .attr('fill', function (d) {
                     var color = nf.Processor.defaultColor();
 
-                    // use the specified color if appropriate
-                    if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
-                        color = d.component.style['background-color'];
+                    if (d.accessPolicy.canRead) {
+                        // use the specified color if appropriate
+                        if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
+                            color = d.component.style['background-color'];
+                        }
                     }
 
                     // get just the color code part
@@ -635,8 +645,8 @@ nf.Processor = (function () {
     var removeTooltips = function (removed) {
         removed.each(function (d) {
             // remove any associated tooltips
-            $('#run-status-tip-' + d.component.id).remove();
-            $('#bulletin-tip-' + d.component.id).remove();
+            $('#run-status-tip-' + d.id).remove();
+            $('#bulletin-tip-' + d.id).remove();
         });
     };
 
@@ -658,28 +668,27 @@ nf.Processor = (function () {
         /**
          * Populates the graph with the specified processors.
          * 
-         * @argument {object | array} processors                The processors to add
+         * @argument {object | array} processorEntities                The processors to add
          * @argument {boolean} selectAll                Whether or not to select the new contents
          */
-        add: function (processors, selectAll) {
+        add: function (processorNodeEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
-            var add = function (processor) {
+            var add = function (processorEntity) {
                 // add the processor
-                processorMap.set(processor.id, {
+                processorMap.set(processorEntity.id, $.extend({
                     type: 'Processor',
-                    component: processor,
                     dimensions: dimensions
-                });
+                }, processorEntity));
             };
 
             // determine how to handle the specified processor
-            if ($.isArray(processors)) {
-                $.each(processors, function (_, processor) {
-                    add(processor);
+            if ($.isArray(processorNodeEntities)) {
+                $.each(processorNodeEntities, function (_, processorEntity) {
+                    add(processorEntity);
                 });
             } else {
-                add(processors);
+                add(processorNodeEntities);
             }
 
             // apply the selection and handle all new processors
@@ -743,7 +752,7 @@ nf.Processor = (function () {
                     url: processor.uri,
                     dataType: 'json'
                 }).done(function (response) {
-                    nf.Processor.set(response.processor);
+                    nf.Processor.set(response);
                 });
             }
         },
@@ -753,27 +762,27 @@ nf.Processor = (function () {
          * will set each processor. If it is not an array, it will 
          * attempt to set the specified processor.
          * 
-         * @param {object | array} processors
+         * @param {object | array} processorEntities
          */
-        set: function (processors) {
-            var set = function (processor) {
-                if (processorMap.has(processor.id)) {
+        set: function (processorEntities) {
+            var set = function (processorEntity) {
+                if (processorMap.has(processorEntity.id)) {
                     // update the current entry
-                    var processorEntry = processorMap.get(processor.id);
-                    processorEntry.component = processor;
-
+                    var processorEntry = processorMap.get(processorEntity.id);
+                    $.extend(processorEntry, processorEntity);
+                    
                     // update the processor in the UI
-                    d3.select('#id-' + processor.id).call(updateProcessors);
+                    d3.select('#id-' + processorEntry.id).call(updateProcessors);
                 }
             };
 
             // determine how to handle the specified processor
-            if ($.isArray(processors)) {
-                $.each(processors, function (_, processor) {
-                    set(processor);
+            if ($.isArray(processorEntities)) {
+                $.each(processorEntities, function (_, processorEntity) {
+                    set(processorEntity);
                 });
             } else {
-                set(processors);
+                set(processorEntities);
             }
         },
         
@@ -825,13 +834,6 @@ nf.Processor = (function () {
         },
 
         /**
-         * Returns the entity key when marshalling an entity of this type.
-         */
-        getEntityKey: function (d) {
-            return 'processor';
-        },
-        
-        /**
          * Returns the default color that should be used when drawing a processor.
          */
         defaultColor: function () {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
index 5f9de0c..6a8277b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-queue-listing.js
@@ -380,7 +380,7 @@ nf.QueueListing = (function () {
             // issue the request to list the flow files
             $.ajax({
                 type: 'POST',
-                url: '../nifi-api/flowfile-queues/' + connection.component.id + '/listing-requests',
+                url: '../nifi-api/flowfile-queues/' + connection.id + '/listing-requests',
                 dataType: 'json',
                 contentType: 'application/json'
             }).done(function(response) {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group-configuration.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-configuration.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-configuration.js
index 738b5b0..f539b66 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-configuration.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-configuration.js
@@ -32,8 +32,8 @@ nf.RemoteProcessGroupConfiguration = (function () {
 
                                 // create the remote process group details
                                 var remoteProcessGroupEntity = {
-                                    revision: nf.Client.getRevision(),
-                                    remoteProcessGroup: {
+                                    'revision': nf.Client.getRevision(),
+                                    'component': {
                                         id: remoteProcessGroupId,
                                         communicationsTimeout: $('#remote-process-group-timeout').val(),
                                         yieldDuration: $('#remote-process-group-yield-duration').val()
@@ -52,7 +52,7 @@ nf.RemoteProcessGroupConfiguration = (function () {
                                     nf.Client.setRevision(response.revision);
                                     
                                     // refresh the remote process group component
-                                    nf.RemoteProcessGroup.set(response.remoteProcessGroup);
+                                    nf.RemoteProcessGroup.set(response);
 
                                     // close the details panel
                                     $('#remote-process-group-configuration').modal('hide');
@@ -113,7 +113,7 @@ nf.RemoteProcessGroupConfiguration = (function () {
                 var selectionData = selection.datum();
 
                 // populate the port settings
-                $('#remote-process-group-id').text(selectionData.component.id);
+                $('#remote-process-group-id').text(selectionData.id);
                 $('#remote-process-group-name').text(selectionData.component.name);
                 $('#remote-process-group-url').text(selectionData.component.targetUri);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group-details.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-details.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-details.js
index b74628a..8ec7c89 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-details.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-details.js
@@ -58,7 +58,7 @@ nf.RemoteProcessGroupDetails = (function () {
                 var selectionData = selection.datum();
 
                 // populate the port settings
-                nf.Common.populateField('read-only-remote-process-group-id', selectionData.component.id);
+                nf.Common.populateField('read-only-remote-process-group-id', selectionData.id);
                 nf.Common.populateField('read-only-remote-process-group-name', selectionData.component.name);
                 nf.Common.populateField('read-only-remote-process-group-url', selectionData.component.targetUri);
                 nf.Common.populateField('read-only-remote-process-group-timeout', selectionData.component.communicationsTimeout);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-remote-process-group-ports.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-ports.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-ports.js
index ef51f46..4a0789e 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-ports.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-ports.js
@@ -40,8 +40,8 @@ nf.RemoteProcessGroupPorts = (function () {
 
                                 // create the remote process group details
                                 var remoteProcessGroupPortEntity = {
-                                    revision: nf.Client.getRevision(),
-                                    remoteProcessGroupPort: {
+                                    'revision': nf.Client.getRevision(),
+                                    'remoteProcessGroupPort': {
                                         id: remotePortId,
                                         useCompression: $('#remote-port-use-compression').hasClass('checkbox-checked'),
                                         concurrentlySchedulableTaskCount: remotePortConcurrentTasks
@@ -259,8 +259,8 @@ nf.RemoteProcessGroupPorts = (function () {
 
                     // create the remote process group details
                     var remoteProcessGroupPortEntity = {
-                        revision: nf.Client.getRevision(),
-                        remoteProcessGroupPort: {
+                        'revision': nf.Client.getRevision(),
+                        'remoteProcessGroupPort': {
                             id: port.id,
                             transmitting: isTransmitting
                         }
@@ -460,7 +460,7 @@ nf.RemoteProcessGroupPorts = (function () {
                     var remoteProcessGroup = response.remoteProcessGroup;
 
                     // set the model locally
-                    nf.RemoteProcessGroup.set(remoteProcessGroup);
+                    nf.RemoteProcessGroup.set(response);
 
                     // populate the port settings
                     $('#remote-process-group-ports-id').text(remoteProcessGroup.id);


[13/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
NIFI-1554:
- Populating component entities in the REST API to decouple key fields from the configuration DTOs.
- Added initial support for components in UI when access isn't allowed. Formal styling to come later.


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

Branch: refs/heads/master
Commit: ff98d823e20f5042dfbb05d9f8efda0daf3d3ba4
Parents: a4409d3
Author: Matt Gilman <ma...@gmail.com>
Authored: Fri Apr 29 14:49:13 2016 -0400
Committer: Matt Gilman <ma...@gmail.com>
Committed: Fri Apr 29 14:49:14 2016 -0400

----------------------------------------------------------------------
 .../org/apache/nifi/authorization/Resource.java |   2 +-
 .../nifi-framework/nifi-administration/pom.xml  |  38 -
 .../authorization/AuthorizerFactoryBean.java    | 342 ---------
 .../StandardAuthorizerConfigurationContext.java |  54 --
 ...StandardAuthorizerInitializationContext.java |  41 --
 .../java/org/apache/nifi/user/NiFiUser.java     |  97 ---
 .../org/apache/nifi/user/NiFiUserGroup.java     |   2 +
 .../resources/nifi-administration-context.xml   |   5 -
 .../src/main/xsd/authorizers.xsd                |  49 --
 .../nifi/web/api/dto/AccessPolicyDTO.java       |  62 ++
 .../apache/nifi/web/api/dto/ComponentDTO.java   |  94 +++
 .../apache/nifi/web/api/dto/ConnectionDTO.java  |   2 +-
 .../nifi/web/api/dto/ControllerServiceDTO.java  |   2 +-
 .../apache/nifi/web/api/dto/DimensionsDTO.java  |  61 ++
 .../org/apache/nifi/web/api/dto/FunnelDTO.java  |   2 +-
 .../org/apache/nifi/web/api/dto/LabelDTO.java   |   2 +-
 .../nifi/web/api/dto/NiFiComponentDTO.java      | 106 ---
 .../org/apache/nifi/web/api/dto/PortDTO.java    |   2 +-
 .../nifi/web/api/dto/ProcessGroupDTO.java       |  20 +-
 .../apache/nifi/web/api/dto/ProcessorDTO.java   |   2 +-
 .../nifi/web/api/dto/RemoteProcessGroupDTO.java |   2 +-
 .../nifi/web/api/dto/ReportingTaskDTO.java      |   2 +-
 .../org/apache/nifi/web/api/dto/SnippetDTO.java |  19 +-
 .../web/api/dto/flow/FlowBreadcrumbDTO.java     |  80 +++
 .../apache/nifi/web/api/dto/flow/FlowDTO.java   | 174 +++++
 .../web/api/dto/flow/ProcessGroupFlowDTO.java   | 112 +++
 .../nifi/web/api/entity/ComponentEntity.java    | 119 ++++
 .../nifi/web/api/entity/ConnectionEntity.java   | 107 ++-
 .../nifi/web/api/entity/ConnectionsEntity.java  |  14 +-
 .../web/api/entity/ControllerServiceEntity.java |   2 +-
 .../org/apache/nifi/web/api/entity/Entity.java  |   5 +-
 .../apache/nifi/web/api/entity/FlowEntity.java  |  44 ++
 .../nifi/web/api/entity/FunnelEntity.java       |  12 +-
 .../nifi/web/api/entity/FunnelsEntity.java      |  14 +-
 .../nifi/web/api/entity/InputPortEntity.java    |  41 --
 .../nifi/web/api/entity/InputPortsEntity.java   |  14 +-
 .../apache/nifi/web/api/entity/LabelEntity.java |  29 +-
 .../nifi/web/api/entity/LabelsEntity.java       |  14 +-
 .../nifi/web/api/entity/OutputPortEntity.java   |  41 --
 .../nifi/web/api/entity/OutputPortsEntity.java  |  14 +-
 .../apache/nifi/web/api/entity/PortEntity.java  |  50 ++
 .../nifi/web/api/entity/ProcessGroupEntity.java |  12 +-
 .../web/api/entity/ProcessGroupFlowEntity.java  |  44 ++
 .../web/api/entity/ProcessGroupsEntity.java     |  15 +-
 .../nifi/web/api/entity/ProcessorEntity.java    |  15 +-
 .../nifi/web/api/entity/ProcessorsEntity.java   |  14 +-
 .../api/entity/RemoteProcessGroupEntity.java    |  12 +-
 .../api/entity/RemoteProcessGroupsEntity.java   |  14 +-
 .../src/main/xsd/authorizations.xsd             |   1 -
 .../nifi-framework-authorization/pom.xml        |  59 +-
 .../authorization/AccessDeniedException.java    |  39 ++
 .../authorization/AuthorizerFactoryBean.java    | 341 +++++++++
 .../StandardAuthorizerConfigurationContext.java |  54 ++
 ...StandardAuthorizerInitializationContext.java |  41 ++
 .../authorization/resource/Authorizable.java    | 129 ++++
 .../authorization/resource/ResourceFactory.java |   1 -
 .../authorization/resource/ResourceType.java    |   1 +
 .../nifi/authorization/user/NiFiUser.java       |  97 +++
 .../authorization/user/NiFiUserDetails.java     |  91 +++
 .../nifi/authorization/user/NiFiUserUtils.java  |  59 ++
 .../nifi-framework-authorization-context.xml    |  26 +
 .../src/main/xsd/authorizers.xsd                |  49 ++
 .../cluster/manager/impl/WebClusterManager.java |  42 +-
 .../nifi-framework-core-api/pom.xml             |   4 +
 .../apache/nifi/connectable/Connectable.java    |   3 +-
 .../org/apache/nifi/connectable/Connection.java |   3 +-
 .../apache/nifi/controller/AbstractPort.java    |  48 +-
 .../apache/nifi/controller/ProcessorNode.java   |  14 +-
 .../apache/nifi/controller/StandardFunnel.java  |  49 +-
 .../org/apache/nifi/controller/label/Label.java |   3 +-
 .../org/apache/nifi/groups/ProcessGroup.java    |   3 +-
 .../apache/nifi/groups/RemoteProcessGroup.java  |   3 +-
 .../nifi/connectable/StandardConnection.java    |  48 +-
 .../nifi/controller/StandardProcessorNode.java  |  60 +-
 .../nifi/controller/label/StandardLabel.java    |  23 +-
 .../nifi/fingerprint/FingerprintFactory.java    |   6 +-
 .../nifi/groups/StandardProcessGroup.java       |  42 +-
 .../nifi/remote/StandardRemoteProcessGroup.java |  70 +-
 .../java/org/apache/nifi/util/SnippetUtils.java |  22 +-
 .../controller/StandardFlowServiceTest.java     |   1 -
 .../zookeeper/TestZooKeeperStateProvider.java   |  13 +-
 .../nifi/remote/StandardRemoteGroupPort.java    |   6 +
 .../nifi/audit/ComponentStateAuditor.java       |   4 +-
 .../apache/nifi/audit/ControllerAuditor.java    |   4 +-
 .../nifi/audit/ControllerServiceAuditor.java    |   4 +-
 .../org/apache/nifi/audit/FunnelAuditor.java    |   4 +-
 .../java/org/apache/nifi/audit/PortAuditor.java |   4 +-
 .../apache/nifi/audit/ProcessGroupAuditor.java  |   4 +-
 .../org/apache/nifi/audit/ProcessorAuditor.java |   4 +-
 .../apache/nifi/audit/RelationshipAuditor.java  |   4 +-
 .../nifi/audit/RemoteProcessGroupAuditor.java   |   4 +-
 .../apache/nifi/audit/ReportingTaskAuditor.java |   4 +-
 .../org/apache/nifi/audit/SnippetAuditor.java   |   4 +-
 .../org/apache/nifi/web/NiFiServiceFacade.java  | 107 +--
 .../nifi/web/NiFiWebApiConfiguration.java       |   1 +
 .../nifi/web/StandardNiFiContentAccess.java     |   4 +-
 .../nifi/web/StandardNiFiServiceFacade.java     | 584 +++++++++++-----
 .../StandardNiFiWebConfigurationContext.java    |  18 +-
 .../apache/nifi/web/StandardNiFiWebContext.java |  16 +-
 .../java/org/apache/nifi/web/UpdateResult.java  |  40 ++
 .../org/apache/nifi/web/api/AccessResource.java |   6 +-
 .../nifi/web/api/ApplicationResource.java       |   2 +-
 .../apache/nifi/web/api/ClusterResource.java    | 223 ------
 .../apache/nifi/web/api/ConnectionResource.java |  83 +--
 .../apache/nifi/web/api/ControllerResource.java |   4 +-
 .../nifi/web/api/ControllerServiceResource.java |  50 --
 .../org/apache/nifi/web/api/FlowResource.java   | 257 ++++++-
 .../org/apache/nifi/web/api/FunnelResource.java |  84 +--
 .../apache/nifi/web/api/InputPortResource.java  |  92 ++-
 .../org/apache/nifi/web/api/LabelResource.java  |  84 +--
 .../apache/nifi/web/api/OutputPortResource.java |  92 ++-
 .../nifi/web/api/ProcessGroupResource.java      | 668 ++++++------------
 .../apache/nifi/web/api/ProcessorResource.java  | 102 ++-
 .../web/api/RemoteProcessGroupResource.java     |  88 ++-
 .../apache/nifi/web/api/TemplateResource.java   |   8 -
 .../api/config/AccessDeniedExceptionMapper.java |   7 +-
 .../org/apache/nifi/web/api/dto/DtoFactory.java | 171 ++++-
 .../apache/nifi/web/api/dto/EntityFactory.java  | 155 +++++
 .../nifi/web/controller/ControllerFacade.java   |  17 +-
 .../org/apache/nifi/web/dao/TemplateDAO.java    |   3 +-
 .../web/dao/impl/StandardConnectionDAO.java     |  19 +-
 .../apache/nifi/web/filter/RequestLogger.java   |   4 +-
 .../src/main/resources/nifi-web-api-context.xml |  20 +-
 .../apache/nifi/integration/NiFiWebApiTest.java |  30 +-
 .../accesscontrol/AccessTokenEndpointTest.java  |   4 +-
 .../accesscontrol/AdminAccessControlTest.java   |  22 +-
 .../accesscontrol/DfmAccessControlTest.java     | 144 ++--
 .../ReadOnlyAccessControlTest.java              |  20 +-
 .../nifi-web/nifi-web-content-viewer/pom.xml    |   5 +
 .../nifi/web/ContentViewerController.java       |   2 +-
 .../web/StandardOptimisticLockingManager.java   |   3 +-
 .../nifi-web/nifi-web-security/pom.xml          |   4 +
 .../web/security/NiFiAuthenticationFilter.java  |   2 +-
 .../nifi/web/security/ProxiedEntitiesUtils.java |   2 +-
 .../anonymous/NiFiAnonymousUserFilter.java      |   5 +-
 .../security/jwt/JwtAuthenticationProvider.java |   4 +-
 .../security/node/NodeAuthorizedUserFilter.java |   5 +-
 .../security/otp/OtpAuthenticationProvider.java |   4 +-
 .../nifi/web/security/user/NiFiUserDetails.java |  92 ---
 .../nifi/web/security/user/NiFiUserUtils.java   |  89 ---
 .../x509/X509AuthenticationProvider.java        |  33 +-
 .../resources/nifi-web-security-context.xml     |   3 +-
 .../otp/OtpAuthenticationProviderTest.java      |   2 +-
 .../controllers/nf-ng-breadcrumbs-controller.js |  12 +-
 .../src/main/webapp/js/nf/canvas/nf-actions.js  | 171 ++---
 .../src/main/webapp/js/nf/canvas/nf-birdseye.js |  28 +-
 .../webapp/js/nf/canvas/nf-canvas-header.js     |  20 +-
 .../webapp/js/nf/canvas/nf-canvas-toolbar.js    |  93 +--
 .../webapp/js/nf/canvas/nf-canvas-toolbox.js    |  50 +-
 .../main/webapp/js/nf/canvas/nf-canvas-utils.js | 118 ++--
 .../src/main/webapp/js/nf/canvas/nf-canvas.js   |  29 +-
 .../main/webapp/js/nf/canvas/nf-connectable.js  |  10 +-
 .../js/nf/canvas/nf-connection-configuration.js |  66 +-
 .../main/webapp/js/nf/canvas/nf-connection.js   | 664 +++++++++---------
 .../main/webapp/js/nf/canvas/nf-context-menu.js | 115 ++-
 .../main/webapp/js/nf/canvas/nf-draggable.js    |  62 +-
 .../src/main/webapp/js/nf/canvas/nf-funnel.js   |  62 +-
 .../src/main/webapp/js/nf/canvas/nf-go-to.js    |  24 +-
 .../js/nf/canvas/nf-label-configuration.js      |   6 +-
 .../src/main/webapp/js/nf/canvas/nf-label.js    | 270 +++-----
 .../js/nf/canvas/nf-port-configuration.js       |  17 +-
 .../main/webapp/js/nf/canvas/nf-port-details.js |   2 +-
 .../src/main/webapp/js/nf/canvas/nf-port.js     | 228 +++---
 .../nf/canvas/nf-process-group-configuration.js |   8 +-
 .../js/nf/canvas/nf-process-group-details.js    |   2 +-
 .../webapp/js/nf/canvas/nf-process-group.js     | 691 +++++++++----------
 .../js/nf/canvas/nf-processor-configuration.js  |  16 +-
 .../main/webapp/js/nf/canvas/nf-processor.js    | 270 ++++----
 .../webapp/js/nf/canvas/nf-queue-listing.js     |   2 +-
 .../nf-remote-process-group-configuration.js    |   8 +-
 .../canvas/nf-remote-process-group-details.js   |   2 +-
 .../nf/canvas/nf-remote-process-group-ports.js  |  10 +-
 .../js/nf/canvas/nf-remote-process-group.js     | 689 +++++++++---------
 .../src/main/webapp/js/nf/canvas/nf-snippet.js  |  16 +-
 .../main/webapp/js/nf/nf-connection-details.js  |  16 +-
 .../main/webapp/js/nf/nf-processor-details.js   |   4 +-
 .../views/nf-ng-breadcrumbs-directive-view.html |   2 +-
 177 files changed, 6082 insertions(+), 4700 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java
----------------------------------------------------------------------
diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java b/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java
index 7756bda..661b326 100644
--- a/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java
+++ b/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java
@@ -29,7 +29,7 @@ public interface Resource {
     String getIdentifier();
 
     /**
-     * The name of this resource.
+     * The name of this resource. May be null.
      *
      * @return name of this resource
      */

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/pom.xml
index c9a9c0e..2aac209 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/pom.xml
@@ -21,40 +21,6 @@
         <version>1.0.0-SNAPSHOT</version>
     </parent>
     <artifactId>nifi-administration</artifactId>
-    <build>
-        <resources>
-            <resource>
-                <directory>src/main/resources</directory>
-            </resource>
-            <resource>
-                <directory>src/main/xsd</directory>
-            </resource>
-        </resources>
-        <plugins>
-            <plugin>
-                <groupId>org.codehaus.mojo</groupId>
-                <artifactId>jaxb2-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>current</id>
-                        <goals>
-                            <goal>xjc</goal>
-                        </goals>
-                        <configuration>
-                            <packageName>org.apache.nifi.authorization.generated</packageName>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-checkstyle-plugin</artifactId>
-                <configuration>
-                    <excludes>**/authorization/generated/*.java,</excludes>
-                </configuration>
-            </plugin>            
-        </plugins>
-    </build>
     <dependencies>
         <dependency>
             <groupId>org.apache.nifi</groupId>
@@ -116,9 +82,5 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-collections4</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.apache.nifi</groupId>
-            <artifactId>nifi-expression-language</artifactId>
-        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
deleted file mode 100644
index 3d3e826..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * 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.authorization;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.authorization.annotation.AuthorizerContext;
-import org.apache.nifi.authorization.exception.AuthorizationAccessException;
-import org.apache.nifi.authorization.exception.AuthorizerCreationException;
-import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
-import org.apache.nifi.authorization.generated.Authorizers;
-import org.apache.nifi.authorization.generated.Property;
-import org.apache.nifi.nar.ExtensionManager;
-import org.apache.nifi.nar.NarCloseable;
-import org.apache.nifi.util.NiFiProperties;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.FactoryBean;
-import org.xml.sax.SAXException;
-
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBElement;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import java.io.File;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Factory bean for loading the configured authorizer.
- */
-public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, AuthorizerLookup {
-
-    private static final Logger logger = LoggerFactory.getLogger(AuthorizerFactoryBean.class);
-    private static final String AUTHORIZERS_XSD = "/authorizers.xsd";
-    private static final String JAXB_GENERATED_PATH = "org.apache.nifi.authorization.generated";
-    private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
-
-    /**
-     * Load the JAXBContext.
-     */
-    private static JAXBContext initializeJaxbContext() {
-        try {
-            return JAXBContext.newInstance(JAXB_GENERATED_PATH, AuthorizerFactoryBean.class.getClassLoader());
-        } catch (JAXBException e) {
-            throw new RuntimeException("Unable to create JAXBContext.");
-        }
-    }
-
-    private Authorizer authorizer;
-    private NiFiProperties properties;
-    private final Map<String, Authorizer> authorizers = new HashMap<>();
-
-    @Override
-    public Authorizer getAuthorizer(String identifier) {
-        return authorizers.get(identifier);
-    }
-
-    @Override
-    public Object getObject() throws Exception {
-        if (authorizer == null) {
-            // look up the authorizer to use
-            final String authorizerIdentifier = properties.getProperty(NiFiProperties.SECURITY_USER_AUTHORIZER);
-
-            // ensure the authorizer class name was specified
-            if (StringUtils.isBlank(authorizerIdentifier)) {
-                // if configured for ssl, the authorizer must be specified
-                if (properties.getSslPort() != null) {
-                    throw new Exception("When running securely, the authorizer identifier must be specified in the nifi properties file.");
-                }
-
-                // use a default authorizer... only allowable when running not securely
-                authorizer = createDefaultAuthorizer();
-            } else {
-                final Authorizers authorizerConfiguration = loadAuthorizersConfiguration();
-
-                // create each authorizer
-                for (final org.apache.nifi.authorization.generated.Authorizer authorizer : authorizerConfiguration.getAuthorizer()) {
-                    authorizers.put(authorizer.getIdentifier(), createAuthorizer(authorizer.getIdentifier(), authorizer.getClazz()));
-                }
-
-                // configure each authorizer
-                for (final org.apache.nifi.authorization.generated.Authorizer provider : authorizerConfiguration.getAuthorizer()) {
-                    final Authorizer instance = authorizers.get(provider.getIdentifier());
-                    instance.onConfigured(loadAuthorizerConfiguration(provider));
-                }
-
-                // get the authorizer instance
-                authorizer = getAuthorizer(authorizerIdentifier);
-
-                // ensure it was found
-                if (authorizer == null) {
-                    throw new Exception(String.format("The specified authorizer '%s' could not be found.", authorizerIdentifier));
-                }
-            }
-        }
-
-        return authorizer;
-    }
-
-    private Authorizers loadAuthorizersConfiguration() throws Exception {
-        final File authorizersConfigurationFile = properties.getAuthorizerConfiguraitonFile();
-
-        // load the authorizers from the specified file
-        if (authorizersConfigurationFile.exists()) {
-            try {
-                // find the schema
-                final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
-                final Schema schema = schemaFactory.newSchema(Authorizers.class.getResource(AUTHORIZERS_XSD));
-
-                // attempt to unmarshal
-                final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
-                unmarshaller.setSchema(schema);
-                final JAXBElement<Authorizers> element = unmarshaller.unmarshal(new StreamSource(authorizersConfigurationFile), Authorizers.class);
-                return element.getValue();
-            } catch (SAXException | JAXBException e) {
-                throw new Exception("Unable to load the authorizer configuration file at: " + authorizersConfigurationFile.getAbsolutePath(), e);
-            }
-        } else {
-            throw new Exception("Unable to find the authorizer configuration file at " + authorizersConfigurationFile.getAbsolutePath());
-        }
-    }
-
-    private Authorizer createAuthorizer(final String identifier, final String authorizerClassName) throws Exception {
-        // get the classloader for the specified authorizer
-        final ClassLoader authorizerClassLoader = ExtensionManager.getClassLoader(authorizerClassName);
-        if (authorizerClassLoader == null) {
-            throw new Exception(String.format("The specified authorizer class '%s' is not known to this nifi.", authorizerClassName));
-        }
-
-        // get the current context classloader
-        final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
-
-        final Authorizer instance;
-        try {
-            // set the appropriate class loader
-            Thread.currentThread().setContextClassLoader(authorizerClassLoader);
-
-            // attempt to load the class
-            Class<?> rawAuthorizerClass = Class.forName(authorizerClassName, true, authorizerClassLoader);
-            Class<? extends Authorizer> authorizerClass = rawAuthorizerClass.asSubclass(Authorizer.class);
-
-            // otherwise create a new instance
-            Constructor constructor = authorizerClass.getConstructor();
-            instance = (Authorizer) constructor.newInstance();
-
-            // method injection
-            performMethodInjection(instance, authorizerClass);
-
-            // field injection
-            performFieldInjection(instance, authorizerClass);
-
-            // call post construction lifecycle event
-            instance.initialize(new StandardAuthorizerInitializationContext(identifier, this));
-        } finally {
-            if (currentClassLoader != null) {
-                Thread.currentThread().setContextClassLoader(currentClassLoader);
-            }
-        }
-
-        return withNarLoader(instance);
-    }
-
-    private AuthorizerConfigurationContext loadAuthorizerConfiguration(final org.apache.nifi.authorization.generated.Authorizer authorizer) {
-        final Map<String, String> authorizerProperties = new HashMap<>();
-
-        for (final Property property : authorizer.getProperty()) {
-            authorizerProperties.put(property.getName(), property.getValue());
-        }
-
-        return new StandardAuthorizerConfigurationContext(authorizer.getIdentifier(), authorizerProperties);
-    }
-
-    private void performMethodInjection(final Authorizer instance, final Class authorizerClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
-        for (final Method method : authorizerClass.getMethods()) {
-            if (method.isAnnotationPresent(AuthorizerContext.class)) {
-                // make the method accessible
-                final boolean isAccessible = method.isAccessible();
-                method.setAccessible(true);
-
-                try {
-                    final Class<?>[] argumentTypes = method.getParameterTypes();
-
-                    // look for setters (single argument)
-                    if (argumentTypes.length == 1) {
-                        final Class<?> argumentType = argumentTypes[0];
-
-                        // look for well known types
-                        if (NiFiProperties.class.isAssignableFrom(argumentType)) {
-                            // nifi properties injection
-                            method.invoke(instance, properties);
-                        }
-                    }
-                } finally {
-                    method.setAccessible(isAccessible);
-                }
-            }
-        }
-
-        final Class parentClass = authorizerClass.getSuperclass();
-        if (parentClass != null && Authorizer.class.isAssignableFrom(parentClass)) {
-            performMethodInjection(instance, parentClass);
-        }
-    }
-
-    private void performFieldInjection(final Authorizer instance, final Class authorizerClass) throws IllegalArgumentException, IllegalAccessException {
-        for (final Field field : authorizerClass.getDeclaredFields()) {
-            if (field.isAnnotationPresent(AuthorizerContext.class)) {
-                // make the method accessible
-                final boolean isAccessible = field.isAccessible();
-                field.setAccessible(true);
-
-                try {
-                    // get the type
-                    final Class<?> fieldType = field.getType();
-
-                    // only consider this field if it isn't set yet
-                    if (field.get(instance) == null) {
-                        // look for well known types
-                        if (NiFiProperties.class.isAssignableFrom(fieldType)) {
-                            // nifi properties injection
-                            field.set(instance, properties);
-                        }
-                    }
-
-                } finally {
-                    field.setAccessible(isAccessible);
-                }
-            }
-        }
-
-        final Class parentClass = authorizerClass.getSuperclass();
-        if (parentClass != null && Authorizer.class.isAssignableFrom(parentClass)) {
-            performFieldInjection(instance, parentClass);
-        }
-    }
-
-    /**
-     * @return a default Authorizer to use when running unsecurely with no authorizer configured
-     */
-    private Authorizer createDefaultAuthorizer() {
-        return new Authorizer() {
-            @Override
-            public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
-                return AuthorizationResult.approved();
-            }
-
-            @Override
-            public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
-            }
-
-            @Override
-            public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
-            }
-
-            @Override
-            public void preDestruction() throws AuthorizerDestructionException {
-            }
-        };
-    }
-
-    /**
-     * Decorates the base authorizer to ensure the nar context classloader is used when invoking the underlying methods.
-     *
-     * @param baseAuthorizer base authorizer
-     * @return authorizer
-     */
-    public Authorizer withNarLoader(final Authorizer baseAuthorizer) {
-        return new Authorizer() {
-            @Override
-            public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException {
-                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
-                    return baseAuthorizer.authorize(request);
-                }
-            }
-
-            @Override
-            public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException {
-                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
-                    baseAuthorizer.initialize(initializationContext);
-                }
-            }
-
-            @Override
-            public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException {
-                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
-                    baseAuthorizer.onConfigured(configurationContext);
-                }
-            }
-
-            @Override
-            public void preDestruction() throws AuthorizerDestructionException {
-                try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
-                    baseAuthorizer.preDestruction();
-                }
-            }
-        };
-    }
-
-    @Override
-    public Class getObjectType() {
-        return Authorizer.class;
-    }
-
-    @Override
-    public boolean isSingleton() {
-        return true;
-    }
-
-    @Override
-    public void destroy() throws Exception {
-        if (authorizer != null) {
-            authorizer.preDestruction();
-        }
-    }
-
-    public void setProperties(NiFiProperties properties) {
-        this.properties = properties;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java
deleted file mode 100644
index 3010c92..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.authorization;
-
-import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
-import org.apache.nifi.components.PropertyValue;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- *
- */
-public class StandardAuthorizerConfigurationContext implements AuthorizerConfigurationContext {
-
-    private final String identifier;
-    private final Map<String, String> properties;
-
-    public StandardAuthorizerConfigurationContext(String identifier, Map<String, String> properties) {
-        this.identifier = identifier;
-        this.properties = Collections.unmodifiableMap(new HashMap<String, String>(properties));
-    }
-
-    @Override
-    public String getIdentifier() {
-        return identifier;
-    }
-
-    @Override
-    public Map<String, String> getProperties() {
-        return properties;
-    }
-
-    @Override
-    public PropertyValue getProperty(String property) {
-        return new StandardPropertyValue(properties.get(property), null);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java
deleted file mode 100644
index 344f49c..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.authorization;
-
-/**
- *
- */
-public class StandardAuthorizerInitializationContext implements AuthorizerInitializationContext {
-
-    private final String identifier;
-    private final AuthorizerLookup authorizerLookup;
-
-    public StandardAuthorizerInitializationContext(String identifier, AuthorizerLookup authorizerLookup) {
-        this.identifier = identifier;
-        this.authorizerLookup = authorizerLookup;
-    }
-
-    @Override
-    public String getIdentifier() {
-        return identifier;
-    }
-
-    public AuthorizerLookup getAuthorizerLookup() {
-        return authorizerLookup;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java
deleted file mode 100644
index 3a919ba..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUser.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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.user;
-
-import java.io.Serializable;
-import java.util.Objects;
-
-/**
- * An NiFiUser.
- */
-public class NiFiUser implements Serializable {
-
-    public static final NiFiUser ANONYMOUS = new NiFiUser("anonymous");
-
-    private String identity;
-    private String userName;
-
-    private NiFiUser chain;
-
-    public NiFiUser(String identity) {
-        this(identity, identity, null);
-    }
-
-    public NiFiUser(String identity, String userName) {
-        this(identity, userName, null);
-    }
-
-    public NiFiUser(String identity, NiFiUser chain) {
-        this(identity, identity, chain);
-    }
-
-    public NiFiUser(String identity, String userName, NiFiUser chain) {
-        this.identity = identity;
-        this.userName = userName;
-        this.chain = chain;
-    }
-
-    /* getters / setters */
-
-    public String getIdentity() {
-        return identity;
-    }
-
-    public String getUserName() {
-        return userName;
-    }
-
-    public NiFiUser getChain() {
-        return chain;
-    }
-
-    public boolean isAnonymous() {
-        return this == ANONYMOUS;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (getClass() != obj.getClass()) {
-            return false;
-        }
-        final NiFiUser other = (NiFiUser) obj;
-        if (!Objects.equals(this.identity, other.identity)) {
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 7;
-        hash = 53 * hash + Objects.hashCode(this.identity);
-        return hash;
-    }
-
-    @Override
-    public String toString() {
-        return String.format("identity[%s], userName[%s]", getIdentity(), getUserName(), ", ");
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
index 7586fd1..e4b7130 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/user/NiFiUserGroup.java
@@ -16,6 +16,8 @@
  */
 package org.apache.nifi.user;
 
+import org.apache.nifi.authorization.user.NiFiUser;
+
 import java.util.Set;
 
 /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
index deec073..e717686 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml
@@ -18,11 +18,6 @@
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
 
-    <!-- user/entity authorizer -->
-    <bean id="authorizer" class="org.apache.nifi.authorization.AuthorizerFactoryBean">
-        <property name="properties" ref="nifiProperties"/>
-    </bean>
-
     <!-- initialize the user key data source -->
     <bean id="keyDataSource" class="org.apache.nifi.admin.KeyDataSourceFactoryBean" destroy-method="shutdown">
         <property name="properties" ref="nifiProperties"/>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd
deleted file mode 100644
index 4b68b00..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0"?>
-<!--
-  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.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
-    <!-- role -->
-    <xs:complexType name="Authorizer">
-        <xs:sequence>
-            <xs:element name="identifier" type="NonEmptyStringType"/>
-            <xs:element name="class" type="NonEmptyStringType"/>
-            <xs:element name="property" type="Property" minOccurs="0" maxOccurs="unbounded" />
-        </xs:sequence>
-    </xs:complexType>
-
-    <!-- Name/Value properties-->
-    <xs:complexType name="Property">
-        <xs:simpleContent>
-            <xs:extension base="xs:string">
-                <xs:attribute name="name" type="NonEmptyStringType"></xs:attribute>
-            </xs:extension>
-        </xs:simpleContent>
-    </xs:complexType>
-
-    <xs:simpleType name="NonEmptyStringType">
-        <xs:restriction base="xs:string">
-            <xs:minLength value="1"/>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <!-- users -->
-    <xs:element name="authorizers">
-        <xs:complexType>
-            <xs:sequence>
-                <xs:element name="authorizer" type="Authorizer" minOccurs="0" maxOccurs="unbounded"/>
-            </xs:sequence>
-        </xs:complexType>
-    </xs:element>
-</xs:schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java
new file mode 100644
index 0000000..1564362
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/AccessPolicyDTO.java
@@ -0,0 +1,62 @@
+/*
+ * 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.web.api.dto;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Details for the access configuration.
+ */
+@XmlType(name = "accessPolicy")
+public class AccessPolicyDTO {
+
+    private Boolean canRead;
+    private Boolean canWrite;
+
+    /**
+     * @return Indicates whether the user can read a given resource.
+     */
+    @ApiModelProperty(
+            value = "Indicates whether the user can read a given resource.",
+            readOnly = true
+    )
+    public Boolean getCanRead() {
+        return canRead;
+    }
+
+    public void setCanRead(Boolean canRead) {
+        this.canRead = canRead;
+    }
+
+    /**
+     * @return Indicates whether the user can write a given resource.
+     */
+    @ApiModelProperty(
+            value = "Indicates whether the user can write a given resource.",
+            readOnly = true
+    )
+    public Boolean getCanWrite() {
+        return canWrite;
+    }
+
+    public void setCanWrite(Boolean canWrite) {
+        this.canWrite = canWrite;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java
new file mode 100644
index 0000000..ca5e06f
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ComponentDTO.java
@@ -0,0 +1,94 @@
+/*
+ * 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.web.api.dto;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Base class for all nifi components.
+ */
+@XmlType(name = "component")
+public class ComponentDTO {
+
+    private String id;
+    private String uri;
+    private String parentGroupId;
+    private PositionDTO position;
+
+    /**
+     * The id for this component.
+     *
+     * @return The id
+     */
+    @ApiModelProperty(
+            value = "The id of the component."
+    )
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(final String id) {
+        this.id = id;
+    }
+
+    /**
+     * @return id for the parent group of this component if applicable, null otherwise
+     */
+    @ApiModelProperty(
+            value = "The id of parent process group of this component if applicable."
+    )
+    public String getParentGroupId() {
+        return parentGroupId;
+    }
+
+    public void setParentGroupId(String parentGroupId) {
+        this.parentGroupId = parentGroupId;
+    }
+
+    /**
+     * The uri for linking to this component in this NiFi.
+     *
+     * @return The uri
+     */
+    @ApiModelProperty(
+            value = "The URI for futures requests to the component."
+    )
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    /**
+     * The position of this component in the UI if applicable, null otherwise.
+     *
+     * @return The position
+     */
+    @ApiModelProperty(
+        value = "The position of this component in the UI if applicable."
+    )
+    public PositionDTO getPosition() {
+        return position;
+    }
+
+    public void setPosition(final PositionDTO position) {
+        this.position = position;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java
index 96da9e3..e4ea0cc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ConnectionDTO.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlType;
  * A connection between two connectable components.
  */
 @XmlType(name = "connection")
-public class ConnectionDTO extends NiFiComponentDTO {
+public class ConnectionDTO extends ComponentDTO {
 
     private ConnectableDTO source;
     private ConnectableDTO destination;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
index 5d51698..f40e181 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ControllerServiceDTO.java
@@ -26,7 +26,7 @@ import javax.xml.bind.annotation.XmlType;
  * A Controller Service that can be shared by other components
  */
 @XmlType(name = "controllerService")
-public class ControllerServiceDTO extends NiFiComponentDTO {
+public class ControllerServiceDTO extends ComponentDTO {
 
     private String name;
     private String type;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java
new file mode 100644
index 0000000..58df0c0
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/DimensionsDTO.java
@@ -0,0 +1,61 @@
+/*
+ * 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.web.api.dto;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * A position on the canvas.
+ */
+@XmlType(name = "dimensions")
+public class DimensionsDTO {
+
+    private Double width;
+    private Double height;
+
+    /* getters / setters */
+
+    /**
+     * @return height of the label in pixels when at a 1:1 scale
+     */
+    @ApiModelProperty(
+        value = "The height of the label in pixels when at a 1:1 scale."
+    )
+    public Double getHeight() {
+        return height;
+    }
+
+    public void setHeight(Double height) {
+        this.height = height;
+    }
+
+    /**
+     * @return width of the label in pixels when at a 1:1 scale
+     */
+    @ApiModelProperty(
+        value = "The width of the label in pixels when at a 1:1 scale."
+    )
+    public Double getWidth() {
+        return width;
+    }
+
+    public void setWidth(Double width) {
+        this.width = width;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FunnelDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FunnelDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FunnelDTO.java
index 1240501..4687737 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FunnelDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/FunnelDTO.java
@@ -22,7 +22,7 @@ import javax.xml.bind.annotation.XmlType;
  * Details of a funnel.
  */
 @XmlType(name = "funnel")
-public class FunnelDTO extends NiFiComponentDTO {
+public class FunnelDTO extends ComponentDTO {
 
     public FunnelDTO() {
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java
index e9016db..063ff65 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/LabelDTO.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlType;
  * Details of a label.
  */
 @XmlType(name = "label")
-public class LabelDTO extends NiFiComponentDTO {
+public class LabelDTO extends ComponentDTO {
 
     private String label;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NiFiComponentDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NiFiComponentDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NiFiComponentDTO.java
deleted file mode 100644
index e89fb5d..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/NiFiComponentDTO.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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.web.api.dto;
-
-import com.wordnik.swagger.annotations.ApiModelProperty;
-import javax.xml.bind.annotation.XmlType;
-
-/**
- * Base class for all nifi components.
- */
-@XmlType(name = "nifiComponent")
-public class NiFiComponentDTO {
-
-    private String id;
-    private String uri;
-    private PositionDTO position;
-    private String parentGroupId;
-
-    public NiFiComponentDTO() {
-    }
-
-    public NiFiComponentDTO(final String id) {
-        this.id = id;
-    }
-
-    public NiFiComponentDTO(final String id, final double x, final double y) {
-        this.id = id;
-        this.position = new PositionDTO(x, y);
-    }
-
-    /**
-     * The id for this component.
-     *
-     * @return The id
-     */
-    @ApiModelProperty(
-            value = "The id of the component."
-    )
-    public String getId() {
-        return this.id;
-    }
-
-    public void setId(final String id) {
-        this.id = id;
-    }
-
-    /**
-     * @return id for the parent group of this component if applicable, null otherwise
-     */
-    @ApiModelProperty(
-            value = "The id of parent process group of this component if applicable."
-    )
-    public String getParentGroupId() {
-        return parentGroupId;
-    }
-
-    public void setParentGroupId(String parentGroupId) {
-        this.parentGroupId = parentGroupId;
-    }
-
-    /**
-     * The uri for linking to this component in this NiFi.
-     *
-     * @return The uri
-     */
-    @ApiModelProperty(
-            value = "The URI for futures requests to the component."
-    )
-    public String getUri() {
-        return uri;
-    }
-
-    public void setUri(String uri) {
-        this.uri = uri;
-    }
-
-    public void setPosition(final PositionDTO position) {
-        this.position = position;
-    }
-
-    /**
-     * The position of this component in the UI if applicable, null otherwise.
-     *
-     * @return The position
-     */
-    @ApiModelProperty(
-            value = "The position of this component in the UI if applicable."
-    )
-    public PositionDTO getPosition() {
-        return position;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
index 489ed0c..f8e4081 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/PortDTO.java
@@ -25,7 +25,7 @@ import javax.xml.bind.annotation.XmlType;
  * The details for a port within this NiFi flow.
  */
 @XmlType(name = "port")
-public class PortDTO extends NiFiComponentDTO {
+public class PortDTO extends ComponentDTO {
 
     private String name;
     private String comments;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java
index 93c4ea9..224db57 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessGroupDTO.java
@@ -23,14 +23,12 @@ import javax.xml.bind.annotation.XmlType;
  * The details for a process group within this NiFi flow.
  */
 @XmlType(name = "processGroup")
-public class ProcessGroupDTO extends NiFiComponentDTO {
+public class ProcessGroupDTO extends ComponentDTO {
 
     private String name;
     private String comments;
     private Boolean running;
 
-    private ProcessGroupDTO parent;
-
     private Integer runningCount;
     private Integer stoppedCount;
     private Integer invalidCount;
@@ -64,22 +62,6 @@ public class ProcessGroupDTO extends NiFiComponentDTO {
     }
 
     /**
-     * This Process Group's parent
-     *
-     * @return This Process Group's parent
-     */
-    @ApiModelProperty(
-            value = "The part of the process group."
-    )
-    public ProcessGroupDTO getParent() {
-        return parent;
-    }
-
-    public void setParent(ProcessGroupDTO parent) {
-        this.parent = parent;
-    }
-
-    /**
      * @return comments for this process group
      */
     @ApiModelProperty(

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java
index b0b9daa..dbd06a3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ProcessorDTO.java
@@ -26,7 +26,7 @@ import javax.xml.bind.annotation.XmlType;
  * Details for a processor within this NiFi.
  */
 @XmlType(name = "processor")
-public class ProcessorDTO extends NiFiComponentDTO {
+public class ProcessorDTO extends ComponentDTO {
 
     private String name;
     private String type;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java
index 2e30001..b303d4d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/RemoteProcessGroupDTO.java
@@ -27,7 +27,7 @@ import org.apache.nifi.web.api.dto.util.DateTimeAdapter;
  * Details of a remote process group in this NiFi.
  */
 @XmlType(name = "remoteProcessGroup")
-public class RemoteProcessGroupDTO extends NiFiComponentDTO {
+public class RemoteProcessGroupDTO extends ComponentDTO {
 
     private String targetUri;
     private Boolean targetSecure;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java
index 182535d..5972ac7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/ReportingTaskDTO.java
@@ -26,7 +26,7 @@ import javax.xml.bind.annotation.XmlType;
  * Component that is capable of reporting internal NiFi state to an external service
  */
 @XmlType(name = "reportingTask")
-public class ReportingTaskDTO extends NiFiComponentDTO {
+public class ReportingTaskDTO extends ComponentDTO {
 
     private String name;
     private String type;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java
index 431df17..bf5d319 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/SnippetDTO.java
@@ -17,9 +17,10 @@
 package org.apache.nifi.web.api.dto;
 
 import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
 import java.util.HashSet;
 import java.util.Set;
-import javax.xml.bind.annotation.XmlType;
 
 /**
  * The contents of a snippet of a flow.
@@ -42,8 +43,6 @@ public class SnippetDTO {
     private Set<String> labels = new HashSet<>();
     private Set<String> funnels = new HashSet<>();
 
-    private FlowSnippetDTO contents;
-
     /**
      * @return id of this snippet
      */
@@ -230,18 +229,4 @@ public class SnippetDTO {
         this.remoteProcessGroups = remoteProcessGroups;
     }
 
-    /**
-     * @return the contents of the configuration for this snippet
-     */
-    @ApiModelProperty(
-            value = "The contents of the configuration for the snippet."
-    )
-    public FlowSnippetDTO getContents() {
-        return contents;
-    }
-
-    public void setContents(FlowSnippetDTO contents) {
-        this.contents = contents;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java
new file mode 100644
index 0000000..afdfb64
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowBreadcrumbDTO.java
@@ -0,0 +1,80 @@
+/*
+ * 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.web.api.dto.flow;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Breadcrumb for the flow.
+ */
+@XmlType(name = "flowBreadcrumb")
+public class FlowBreadcrumbDTO {
+
+    private String id;
+    private String name;
+    private FlowBreadcrumbDTO parentBreadcrumb;
+
+    /**
+     * The id for this group.
+     *
+     * @return The id
+     */
+    @ApiModelProperty(
+        value = "The id of the group."
+    )
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(final String id) {
+        this.id = id;
+    }
+
+    /**
+     * The name for this group.
+     *
+     * @return The name
+     */
+    @ApiModelProperty(
+        value = "The id of the group."
+    )
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * The parent breadcrumb for this breadcrumb.
+     *
+     * @return The parent breadcrumb for this breadcrumb
+     */
+    @ApiModelProperty(
+        value = "The parent breadcrumb for this breadcrumb."
+    )
+    public FlowBreadcrumbDTO getParentBreadcrumb() {
+        return parentBreadcrumb;
+    }
+
+    public void setParentBreadcrumb(FlowBreadcrumbDTO parentBreadcrumb) {
+        this.parentBreadcrumb = parentBreadcrumb;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java
new file mode 100644
index 0000000..a3a3ae7
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/FlowDTO.java
@@ -0,0 +1,174 @@
+/*
+ * 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.web.api.dto.flow;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.entity.ConnectionEntity;
+import org.apache.nifi.web.api.entity.ControllerServiceEntity;
+import org.apache.nifi.web.api.entity.FunnelEntity;
+import org.apache.nifi.web.api.entity.LabelEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupEntity;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
+
+import javax.xml.bind.annotation.XmlType;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * The structure of the flow.
+ */
+@XmlType(name = "flow")
+public class FlowDTO {
+
+    private Set<ProcessGroupEntity> processGroups = new LinkedHashSet<>();
+    private Set<RemoteProcessGroupEntity> remoteProcessGroups = new LinkedHashSet<>();
+    private Set<ProcessorEntity> processors = new LinkedHashSet<>();
+    private Set<PortEntity> inputPorts = new LinkedHashSet<>();
+    private Set<PortEntity> outputPorts = new LinkedHashSet<>();
+    private Set<ConnectionEntity> connections = new LinkedHashSet<>();
+    private Set<LabelEntity> labels = new LinkedHashSet<>();
+    private Set<FunnelEntity> funnels = new LinkedHashSet<>();
+    private Set<ControllerServiceEntity> controllerServices = new LinkedHashSet<>();
+
+    /**
+     * @return connections in this flow
+     */
+    @ApiModelProperty(
+            value = "The connections in this flow."
+    )
+    public Set<ConnectionEntity> getConnections() {
+        return connections;
+    }
+
+    public void setConnections(Set<ConnectionEntity> connections) {
+        this.connections = connections;
+    }
+
+    /**
+     * @return input ports in this flow
+     */
+    @ApiModelProperty(
+            value = "The input ports in this flow."
+    )
+    public Set<PortEntity> getInputPorts() {
+        return inputPorts;
+    }
+
+    public void setInputPorts(Set<PortEntity> inputPorts) {
+        this.inputPorts = inputPorts;
+    }
+
+    /**
+     * @return labels in this flow
+     */
+    @ApiModelProperty(
+            value = "The labels in this flow."
+    )
+    public Set<LabelEntity> getLabels() {
+        return labels;
+    }
+
+    public void setLabels(Set<LabelEntity> labels) {
+        this.labels = labels;
+    }
+
+    /**
+     * @return funnels in this flow
+     */
+    @ApiModelProperty(
+            value = "The funnels in this flow."
+    )
+    public Set<FunnelEntity> getFunnels() {
+        return funnels;
+    }
+
+    public void setFunnels(Set<FunnelEntity> funnels) {
+        this.funnels = funnels;
+    }
+
+    /**
+     * @return output ports in this flow
+     */
+    @ApiModelProperty(
+            value = "The output ports in this flow."
+    )
+    public Set<PortEntity> getOutputPorts() {
+        return outputPorts;
+    }
+
+    public void setOutputPorts(Set<PortEntity> outputPorts) {
+        this.outputPorts = outputPorts;
+    }
+
+    /**
+     * @return process groups in this flow
+     */
+    @ApiModelProperty(
+            value = "The process groups in this flow."
+    )
+    public Set<ProcessGroupEntity> getProcessGroups() {
+        return processGroups;
+    }
+
+    public void setProcessGroups(Set<ProcessGroupEntity> processGroups) {
+        this.processGroups = processGroups;
+    }
+
+    /**
+     * @return processors in this flow
+     */
+    @ApiModelProperty(
+            value = "The processors in this flow."
+    )
+    public Set<ProcessorEntity> getProcessors() {
+        return processors;
+    }
+
+    public void setProcessors(Set<ProcessorEntity> processors) {
+        this.processors = processors;
+    }
+
+    /**
+     * @return remote process groups in this flow
+     */
+    @ApiModelProperty(
+            value = "The remote process groups in this flow."
+    )
+    public Set<RemoteProcessGroupEntity> getRemoteProcessGroups() {
+        return remoteProcessGroups;
+    }
+
+    public void setRemoteProcessGroups(Set<RemoteProcessGroupEntity> remoteProcessGroups) {
+        this.remoteProcessGroups = remoteProcessGroups;
+    }
+
+    /**
+     * @return the Controller Services in this flow
+     */
+    @ApiModelProperty(
+            value = "The controller services in this flow."
+    )
+    public Set<ControllerServiceEntity> getControllerServices() {
+        return controllerServices;
+    }
+
+    public void setControllerServices(Set<ControllerServiceEntity> controllerServices) {
+        this.controllerServices = controllerServices;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java
new file mode 100644
index 0000000..b651efc
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/flow/ProcessGroupFlowDTO.java
@@ -0,0 +1,112 @@
+/*
+ * 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.web.api.dto.flow;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * The NiFi flow starting at a given Process Group.
+ */
+@XmlType(name = "processGroupflow")
+public class ProcessGroupFlowDTO {
+
+    private String id;
+    private String uri;
+    private String parentGroupId;
+    private FlowBreadcrumbDTO breadcrumb;
+    private FlowDTO flow;
+
+    /**
+     * @return contents of this process group. This field will be populated if the request is marked verbose
+     */
+    @ApiModelProperty(
+        value = "The flow structure starting at this Process Group."
+    )
+    public FlowDTO getFlow() {
+        return flow;
+    }
+
+    public void setFlow(FlowDTO flow) {
+        this.flow = flow;
+    }
+
+    /**
+     * The id for this component.
+     *
+     * @return The id
+     */
+    @ApiModelProperty(
+        value = "The id of the component."
+    )
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(final String id) {
+        this.id = id;
+    }
+
+    /**
+     * The breadcrumb for this ProcessGroup flow.
+     *
+     * @return The breadcrumb for this ProcessGroup flow
+     */
+    @ApiModelProperty(
+        value = "The breadcrumb of the process group."
+    )
+    public FlowBreadcrumbDTO getBreadcrumb() {
+        return breadcrumb;
+    }
+
+    public void setBreadcrumb(FlowBreadcrumbDTO breadcrumb) {
+        this.breadcrumb = breadcrumb;
+    }
+
+    /**
+     * @return id for the parent group of this component if applicable, null otherwise
+     */
+    @ApiModelProperty(
+        value = "The id of parent process group of this component if applicable."
+    )
+    public String getParentGroupId() {
+        return parentGroupId;
+    }
+
+    public void setParentGroupId(String parentGroupId) {
+        this.parentGroupId = parentGroupId;
+    }
+
+    /**
+     * The uri for linking to this component in this NiFi.
+     *
+     * @return The uri
+     */
+    @ApiModelProperty(
+        value = "The URI for futures requests to the component."
+    )
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java
new file mode 100644
index 0000000..e0c85fa
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ComponentEntity.java
@@ -0,0 +1,119 @@
+/*
+ * 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.web.api.entity;
+
+import com.wordnik.swagger.annotations.ApiModelProperty;
+import org.apache.nifi.web.api.dto.AccessPolicyDTO;
+import org.apache.nifi.web.api.dto.PositionDTO;
+import org.apache.nifi.web.api.dto.RevisionDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * A base type for request/response entities.
+ */
+@XmlRootElement(name = "entity")
+public class ComponentEntity extends Entity {
+
+    private RevisionDTO revision;
+    private String id;
+    private String uri;
+    private PositionDTO position;
+    private AccessPolicyDTO accessPolicy;
+
+    /**
+     * @return revision for this request/response
+     */
+    @ApiModelProperty(
+            value = "The revision for this request/response. The revision is required for any mutable flow requests and is included in all responses."
+    )
+    public RevisionDTO getRevision() {
+        if (revision == null) {
+            return new RevisionDTO();
+        } else {
+            return revision;
+        }
+    }
+
+    public void setRevision(RevisionDTO revision) {
+        this.revision = revision;
+    }
+
+    /**
+     * The id for this component.
+     *
+     * @return The id
+     */
+    @ApiModelProperty(
+        value = "The id of the component."
+    )
+    public String getId() {
+        return this.id;
+    }
+
+    public void setId(final String id) {
+        this.id = id;
+    }
+
+    /**
+     * The uri for linking to this component in this NiFi.
+     *
+     * @return The uri
+     */
+    @ApiModelProperty(
+        value = "The URI for futures requests to the component."
+    )
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    /**
+     * The position of this component in the UI if applicable, null otherwise.
+     *
+     * @return The position
+     */
+    @ApiModelProperty(
+        value = "The position of this component in the UI if applicable."
+    )
+    public PositionDTO getPosition() {
+        return position;
+    }
+
+    public void setPosition(PositionDTO position) {
+        this.position = position;
+    }
+
+    /**
+     * The access policy for this component.
+     *
+     * @return The access policy
+     */
+    @ApiModelProperty(
+        value = "The access policy for this component."
+    )
+    public AccessPolicyDTO getAccessPolicy() {
+        return accessPolicy;
+    }
+
+    public void setAccessPolicy(AccessPolicyDTO accessPolicy) {
+        this.accessPolicy = accessPolicy;
+    }
+}


[03/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 555450e..d042286 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
@@ -45,7 +45,7 @@ nf.Funnel = (function () {
      */
     var select = function () {
         return funnelContainer.selectAll('g.funnel').data(funnelMap.values(), function (d) {
-            return d.component.id;
+            return d.id;
         });
     };
 
@@ -63,7 +63,7 @@ nf.Funnel = (function () {
         var funnel = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': 'funnel component'
                 })
@@ -100,9 +100,9 @@ nf.Funnel = (function () {
         funnel.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
 
         // only support dragging and connecting when appropriate
-        if (nf.Common.isDFM()) {
-            funnel.call(nf.Draggable.activate).call(nf.Connectable.activate);
-        }
+        funnel.filter(function (d) {
+            return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+        }).call(nf.Draggable.activate).call(nf.Connectable.activate);
 
         return funnel;
     };
@@ -142,28 +142,27 @@ nf.Funnel = (function () {
         /**
          * Populates the graph with the specified funnels.
          * 
-         * @argument {object | array} funnels                    The funnels to add
+         * @argument {object | array} funnelEntities                    The funnels to add
          * @argument {boolean} selectAll                Whether or not to select the new contents
          */
-        add: function (funnels, selectAll) {
+        add: function (funnelEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
-            var add = function (funnel) {
+            var add = function (funnelEntity) {
                 // add the funnel
-                funnelMap.set(funnel.id, {
+                funnelMap.set(funnelEntity.id, $.extend({
                     type: 'Funnel',
-                    component: funnel,
                     dimensions: dimensions
-                });
+                }, funnelEntity));
             };
 
             // determine how to handle the specified funnel status
-            if ($.isArray(funnels)) {
-                $.each(funnels, function (_, funnel) {
-                    add(funnel);
+            if ($.isArray(funnelEntities)) {
+                $.each(funnelEntities, function (_, funnelEntity) {
+                    add(funnelEntity);
                 });
             } else {
-                add(funnels);
+                add(funnelEntities);
             }
 
             // apply the selection and handle all new processors
@@ -211,7 +210,7 @@ nf.Funnel = (function () {
                     url: funnel.uri,
                     dataType: 'json'
                 }).done(function (response) {
-                    nf.Funnel.set(response.funnel);
+                    nf.Funnel.set(response);
                 });
             }
         },
@@ -230,38 +229,31 @@ nf.Funnel = (function () {
          * will set each funnel. If it is not an array, it will 
          * attempt to set the specified funnel.
          * 
-         * @param {object | array} funnels
+         * @param {object | array} funnelEntities
          */
-        set: function (funnels) {
-            var set = function (funnel) {
-                if (funnelMap.has(funnel.id)) {
+        set: function (funnelEntities) {
+            var set = function (funnelEntity) {
+                if (funnelMap.has(funnelEntity.id)) {
                     // update the current entry
-                    var funnelEntry = funnelMap.get(funnel.id);
-                    funnelEntry.component = funnel;
-
+                    var funnelEntry = funnelMap.get(funnelEntity.id);
+                    $.extend(funnelEntry, funnelEntity);
+                    
                     // update the connection in the UI
-                    d3.select('#id-' + funnel.id).call(updateFunnels);
+                    d3.select('#id-' + funnelEntity.id).call(updateFunnels);
                 }
             };
 
             // determine how to handle the specified funnel status
-            if ($.isArray(funnels)) {
-                $.each(funnels, function (_, funnel) {
-                    set(funnel);
+            if ($.isArray(funnelEntities)) {
+                $.each(funnelEntities, function (_, funnelEntity) {
+                    set(funnelEntity);
                 });
             } else {
-                set(funnels);
+                set(funnelEntities);
             }
         },
 
         /**
-         * Returns the entity key when marshalling an entity of this type.
-         */
-        getEntityKey: function (d) {
-            return 'funnel';
-        },
-
-        /**
          * Removes the specified funnel.
          * 
          * @param {array|string} funnels      The funnel id

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-go-to.js
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-go-to.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-go-to.js
index f3d0738..5bf3e9e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-go-to.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-go-to.js
@@ -156,7 +156,7 @@ nf.GoTo = (function () {
     var addDestinationInputPort = function (container, connection) {
         // get the remote process group
         return getProcessGroup(connection.destination.groupId).done(function (response) {
-            var processGroup = response.processGroup;
+            var processGroup = response.component;
 
             // process group
             var downstreamComponent = $('<div class="destination-component"></div>').appendTo(container);
@@ -263,7 +263,7 @@ nf.GoTo = (function () {
     var addSourceOutputPort = function (container, connection) {
         // get the remote process group
         return getProcessGroup(connection.source.groupId).done(function (response) {
-            var processGroup = response.processGroup;
+            var processGroup = response.component;
 
             // process group
             var sourceComponent = $('<div class="source-component"></div>').appendTo(container);
@@ -364,7 +364,7 @@ nf.GoTo = (function () {
                 // add the destination for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the source
-                    if (connection.source.id === selectionData.component.id) {
+                    if (connection.source.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -403,7 +403,7 @@ nf.GoTo = (function () {
                 // add the source for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the destination
-                    if (connection.destination.id === selectionData.component.id) {
+                    if (connection.destination.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -442,7 +442,7 @@ nf.GoTo = (function () {
                 // add the destination for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the source
-                    if (connection.source.groupId === selectionData.component.id) {
+                    if (connection.source.groupId === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -481,7 +481,7 @@ nf.GoTo = (function () {
                 // add the source for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the destination
-                    if (connection.destination.groupId === selectionData.component.id) {
+                    if (connection.destination.groupId === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -520,7 +520,7 @@ nf.GoTo = (function () {
                 // add the destination for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the source
-                    if (connection.source.id === selectionData.component.id) {
+                    if (connection.source.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -562,7 +562,7 @@ nf.GoTo = (function () {
                 // add the source for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the destination
-                    if (connection.destination.id === selectionData.component.id) {
+                    if (connection.destination.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -604,7 +604,7 @@ nf.GoTo = (function () {
                 // add the destination for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the source
-                    if (connection.source.id === selectionData.component.id) {
+                    if (connection.source.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -643,7 +643,7 @@ nf.GoTo = (function () {
                 // add the source for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the destination
-                    if (connection.destination.id === selectionData.component.id) {
+                    if (connection.destination.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -679,7 +679,7 @@ nf.GoTo = (function () {
                 // add the destination for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the source
-                    if (connection.source.id === selectionData.component.id) {
+                    if (connection.source.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });
@@ -715,7 +715,7 @@ nf.GoTo = (function () {
                 // add the source for each connection
                 $.each(connections, function (_, connection) {
                     // only show connections for which this selection is the destination
-                    if (connection.destination.id === selectionData.component.id) {
+                    if (connection.destination.id === selectionData.id) {
                         addConnection(connection);
                     }
                 });

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label-configuration.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-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label-configuration.js
index 6e9ee36..5524ec4 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label-configuration.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-label-configuration.js
@@ -43,7 +43,7 @@ nf.LabelConfiguration = (function () {
                             // build the label entity
                             var labelEntity = {
                                 'revision': nf.Client.getRevision(),
-                                'label': {
+                                'component': {
                                     'id': labelId,
                                     'label': labelValue,
                                     'style': {
@@ -64,7 +64,7 @@ nf.LabelConfiguration = (function () {
                                 nf.Client.setRevision(response.revision);
 
                                 // get the label out of the response
-                                nf.Label.set(response.label);
+                                nf.Label.set(response);
                             }).fail(nf.Common.handleAjaxError);
 
                             // reset and hide the dialog
@@ -139,7 +139,7 @@ nf.LabelConfiguration = (function () {
                 }
 
                 // store the label uri
-                labelId = selectionData.component.id;
+                labelId = selectionData.id;
 
                 // populate the dialog
                 $('#label-value').val(labelValue);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 5629bbb..809b905 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
@@ -53,9 +53,7 @@ nf.Label = (function () {
      * Selects the labels elements against the current label map.
      */
     var select = function () {
-        return labelContainer.selectAll('g.label').data(labelMap.values(), function (d) {
-            return d.component.id;
-        });
+        return labelContainer.selectAll('g.label').data(labelMap.values());
     };
 
     /**
@@ -72,12 +70,12 @@ nf.Label = (function () {
         var label = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': 'label component'
                 })
                 .classed('selected', selected)
-                .call(position);
+                .call(nf.CanvasUtils.position);
 
         // label border
         label.append('rect')
@@ -110,31 +108,15 @@ nf.Label = (function () {
         label.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
 
         // only support dragging when appropriate
-        if (nf.Common.isDFM()) {
-            label.call(nf.Draggable.activate);
-        }
+        label.filter(function (d) {
+            return d.accessPolicy.canWrite && d.accessPolicy.canRead;
+        }).call(nf.Draggable.activate);
 
         // call update to trigger some rendering
         label.call(updateLabels);
     };
 
     /**
-     * Position the component accordingly.
-     * 
-     * @param {selection} updated
-     */
-    var position = function (updated) {
-        if (updated.empty()) {
-            return;
-        }
-
-        // update the processors positioning
-        updated.attr('transform', function (d) {
-            return 'translate(' + d.component.position.x + ', ' + d.component.position.y + ')';
-        });
-    };
-
-    /**
      * Updates the labels in the specified selection.
      * 
      * @param {selection} updated               The labels to be updated
@@ -150,9 +132,11 @@ nf.Label = (function () {
 
         // determine all unique colors
         labelMap.forEach(function (id, d) {
-            var color = d.component.style['background-color'];
-            if (nf.Common.isDefinedAndNotNull(color)) {
-                colors.add(nf.Common.substringAfterLast(color, '#'));
+            if (d.accessPolicy.canRead) {
+                var color = d.component.style['background-color'];
+                if (nf.Common.isDefinedAndNotNull(color)) {
+                    colors.add(nf.Common.substringAfterLast(color, '#'));
+                }
             }
         });
         nf.Canvas.defineLabelColors(colors.values());
@@ -163,9 +147,11 @@ nf.Label = (function () {
                     'stroke': function (d) {
                         var color = nf.Label.defaultColor();
 
-                        // use the specified color if appropriate
-                        if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
-                            color = d.component.style['background-color'];
+                        if (d.accessPolicy.canRead) {
+                            // use the specified color if appropriate
+                            if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
+                                color = d.component.style['background-color'];
+                            }
                         }
 
                         return color;
@@ -184,9 +170,11 @@ nf.Label = (function () {
                     'fill': function (d) {
                         var color = nf.Label.defaultColor();
 
-                        // use the specified color if appropriate
-                        if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
-                            color = d.component.style['background-color'];
+                        if (d.accessPolicy.canRead) {
+                            // use the specified color if appropriate
+                            if (nf.Common.isDefinedAndNotNull(d.component.style['background-color'])) {
+                                color = d.component.style['background-color'];
+                            }
                         }
 
                         // get just the color code part
@@ -206,68 +194,71 @@ nf.Label = (function () {
         updated.each(function (d) {
             var updatedLabel = d3.select(this);
 
-            // update the label
-            var label = updatedLabel.select('text.label-value');
+            if (d.accessPolicy.canRead) {
+                // update the label
+                var label = updatedLabel.select('text.label-value');
 
-            // udpate the font size
-            label.attr('font-size', function () {
-                var fontSize = '12px';
+                // udpate the font size
+                label.attr('font-size', function () {
+                    var fontSize = '12px';
 
-                // use the specified color if appropriate
-                if (nf.Common.isDefinedAndNotNull(d.component.style['font-size'])) {
-                    fontSize = d.component.style['font-size'];
-                }
+                    // use the specified color if appropriate
+                    if (nf.Common.isDefinedAndNotNull(d.component.style['font-size'])) {
+                        fontSize = d.component.style['font-size'];
+                    }
 
-                return fontSize;
-            });
+                    return fontSize;
+                });
 
-            // remove the previous label value
-            label.selectAll('tspan').remove();
+                // remove the previous label value
+                label.selectAll('tspan').remove();
 
-            // parse the lines in this label
-            var lines = [];
-            if (nf.Common.isDefinedAndNotNull(d.component.label)) {
-                lines = d.component.label.split('\n');
-            } else {
-                lines.push('');
-            }
+                // parse the lines in this label
+                var lines = [];
+                if (nf.Common.isDefinedAndNotNull(d.component.label)) {
+                    lines = d.component.label.split('\n');
+                } else {
+                    lines.push('');
+                }
 
-            // add label value
-            $.each(lines, function (i, line) {
-                label.append('tspan')
-                        .attr('x', '0.4em')
-                        .attr('dy', '1.2em')
-                        .text(function () {
-                            return line;
-                        });
-            });
-
-            // -----------
-            // labelpoints
-            // -----------
-
-            if (nf.Common.isDFM()) {
-                var pointData = [
-                    {x: d.dimensions.width, y: d.dimensions.height}
-                ];
-                var points = updatedLabel.selectAll('rect.labelpoint').data(pointData);
-
-                // create a point for the end
-                points.enter().append('rect')
-                        .attr({
-                            'class': 'labelpoint',
-                            'width': 10,
-                            'height': 10
-                        })
-                        .call(labelPointDrag);
-
-                // update the midpoints
-                points.attr('transform', function (p) {
-                    return 'translate(' + (p.x - 10) + ', ' + (p.y - 10) + ')';
+                // add label value
+                $.each(lines, function (i, line) {
+                    label.append('tspan')
+                            .attr('x', '0.4em')
+                            .attr('dy', '1.2em')
+                            .text(function () {
+                                return line;
+                            });
                 });
 
-                // remove old items
-                points.exit().remove();
+
+                // -----------
+                // labelpoints
+                // -----------
+
+                if (d.accessPolicy.canWrite) {
+                    var pointData = [
+                        {x: d.dimensions.width, y: d.dimensions.height}
+                    ];
+                    var points = updatedLabel.selectAll('rect.labelpoint').data(pointData);
+
+                    // create a point for the end
+                    points.enter().append('rect')
+                            .attr({
+                                'class': 'labelpoint',
+                                'width': 10,
+                                'height': 10
+                            })
+                            .call(labelPointDrag);
+
+                    // update the midpoints
+                    points.attr('transform', function (p) {
+                        return 'translate(' + (p.x - 10) + ', ' + (p.y - 10) + ')';
+                    });
+
+                    // remove old items
+                    points.exit().remove();
+                }
             }
         });
     };
@@ -334,24 +325,27 @@ nf.Label = (function () {
 
                         // only save the updated bends if necessary
                         if (different) {
-                            var revision = nf.Client.getRevision();
+                            var labelEntity = {
+                                'revision': nf.Client.getRevision(),
+                                'component': {
+                                    'id': labelData.id,
+                                    'width': labelData.dimensions.width,
+                                    'height': labelData.dimensions.height
+                                }
+                            }
 
                             $.ajax({
                                 type: 'PUT',
                                 url: labelData.component.uri,
-                                data: {
-                                    'version': revision.version,
-                                    'clientId': revision.clientId,
-                                    'width': labelData.dimensions.width,
-                                    'height': labelData.dimensions.height
-                                },
-                                dataType: 'json'
+                                data: JSON.stringify(labelEntity),
+                                dataType: 'json',
+                                contentType: 'application/json'
                             }).done(function (response) {
                                 // update the revision
                                 nf.Client.setRevision(response.revision);
 
                                 // request was successful, update the entry
-                                nf.Label.set(response.label);
+                                nf.Label.set(response);
                             }).fail(function () {
                                 // determine the previous width
                                 var width = dimensions.width;
@@ -384,43 +378,26 @@ nf.Label = (function () {
         /**
          * Populates the graph with the specified labels.
          * 
-         * @argument {object | array} labels                    The labels to add
+         * @argument {object | array} labelEntities                   The labels to add
          * @argument {boolean} selectAll                Whether or not to select the new contents
          */
-        add: function (labels, selectAll) {
+        add: function (labelEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
-            var add = function (label) {
-                // determine the width
-                var width = dimensions.width;
-                if (nf.Common.isDefinedAndNotNull(label.width)) {
-                    width = label.width;
-                }
-
-                // determine the height
-                var height = dimensions.height;
-                if (nf.Common.isDefinedAndNotNull(label.height)) {
-                    height = label.height;
-                }
-
+            var add = function (labelEntity) {
                 // add the label
-                labelMap.set(label.id, {
-                    type: 'Label',
-                    component: label,
-                    dimensions: {
-                        width: width,
-                        height: height
-                    }
-                });
+                labelMap.set(labelEntity.id, $.extend({
+                    type: 'Label'
+                }, labelEntity));
             };
 
             // determine how to handle the specified label status
-            if ($.isArray(labels)) {
-                $.each(labels, function (_, label) {
-                    add(label);
+            if ($.isArray(labelEntities)) {
+                $.each(labelEntities, function (_, labelEntity) {
+                    add(labelEntity);
                 });
             } else {
-                add(labels);
+                add(labelEntities);
             }
 
             // apply the selection and handle all new labels
@@ -468,7 +445,7 @@ nf.Label = (function () {
                     url: label.uri,
                     dataType: 'json'
                 }).done(function (response) {
-                    nf.Label.set(response.label);
+                    nf.Label.set(response);
                 });
             }
         },
@@ -479,7 +456,7 @@ nf.Label = (function () {
          * @param {string} id   The id
          */
         position: function (id) {
-            d3.select('#id-' + id).call(position);
+            d3.select('#id-' + id).call(nf.CanvasUtils.position);
         },
         
         /**
@@ -487,54 +464,31 @@ nf.Label = (function () {
          * will set each label. If it is not an array, it will 
          * attempt to set the specified label.
          * 
-         * @param {object | array} labels
+         * @param {object | array} labelEntities
          */
-        set: function (labels) {
-            var set = function (label) {
-                if (labelMap.has(label.id)) {
-                    // determine the width
-                    var width = dimensions.width;
-                    if (nf.Common.isDefinedAndNotNull(label.width)) {
-                        width = label.width;
-                    }
-
-                    // determine the height
-                    var height = dimensions.height;
-                    if (nf.Common.isDefinedAndNotNull(label.height)) {
-                        height = label.height;
-                    }
-
+        set: function (labelEntities) {
+            var set = function (labelEntity) {
+                if (labelMap.has(labelEntity.id)) {
                     // update the current entry
-                    var labelEntry = labelMap.get(label.id);
-                    labelEntry.component = label;
-                    labelEntry.dimensions = {
-                        width: width,
-                        height: height
-                    };
+                    var labelEntry = labelMap.get(labelEntity.id);
+                    $.extend(labelEntry, labelEntity);
 
                     // update the connection in the UI
-                    d3.select('#id-' + label.id).call(updateLabels);
+                    d3.select('#id-' + labelEntry.id).call(updateLabels);
                 }
             };
 
             // determine how to handle the specified label status
-            if ($.isArray(labels)) {
-                $.each(labels, function (_, label) {
+            if ($.isArray(labelEntities)) {
+                $.each(labelEntities, function (_, label) {
                     set(label);
                 });
             } else {
-                set(labels);
+                set(labelEntities);
             }
         },
 
         /**
-         * Returns the entity key when marshalling an entity of this type.
-         */
-        getEntityKey: function (d) {
-            return 'label';
-        },
-        
-        /**
          * Removes the specified label.
          * 
          * @param {array|string} labels      The label id(s)

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-configuration.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-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-configuration.js
index 41278b8..a972e8e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-configuration.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-configuration.js
@@ -55,12 +55,10 @@ nf.PortConfiguration = (function () {
                             
                             // build the port entity
                             var portEntity = {
-                                'revision': nf.Client.getRevision()
+                                'revision': nf.Client.getRevision(),
+                                'component': port
                             };
 
-                            // use bracket notation to set the key based on the type
-                            portEntity[nf[portData.type].getEntityKey(portData)] = port;
-                            
                             // update the selected component
                             $.ajax({
                                 type: 'PUT',
@@ -72,15 +70,8 @@ nf.PortConfiguration = (function () {
                                 // update the revision
                                 nf.Client.setRevision(response.revision);
 
-                                var port;
-                                if (nf.Common.isDefinedAndNotNull(response.inputPort)) {
-                                    port = response.inputPort;
-                                } else {
-                                    port = response.outputPort;
-                                }
-
                                 // refresh the port component
-                                nf.Port.set(port);
+                                nf.Port.set(response);
 
                                 // close the details panel
                                 $('#port-configuration').modal('hide');
@@ -166,7 +157,7 @@ nf.PortConfiguration = (function () {
                 }
 
                 // populate the port settings
-                $('#port-id').text(selectionData.component.id);
+                $('#port-id').text(selectionData.id);
                 $('#port-name').val(selectionData.component.name);
                 $('#port-enabled').removeClass('checkbox-unchecked checkbox-checked').addClass(portEnableStyle);
                 $('#port-concurrent-tasks').val(selectionData.component.concurrentlySchedulableTaskCount);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-details.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-details.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-details.js
index c520044..1134fc1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-details.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-port-details.js
@@ -55,7 +55,7 @@ nf.PortDetails = (function () {
 
                 // populate the port settings
                 nf.Common.populateField('read-only-port-name', selectionData.component.name);
-                nf.Common.populateField('read-only-port-id', selectionData.component.id);
+                nf.Common.populateField('read-only-port-id', selectionData.id);
                 nf.Common.populateField('read-only-port-comments', selectionData.component.comments);
 
                 // show the details

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/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 7b69c8b..74c7a77 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
@@ -51,9 +51,7 @@ nf.Port = (function () {
      * Selects the port elements against the current port map.
      */
     var select = function () {
-        return portContainer.selectAll('g.input-port, g.output-port').data(portMap.values(), function (d) {
-            return d.component.id;
-        });
+        return portContainer.selectAll('g.input-port, g.output-port').data(portMap.values());
     };
 
     /**
@@ -70,10 +68,10 @@ nf.Port = (function () {
         var port = entered.append('g')
                 .attr({
                     'id': function (d) {
-                        return 'id-' + d.component.id;
+                        return 'id-' + d.id;
                     },
                     'class': function (d) {
-                        if (d.component.type === 'INPUT_PORT') {
+                        if (d.portType === 'INPUT_PORT') {
                             return 'input-port component';
                         } else {
                             return 'output-port component';
@@ -142,7 +140,7 @@ nf.Port = (function () {
                 .call(nf.CanvasUtils.disableImageHref)
                 .attr({
                     'xlink:href': function (d) {
-                        if (d.component.type === 'INPUT_PORT') {
+                        if (d.portTtype === 'INPUT_PORT') {
                             return 'images/iconInputPort.png';
                         } else {
                             return 'images/iconOutputPort.png';
@@ -151,7 +149,7 @@ nf.Port = (function () {
                     'width': 46,
                     'height': 31,
                     'x': function (d) {
-                        if (d.component.type === 'INPUT_PORT') {
+                        if (d.portType === 'INPUT_PORT') {
                             return 0;
                         } else {
                             return 114;
@@ -164,7 +162,7 @@ nf.Port = (function () {
         port.append('text')
                 .attr({
                     'x': function (d) {
-                        if (d.component.type === 'INPUT_PORT') {
+                        if (d.portType === 'INPUT_PORT') {
                             return 52;
                         } else {
                             return 5;
@@ -183,9 +181,9 @@ nf.Port = (function () {
         port.call(nf.Selectable.activate).call(nf.ContextMenu.activate);
 
         // only activate dragging and connecting if appropriate
-        if (nf.Common.isDFM()) {
-            port.call(nf.Draggable.activate).call(nf.Connectable.activate);
-        }
+        port.filter(function (d) {
+            return d.accessPolicy.canWrite && d.accessPolicy.canRead;  
+        }).call(nf.Draggable.activate).call(nf.Connectable.activate);
 
         // call update to trigger some rendering
         port.call(updatePorts);
@@ -201,7 +199,7 @@ nf.Port = (function () {
             return;
         }
 
-        updated.each(function () {
+        updated.each(function (portData) {
             var port = d3.select(this);
             var details = port.select('g.port-details');
 
@@ -246,7 +244,7 @@ nf.Port = (function () {
                                 'width': 16,
                                 'height': 16,
                                 'x': function (d) {
-                                    if (d.component.type === 'INPUT_PORT') {
+                                    if (d.portType === 'INPUT_PORT') {
                                         return 33;
                                     } else {
                                         return 107;
@@ -279,83 +277,87 @@ nf.Port = (function () {
                             });
                 }
 
-                // update the run status
-                details.select('image.port-run-status-icon')
-                        .attr('xlink:href', function (d) {
-                            var img = '';
-                            if (d.component.state === 'DISABLED') {
-                                img = 'images/iconDisable.png';
-                            } else if (!nf.Common.isEmpty(d.component.validationErrors)) {
-                                img = 'images/iconAlert.png';
-                            } else if (d.component.state === 'RUNNING') {
-                                img = 'images/iconRun.png';
-                            } else if (d.component.state === 'STOPPED') {
-                                img = 'images/iconStop.png';
-                            }
-                            return img;
-                        })
-                        .each(function (d) {
-                            // remove the existing tip if necessary
-                            var tip = d3.select('#run-status-tip-' + d.component.id);
-                            if (!tip.empty()) {
-                                tip.remove();
-                            }
-
-                            // if there are validation errors generate a tooltip
-                            if (!nf.Common.isEmpty(d.component.validationErrors)) {
-                                tip = d3.select('#port-tooltips').append('div')
-                                        .attr('id', function () {
-                                            return 'run-status-tip-' + d.component.id;
-                                        })
-                                        .attr('class', 'tooltip nifi-tooltip')
-                                        .html(function () {
-                                            var list = nf.Common.formatUnorderedList(d.component.validationErrors);
-                                            if (list === null || list.length === 0) {
-                                                return '';
-                                            } else {
-                                                return $('<div></div>').append(list).html();
-                                            }
-                                        });
-
-                                // add the tooltip
-                                nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
-                            }
-                        });
-
-                // update the port name
-                port.select('text.port-name')
-                        .each(function (d) {
-                            var portName = d3.select(this);
-                            var name = d.component.name;
-                            var words = name.split(/\s+/);
-
-                            // reset the port name to handle any previous state
-                            portName.text(null).selectAll('tspan, title').remove();
-
-                            // handle based on the number of tokens in the port name
-                            if (words.length === 1) {
-                                // apply ellipsis to the port name as necessary
-                                nf.CanvasUtils.ellipsis(portName, name);
-                            } else {
-                                nf.CanvasUtils.multilineEllipsis(portName, 2, name);
-                            }
-                        }).append('title').text(function (d) {
-                    return d.component.name;
-                });
+                if (portData.accessPolicy.canRead) {
+                    // update the run status
+                    details.select('image.port-run-status-icon')
+                            .attr('xlink:href', function (d) {
+                                var img = '';
+                                if (d.component.state === 'DISABLED') {
+                                    img = 'images/iconDisable.png';
+                                } else if (!nf.Common.isEmpty(d.component.validationErrors)) {
+                                    img = 'images/iconAlert.png';
+                                } else if (d.component.state === 'RUNNING') {
+                                    img = 'images/iconRun.png';
+                                } else if (d.component.state === 'STOPPED') {
+                                    img = 'images/iconStop.png';
+                                }
+                                return img;
+                            })
+                            .each(function (d) {
+                                // remove the existing tip if necessary
+                                var tip = d3.select('#run-status-tip-' + d.id);
+                                if (!tip.empty()) {
+                                    tip.remove();
+                                }
+
+                                // if there are validation errors generate a tooltip
+                                if (!nf.Common.isEmpty(d.component.validationErrors)) {
+                                    tip = d3.select('#port-tooltips').append('div')
+                                            .attr('id', function () {
+                                                return 'run-status-tip-' + d.id;
+                                            })
+                                            .attr('class', 'tooltip nifi-tooltip')
+                                            .html(function () {
+                                                var list = nf.Common.formatUnorderedList(d.component.validationErrors);
+                                                if (list === null || list.length === 0) {
+                                                    return '';
+                                                } else {
+                                                    return $('<div></div>').append(list).html();
+                                                }
+                                            });
+
+                                    // add the tooltip
+                                    nf.CanvasUtils.canvasTooltip(tip, d3.select(this));
+                                }
+                            });
+
+                    // update the port name
+                    port.select('text.port-name')
+                            .each(function (d) {
+                                var portName = d3.select(this);
+                                var name = d.component.name;
+                                var words = name.split(/\s+/);
+
+                                // reset the port name to handle any previous state
+                                portName.text(null).selectAll('tspan, title').remove();
+
+                                // handle based on the number of tokens in the port name
+                                if (words.length === 1) {
+                                    // apply ellipsis to the port name as necessary
+                                    nf.CanvasUtils.ellipsis(portName, name);
+                                } else {
+                                    nf.CanvasUtils.multilineEllipsis(portName, 2, name);
+                                }
+                            }).append('title').text(function (d) {
+                        return d.component.name;
+                    });
+                }
 
                 // populate the stats
                 port.call(updatePortStatus);
             } else {
-                // update the port name
-                port.select('text.port-name')
-                        .text(function (d) {
-                            var name = d.component.name;
-                            if (name.length > PREVIEW_NAME_LENGTH) {
-                                return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
-                            } else {
-                                return name;
-                            }
-                        });
+                if (portData.accessPolicy.canRead) {
+                    // update the port name
+                    port.select('text.port-name')
+                            .text(function (d) {
+                                var name = d.component.name;
+                                if (name.length > PREVIEW_NAME_LENGTH) {
+                                    return name.substring(0, PREVIEW_NAME_LENGTH) + String.fromCharCode(8230);
+                                } else {
+                                    return name;
+                                }
+                            });
+                }
 
                 // remove tooltips if necessary
                 port.call(removeTooltips);
@@ -430,8 +432,8 @@ nf.Port = (function () {
     var removeTooltips = function (removed) {
         removed.each(function (d) {
             // remove any associated tooltips
-            $('#run-status-tip-' + d.component.id).remove();
-            $('#bulletin-tip-' + d.component.id).remove();
+            $('#run-status-tip-' + d.id).remove();
+            $('#bulletin-tip-' + d.id).remove();
         });
     };
 
@@ -453,10 +455,10 @@ nf.Port = (function () {
         /**
          * Populates the graph with the specified ports.
          *
-         * @argument {object | array} ports                    The ports to add
+         * @argument {object | array} portNodes                    The ports to add
          * @argument {boolean} selectAll                Whether or not to select the new contents
          */
-        add: function (ports, selectAll) {
+        add: function (portEntities, selectAll) {
             selectAll = nf.Common.isDefinedAndNotNull(selectAll) ? selectAll : false;
 
             // determine the appropriate dimensions for this port
@@ -465,25 +467,24 @@ nf.Port = (function () {
                 dimensions = remotePortDimensions;
             }
 
-            var add = function (ports) {
+            var add = function (portEntity) {
                 // add the port
-                portMap.set(ports.id, {
+                portMap.set(portEntity.id, $.extend({
                     type: 'Port',
-                    component: ports,
                     dimensions: dimensions,
                     status: {
                         activeThreadCount: 0
                     }
-                });
+                }, portEntity));
             };
 
             // determine how to handle the specified port status
-            if ($.isArray(ports)) {
-                $.each(ports, function (_, port) {
-                    add(port);
+            if ($.isArray(portEntities)) {
+                $.each(portEntities, function (_, portNode) {
+                    add(portNode);
                 });
             } else {
-                add(ports);
+                add(portEntities);
             }
 
             // apply the selection and handle all new ports
@@ -539,9 +540,9 @@ nf.Port = (function () {
                     dataType: 'json'
                 }).done(function (response) {
                     if (nf.Common.isDefinedAndNotNull(response.inputPort)) {
-                        nf.Port.set(response.inputPort);
+                        nf.Port.set(response);
                     } else {
-                        nf.Port.set(response.outputPort);
+                        nf.Port.set(response);
                     }
                 });
             }
@@ -561,27 +562,27 @@ nf.Port = (function () {
          * will set each port. If it is not an array, it will
          * attempt to set the specified port.
          *
-         * @param {object | array} ports
+         * @param {object | array} portEntities
          */
-        set: function (ports) {
-            var set = function (port) {
-                if (portMap.has(port.id)) {
+        set: function (portEntities) {
+            var set = function (portEntity) {
+                if (portMap.has(portEntity.id)) {
                     // update the current entry
-                    var portEntry = portMap.get(port.id);
-                    portEntry.component = port;
+                    var portEntry = portMap.get(portEntity.id);
+                    $.extend(portEntry, portEntity);
 
                     // update the connection in the UI
-                    d3.select('#id-' + port.id).call(updatePorts);
+                    d3.select('#id-' + portEntry.id).call(updatePorts);
                 }
             };
 
             // determine how to handle the specified ports
-            if ($.isArray(ports)) {
-                $.each(ports, function (_, port) {
+            if ($.isArray(portEntities)) {
+                $.each(portEntities, function (_, port) {
                     set(port);
                 });
             } else {
-                set(ports);
+                set(portEntities);
             }
         },
         
@@ -608,13 +609,6 @@ nf.Port = (function () {
         },
 
         /**
-         * Returns the entity key when marshalling an entity of this type.
-         */
-        getEntityKey: function (d) {
-            return d.component.type === 'INPUT_PORT' ? 'inputPort' : 'outputPort';
-        },
-
-        /**
          * Removes the specified port.
          *
          * @param {string} ports      The port id(s)

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-configuration.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-configuration.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-configuration.js
index b72deb2..3b6cd14 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-configuration.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-configuration.js
@@ -37,7 +37,7 @@ nf.ProcessGroupConfiguration = (function () {
                                 // build the entity
                                 var entity = {
                                     'revision': nf.Client.getRevision(),
-                                    'processGroup': {
+                                    'component': {
                                         'id': processGroupId,
                                         'name': $('#process-group-name').val(),
                                         'comments': $('#process-group-comments').val()
@@ -52,12 +52,12 @@ nf.ProcessGroupConfiguration = (function () {
                                     dataType: 'json',
                                     contentType: 'application/json'
                                 }).done(function (response) {
-                                    if (nf.Common.isDefinedAndNotNull(response.processGroup)) {
+                                    if (nf.Common.isDefinedAndNotNull(response.component)) {
                                         // update the revision
                                         nf.Client.setRevision(response.revision);
 
                                         // refresh the process group
-                                        nf.ProcessGroup.set(response.processGroup);
+                                        nf.ProcessGroup.set(response);
 
                                         // close the details panel
                                         $('#process-group-configuration').modal('hide');
@@ -104,7 +104,7 @@ nf.ProcessGroupConfiguration = (function () {
                 var selectionData = selection.datum();
 
                 // populate the process group settings
-                $('#process-group-id').text(selectionData.component.id);
+                $('#process-group-id').text(selectionData.id);
                 $('#process-group-name').val(selectionData.component.name);
                 $('#process-group-comments').val(selectionData.component.comments);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-details.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-details.js b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-details.js
index 473ca9c..7796901 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-details.js
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-ui/src/main/webapp/js/nf/canvas/nf-process-group-details.js
@@ -54,7 +54,7 @@ nf.ProcessGroupDetails = (function () {
                 var selectionData = selection.datum();
 
                 // populate the port settings
-                nf.Common.populateField('read-only-process-group-id', selectionData.component.id);
+                nf.Common.populateField('read-only-process-group-id', selectionData.id);
                 nf.Common.populateField('read-only-process-group-name', selectionData.component.name);
                 nf.Common.populateField('read-only-process-group-comments', selectionData.component.comments);
 


[10/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
index 67f24e1..ba9d0ff 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java
@@ -34,7 +34,6 @@ import org.apache.nifi.web.api.dto.CountersDTO;
 import org.apache.nifi.web.api.dto.DocumentedTypeDTO;
 import org.apache.nifi.web.api.dto.DropRequestDTO;
 import org.apache.nifi.web.api.dto.FlowFileDTO;
-import org.apache.nifi.web.api.dto.FlowSnippetDTO;
 import org.apache.nifi.web.api.dto.FunnelDTO;
 import org.apache.nifi.web.api.dto.LabelDTO;
 import org.apache.nifi.web.api.dto.ListingRequestDTO;
@@ -54,6 +53,8 @@ import org.apache.nifi.web.api.dto.TemplateDTO;
 import org.apache.nifi.web.api.dto.action.ActionDTO;
 import org.apache.nifi.web.api.dto.action.HistoryDTO;
 import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
+import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceDTO;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceEventDTO;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceOptionsDTO;
@@ -66,6 +67,13 @@ import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
 import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
 import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
+import org.apache.nifi.web.api.entity.ConnectionEntity;
+import org.apache.nifi.web.api.entity.FunnelEntity;
+import org.apache.nifi.web.api.entity.LabelEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupEntity;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
 
 import java.util.Date;
 import java.util.List;
@@ -318,7 +326,7 @@ public interface NiFiServiceFacade {
      * @param originY y
      * @return snapshot
      */
-    ConfigurationSnapshot<FlowSnippetDTO> createTemplateInstance(Revision revision, String groupId, Double originX, Double originY, String templateId);
+    ConfigurationSnapshot<FlowDTO> createTemplateInstance(Revision revision, String groupId, Double originX, Double originY, String templateId);
 
     /**
      * Gets the template with the specified id.
@@ -361,7 +369,7 @@ public interface NiFiServiceFacade {
      * @param processorDTO The processor DTO
      * @return The new processor DTO
      */
-    ConfigurationSnapshot<ProcessorDTO> createProcessor(Revision revision, String groupId, ProcessorDTO processorDTO);
+    ProcessorEntity createProcessor(Revision revision, String groupId, ProcessorDTO processorDTO);
 
     /**
      * Gets the Processor transfer object for the specified id.
@@ -369,7 +377,7 @@ public interface NiFiServiceFacade {
      * @param id Id of the processor to return
      * @return The Processor transfer object
      */
-    ProcessorDTO getProcessor(String id);
+    ProcessorEntity getProcessor(String id);
 
     /**
      * Gets the processor status.
@@ -402,7 +410,7 @@ public interface NiFiServiceFacade {
      * @param groupId group
      * @return List of all the Processor transfer object
      */
-    Set<ProcessorDTO> getProcessors(String groupId);
+    Set<ProcessorEntity> getProcessors(String groupId);
 
     /**
      * Verifies the specified processor can be updated.
@@ -418,7 +426,7 @@ public interface NiFiServiceFacade {
      * @param processorDTO The processorDTO
      * @return The updated processor
      */
-    ConfigurationSnapshot<ProcessorDTO> updateProcessor(Revision revision, ProcessorDTO processorDTO);
+    UpdateResult<ProcessorEntity> updateProcessor(Revision revision, ProcessorDTO processorDTO);
 
     /**
      * Verifies the specified processor can be removed.
@@ -434,7 +442,7 @@ public interface NiFiServiceFacade {
      * @param processorId The processor id to delete
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteProcessor(Revision revision, String processorId);
+    ProcessorEntity deleteProcessor(Revision revision, String processorId);
 
     // ----------------------------------------
     // Connections methods
@@ -446,7 +454,7 @@ public interface NiFiServiceFacade {
      * @param groupId group
      * @return The Connection transfer objects
      */
-    Set<ConnectionDTO> getConnections(String groupId);
+    Set<ConnectionEntity> getConnections(String groupId);
 
     /**
      * Gets the specified Connection transfer object.
@@ -454,7 +462,7 @@ public interface NiFiServiceFacade {
      * @param connectionId The ID of the connection
      * @return The Connection transfer object
      */
-    ConnectionDTO getConnection(String connectionId);
+    ConnectionEntity getConnection(String connectionId);
 
     /**
      * Gets the status of the specified connection.
@@ -480,7 +488,7 @@ public interface NiFiServiceFacade {
      * @param connectionDTO The Connection DTO
      * @return The Connection DTO
      */
-    ConfigurationSnapshot<ConnectionDTO> createConnection(Revision revision, String groupId, ConnectionDTO connectionDTO);
+    ConnectionEntity createConnection(Revision revision, String groupId, ConnectionDTO connectionDTO);
 
     /**
      * Determines if this connection can be listed.
@@ -511,7 +519,7 @@ public interface NiFiServiceFacade {
      * @param connectionDTO The Connection DTO
      * @return The Connection DTO
      */
-    ConfigurationSnapshot<ConnectionDTO> updateConnection(Revision revision, ConnectionDTO connectionDTO);
+    UpdateResult<ConnectionEntity> updateConnection(Revision revision, ConnectionDTO connectionDTO);
 
     /**
      * Determines if this connection can be removed.
@@ -527,7 +535,7 @@ public interface NiFiServiceFacade {
      * @param connectionId The ID of the connection
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteConnection(Revision revision, String connectionId);
+    ConnectionEntity deleteConnection(Revision revision, String connectionId);
 
     /**
      * Creates a new flow file drop request.
@@ -603,7 +611,7 @@ public interface NiFiServiceFacade {
      * @param inputPortDTO The input PortDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<PortDTO> createInputPort(Revision revision, String groupId, PortDTO inputPortDTO);
+    PortEntity createInputPort(Revision revision, String groupId, PortDTO inputPortDTO);
 
     /**
      * Gets an input port.
@@ -611,7 +619,7 @@ public interface NiFiServiceFacade {
      * @param inputPortId The input port id
      * @return port
      */
-    PortDTO getInputPort(String inputPortId);
+    PortEntity getInputPort(String inputPortId);
 
     /**
      * Gets all input ports in a given group.
@@ -619,7 +627,7 @@ public interface NiFiServiceFacade {
      * @param groupId The id of the group
      * @return port
      */
-    Set<PortDTO> getInputPorts(String groupId);
+    Set<PortEntity> getInputPorts(String groupId);
 
     /**
      * Gets the input port status.
@@ -643,7 +651,7 @@ public interface NiFiServiceFacade {
      * @param inputPortDTO The input PortDTO
      * @return snapshort
      */
-    ConfigurationSnapshot<PortDTO> updateInputPort(Revision revision, PortDTO inputPortDTO);
+    UpdateResult<PortEntity> updateInputPort(Revision revision, PortDTO inputPortDTO);
 
     /**
      * Determines if the input port could be deleted.
@@ -659,7 +667,7 @@ public interface NiFiServiceFacade {
      * @param inputPortId The id of the input port
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteInputPort(Revision revision, String inputPortId);
+    PortEntity deleteInputPort(Revision revision, String inputPortId);
 
     // ----------------------------------------
     // OutputPort methods
@@ -672,7 +680,7 @@ public interface NiFiServiceFacade {
      * @param outputPortDTO The output PortDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<PortDTO> createOutputPort(Revision revision, String groupId, PortDTO outputPortDTO);
+    PortEntity createOutputPort(Revision revision, String groupId, PortDTO outputPortDTO);
 
     /**
      * Gets an output port.
@@ -680,7 +688,7 @@ public interface NiFiServiceFacade {
      * @param outputPortId The output port id
      * @return port
      */
-    PortDTO getOutputPort(String outputPortId);
+    PortEntity getOutputPort(String outputPortId);
 
     /**
      * Gets all output ports in a given group.
@@ -688,7 +696,7 @@ public interface NiFiServiceFacade {
      * @param groupId The id of the group
      * @return ports
      */
-    Set<PortDTO> getOutputPorts(String groupId);
+    Set<PortEntity> getOutputPorts(String groupId);
 
     /**
      * Gets the output port status.
@@ -712,7 +720,7 @@ public interface NiFiServiceFacade {
      * @param outputPortDTO The output PortDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<PortDTO> updateOutputPort(Revision revision, PortDTO outputPortDTO);
+    UpdateResult<PortEntity> updateOutputPort(Revision revision, PortDTO outputPortDTO);
 
     /**
      * Determines if the output port could be deleted.
@@ -728,7 +736,19 @@ public interface NiFiServiceFacade {
      * @param outputPortId The id of the output port
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteOutputPort(Revision revision, String outputPortId);
+    PortEntity deleteOutputPort(Revision revision, String outputPortId);
+
+    // ----------------------------------------
+    // Flow methods
+    // ----------------------------------------
+    /**
+     * Returns the flow.
+     *
+     * @param groupId group
+     * @param recurse recurse
+     * @return the flow
+     */
+    ConfigurationSnapshot<ProcessGroupFlowDTO> getProcessGroupFlow(String groupId, boolean recurse);
 
     // ----------------------------------------
     // ProcessGroup methods
@@ -741,16 +761,15 @@ public interface NiFiServiceFacade {
      * @param processGroupDTO The ProcessGroupDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<ProcessGroupDTO> createProcessGroup(String parentGroupId, Revision revision, ProcessGroupDTO processGroupDTO);
+    ProcessGroupEntity createProcessGroup(String parentGroupId, Revision revision, ProcessGroupDTO processGroupDTO);
 
     /**
      * Returns the process group.
      *
      * @param groupId group
-     * @param recurse recurse
      * @return ProcessGroup transfer object
      */
-    ConfigurationSnapshot<ProcessGroupDTO> getProcessGroup(String groupId, boolean recurse);
+    ProcessGroupEntity getProcessGroup(String groupId);
 
     /**
      * Gets all process groups in the specified parent group.
@@ -758,7 +777,7 @@ public interface NiFiServiceFacade {
      * @param parentGroupId The id of the parent group
      * @return process group
      */
-    Set<ProcessGroupDTO> getProcessGroups(String parentGroupId);
+    Set<ProcessGroupEntity> getProcessGroups(String parentGroupId);
 
     /**
      * Verifies the specified process group can be updated.
@@ -774,7 +793,7 @@ public interface NiFiServiceFacade {
      * @param processGroupDTO The ProcessGroupDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<ProcessGroupDTO> updateProcessGroup(Revision revision, ProcessGroupDTO processGroupDTO);
+    UpdateResult<ProcessGroupEntity> updateProcessGroup(Revision revision, ProcessGroupDTO processGroupDTO);
 
     /**
      * Verifies the specified process group can be removed.
@@ -790,7 +809,7 @@ public interface NiFiServiceFacade {
      * @param groupId The id of the process group
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteProcessGroup(Revision revision, String groupId);
+    ProcessGroupEntity deleteProcessGroup(Revision revision, String groupId);
 
     // ----------------------------------------
     // RemoteProcessGroup methods
@@ -803,7 +822,7 @@ public interface NiFiServiceFacade {
      * @param remoteProcessGroupDTO The RemoteProcessGroupDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<RemoteProcessGroupDTO> createRemoteProcessGroup(Revision revision, String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO);
+    RemoteProcessGroupEntity createRemoteProcessGroup(Revision revision, String groupId, RemoteProcessGroupDTO remoteProcessGroupDTO);
 
     /**
      * Gets a remote process group.
@@ -811,7 +830,7 @@ public interface NiFiServiceFacade {
      * @param remoteProcessGroupId The id of the remote process group
      * @return group
      */
-    RemoteProcessGroupDTO getRemoteProcessGroup(String remoteProcessGroupId);
+    RemoteProcessGroupEntity getRemoteProcessGroup(String remoteProcessGroupId);
 
     /**
      * Gets all remote process groups in the a given parent group.
@@ -819,7 +838,7 @@ public interface NiFiServiceFacade {
      * @param groupId The id of the parent group
      * @return group
      */
-    Set<RemoteProcessGroupDTO> getRemoteProcessGroups(String groupId);
+    Set<RemoteProcessGroupEntity> getRemoteProcessGroups(String groupId);
 
     /**
      * Gets the remote process group status.
@@ -867,7 +886,7 @@ public interface NiFiServiceFacade {
      * @param remoteProcessGroupDTO The RemoteProcessGroupDTO
      * @return snapshot
      */
-    ConfigurationSnapshot<RemoteProcessGroupDTO> updateRemoteProcessGroup(Revision revision, RemoteProcessGroupDTO remoteProcessGroupDTO);
+    UpdateResult<RemoteProcessGroupEntity> updateRemoteProcessGroup(Revision revision, RemoteProcessGroupDTO remoteProcessGroupDTO);
 
     /**
      * Updates the specified remote process groups input port.
@@ -903,7 +922,7 @@ public interface NiFiServiceFacade {
      * @param remoteProcessGroupId The id of the remote process group
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteRemoteProcessGroup(Revision revision, String remoteProcessGroupId);
+    RemoteProcessGroupEntity deleteRemoteProcessGroup(Revision revision, String remoteProcessGroupId);
 
     // ----------------------------------------
     // Funnel methods
@@ -916,7 +935,7 @@ public interface NiFiServiceFacade {
      * @param funnelDTO funnel
      * @return The funnel DTO
      */
-    ConfigurationSnapshot<FunnelDTO> createFunnel(Revision revision, String groupId, FunnelDTO funnelDTO);
+    FunnelEntity createFunnel(Revision revision, String groupId, FunnelDTO funnelDTO);
 
     /**
      * Gets the specified funnel.
@@ -924,7 +943,7 @@ public interface NiFiServiceFacade {
      * @param funnelId The funnel id
      * @return The funnel transfer object
      */
-    FunnelDTO getFunnel(String funnelId);
+    FunnelEntity getFunnel(String funnelId);
 
     /**
      * Gets all of the funnels.
@@ -932,7 +951,7 @@ public interface NiFiServiceFacade {
      * @param groupId group
      * @return The funnel transfer objects
      */
-    Set<FunnelDTO> getFunnels(String groupId);
+    Set<FunnelEntity> getFunnels(String groupId);
 
     /**
      * Updates the specified label.
@@ -941,7 +960,7 @@ public interface NiFiServiceFacade {
      * @param funnelDTO The funnel DTO
      * @return The funnel DTO
      */
-    ConfigurationSnapshot<FunnelDTO> updateFunnel(Revision revision, FunnelDTO funnelDTO);
+    UpdateResult<FunnelEntity> updateFunnel(Revision revision, FunnelDTO funnelDTO);
 
     /**
      * Verifies the specified funnel can be deleted.
@@ -957,7 +976,7 @@ public interface NiFiServiceFacade {
      * @param funnelId The funnel id
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteFunnel(Revision revision, String funnelId);
+    FunnelEntity deleteFunnel(Revision revision, String funnelId);
 
     // ----------------------------------------
     // Component state methods
@@ -1046,7 +1065,7 @@ public interface NiFiServiceFacade {
      * @param labelDTO The label DTO
      * @return The label DTO
      */
-    ConfigurationSnapshot<LabelDTO> createLabel(Revision revision, String groupId, LabelDTO labelDTO);
+    LabelEntity createLabel(Revision revision, String groupId, LabelDTO labelDTO);
 
     /**
      * Gets the specified label.
@@ -1054,7 +1073,7 @@ public interface NiFiServiceFacade {
      * @param labelId The label id
      * @return The label transfer object
      */
-    LabelDTO getLabel(String labelId);
+    LabelEntity getLabel(String labelId);
 
     /**
      * Gets all of the labels.
@@ -1062,7 +1081,7 @@ public interface NiFiServiceFacade {
      * @param groupId group
      * @return The label transfer objects
      */
-    Set<LabelDTO> getLabels(String groupId);
+    Set<LabelEntity> getLabels(String groupId);
 
     /**
      * Updates the specified label.
@@ -1071,7 +1090,7 @@ public interface NiFiServiceFacade {
      * @param labelDTO The label DTO
      * @return The label DTO
      */
-    ConfigurationSnapshot<LabelDTO> updateLabel(Revision revision, LabelDTO labelDTO);
+    UpdateResult<LabelEntity> updateLabel(Revision revision, LabelDTO labelDTO);
 
     /**
      * Deletes the specified label.
@@ -1080,7 +1099,7 @@ public interface NiFiServiceFacade {
      * @param labelId The label id
      * @return snapshot
      */
-    ConfigurationSnapshot<Void> deleteLabel(Revision revision, String labelId);
+    LabelEntity deleteLabel(Revision revision, String labelId);
 
     // ----------------------------------------
     // Controller Services methods
@@ -1294,7 +1313,7 @@ public interface NiFiServiceFacade {
      * @param originY y
      * @return snapshot
      */
-    ConfigurationSnapshot<FlowSnippetDTO> copySnippet(Revision revision, String groupId, String snippetId, Double originX, Double originY);
+    ConfigurationSnapshot<FlowDTO> copySnippet(Revision revision, String groupId, String snippetId, Double originX, Double originY);
 
     /**
      * Creates a new snippet.

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
index 58b0af8..51fa7a2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiWebApiConfiguration.java
@@ -27,6 +27,7 @@ import org.springframework.context.annotation.ImportResource;
 @Import({NiFiWebApiSecurityConfiguration.class})
 @ImportResource({"classpath:nifi-context.xml",
     "classpath:nifi-administration-context.xml",
+    "classpath:nifi-framework-authorization-context.xml",
     "classpath:nifi-cluster-manager-context.xml",
     "classpath:nifi-cluster-protocol-context.xml",
     "classpath:nifi-web-security-context.xml",

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
index 66f1546..36db1d9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiContentAccess.java
@@ -20,6 +20,8 @@ import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.ClientResponse.Status;
 import com.sun.jersey.core.util.MultivaluedMapImpl;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
@@ -27,11 +29,9 @@ import org.apache.nifi.cluster.node.Node;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
 import org.apache.nifi.controller.repository.claim.ContentDirection;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
index dae1ab6..b85c15d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java
@@ -24,7 +24,12 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.details.FlowChangePurgeDetails;
 import org.apache.nifi.admin.service.AuditService;
 import org.apache.nifi.admin.service.KeyService;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.context.ClusterContext;
 import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
 import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat;
@@ -62,13 +67,14 @@ import org.apache.nifi.remote.RootGroupPort;
 import org.apache.nifi.reporting.Bulletin;
 import org.apache.nifi.reporting.BulletinQuery;
 import org.apache.nifi.reporting.BulletinRepository;
-import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.api.dto.AccessPolicyDTO;
 import org.apache.nifi.web.api.dto.BulletinBoardDTO;
 import org.apache.nifi.web.api.dto.BulletinDTO;
 import org.apache.nifi.web.api.dto.BulletinQueryDTO;
 import org.apache.nifi.web.api.dto.ClusterDTO;
+import org.apache.nifi.web.api.dto.ComponentDTO;
 import org.apache.nifi.web.api.dto.ComponentHistoryDTO;
 import org.apache.nifi.web.api.dto.ComponentStateDTO;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
@@ -82,12 +88,12 @@ import org.apache.nifi.web.api.dto.CountersSnapshotDTO;
 import org.apache.nifi.web.api.dto.DocumentedTypeDTO;
 import org.apache.nifi.web.api.dto.DropRequestDTO;
 import org.apache.nifi.web.api.dto.DtoFactory;
+import org.apache.nifi.web.api.dto.EntityFactory;
 import org.apache.nifi.web.api.dto.FlowFileDTO;
 import org.apache.nifi.web.api.dto.FlowSnippetDTO;
 import org.apache.nifi.web.api.dto.FunnelDTO;
 import org.apache.nifi.web.api.dto.LabelDTO;
 import org.apache.nifi.web.api.dto.ListingRequestDTO;
-import org.apache.nifi.web.api.dto.NiFiComponentDTO;
 import org.apache.nifi.web.api.dto.NodeDTO;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.PreviousValueDTO;
@@ -107,6 +113,8 @@ import org.apache.nifi.web.api.dto.TemplateDTO;
 import org.apache.nifi.web.api.dto.action.ActionDTO;
 import org.apache.nifi.web.api.dto.action.HistoryDTO;
 import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
+import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceDTO;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceEventDTO;
 import org.apache.nifi.web.api.dto.provenance.ProvenanceOptionsDTO;
@@ -119,6 +127,13 @@ import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
 import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
 import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
+import org.apache.nifi.web.api.entity.ConnectionEntity;
+import org.apache.nifi.web.api.entity.FunnelEntity;
+import org.apache.nifi.web.api.entity.LabelEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupEntity;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
 import org.apache.nifi.web.controller.ControllerFacade;
 import org.apache.nifi.web.dao.ConnectionDAO;
 import org.apache.nifi.web.dao.ControllerServiceDAO;
@@ -131,7 +146,6 @@ import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
 import org.apache.nifi.web.dao.ReportingTaskDAO;
 import org.apache.nifi.web.dao.SnippetDAO;
 import org.apache.nifi.web.dao.TemplateDAO;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.apache.nifi.web.util.SnippetUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -192,6 +206,9 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     // properties
     private NiFiProperties properties;
     private DtoFactory dtoFactory;
+    private EntityFactory entityFactory;
+
+    private Authorizer authorizer;
 
     // -----------------------------------------
     // Verification Operations
@@ -345,43 +362,73 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     // Write Operations
     // -----------------------------------------
     @Override
-    public ConfigurationSnapshot<ConnectionDTO> updateConnection(final Revision revision, final ConnectionDTO connectionDTO) {
+    public UpdateResult<ConnectionEntity> updateConnection(final Revision revision, final ConnectionDTO connectionDTO) {
         // if connection does not exist, then create new connection
         if (connectionDAO.hasConnection(connectionDTO.getId()) == false) {
-            return createConnection(revision, connectionDTO.getParentGroupId(), connectionDTO);
+            return new UpdateResult<>(createConnection(revision, connectionDTO.getParentGroupId(), connectionDTO), true);
         }
 
-        return updateComponent(revision, () -> connectionDAO.updateConnection(connectionDTO), connection -> dtoFactory.createConnectionDto(connection));
+        final Connection connectionNode = connectionDAO.getConnection(connectionDTO.getId());
+        final ConfigurationSnapshot<ConnectionDTO> snapshot = updateComponent(
+            revision,
+            connectionNode,
+            () -> connectionDAO.updateConnection(connectionDTO),
+            connection -> dtoFactory.createConnectionDto(connection));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(connectionNode);
+        return new UpdateResult<>(entityFactory.createConnectionEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy), false);
     }
 
     @Override
-    public ConfigurationSnapshot<ProcessorDTO> updateProcessor(final Revision revision, final ProcessorDTO processorDTO) {
+    public UpdateResult<ProcessorEntity> updateProcessor(final Revision revision, final ProcessorDTO processorDTO) {
         // if processor does not exist, then create new processor
         if (processorDAO.hasProcessor(processorDTO.getId()) == false) {
-            return createProcessor(revision, processorDTO.getParentGroupId(), processorDTO);
+            return new UpdateResult<>(createProcessor(revision, processorDTO.getParentGroupId(), processorDTO), true);
         }
 
-        return updateComponent(revision, () -> processorDAO.updateProcessor(processorDTO), proc -> dtoFactory.createProcessorDto(proc));
+        // get the component, ensure we have access to it, and perform the update request
+        final ProcessorNode processorNode = processorDAO.getProcessor(processorDTO.getId());
+        final ConfigurationSnapshot<ProcessorDTO> snapshot = updateComponent(revision,
+            processorNode,
+            () -> processorDAO.updateProcessor(processorDTO),
+            proc -> dtoFactory.createProcessorDto(proc));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(processorNode);
+        return new UpdateResult<>(entityFactory.createProcessorEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy), false);
     }
 
     @Override
-    public ConfigurationSnapshot<LabelDTO> updateLabel(final Revision revision, final LabelDTO labelDTO) {
+    public UpdateResult<LabelEntity> updateLabel(final Revision revision, final LabelDTO labelDTO) {
         // if label does not exist, then create new label
         if (labelDAO.hasLabel(labelDTO.getId()) == false) {
-            return createLabel(revision, labelDTO.getParentGroupId(), labelDTO);
+            return new UpdateResult<>(createLabel(revision, labelDTO.getParentGroupId(), labelDTO), false);
         }
 
-        return updateComponent(revision, () -> labelDAO.updateLabel(labelDTO), label -> dtoFactory.createLabelDto(label));
+        final Label labelNode = labelDAO.getLabel(labelDTO.getId());
+        final ConfigurationSnapshot<LabelDTO> snapshot = updateComponent(revision,
+            labelNode,
+            () -> labelDAO.updateLabel(labelDTO),
+            label -> dtoFactory.createLabelDto(label));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(labelNode);
+        return new UpdateResult<>(entityFactory.createLabelEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy), false);
     }
 
     @Override
-    public ConfigurationSnapshot<FunnelDTO> updateFunnel(final Revision revision, final FunnelDTO funnelDTO) {
+    public UpdateResult<FunnelEntity> updateFunnel(final Revision revision, final FunnelDTO funnelDTO) {
         // if label does not exist, then create new label
         if (funnelDAO.hasFunnel(funnelDTO.getId()) == false) {
-            return createFunnel(revision, funnelDTO.getParentGroupId(), funnelDTO);
+            return new UpdateResult<>(createFunnel(revision, funnelDTO.getParentGroupId(), funnelDTO), true);
         }
 
-        return updateComponent(revision, () -> funnelDAO.updateFunnel(funnelDTO), funnel -> dtoFactory.createFunnelDto(funnel));
+        final Funnel funnelNode = funnelDAO.getFunnel(funnelDTO.getId());
+        final ConfigurationSnapshot<FunnelDTO> snapshot = updateComponent(revision,
+            funnelNode,
+            () -> funnelDAO.updateFunnel(funnelDTO),
+            funnel -> dtoFactory.createFunnelDto(funnel));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(funnelNode);
+        return new UpdateResult<>(entityFactory.createFunnelEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy), false);
     }
 
 
@@ -398,10 +445,18 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
      *
      * @return A ConfigurationSnapshot that represents the new configuration
      */
-    private <D, C> ConfigurationSnapshot<D> updateComponent(final Revision revision, final Supplier<C> daoUpdate, final Function<C, D> dtoCreation) {
+    private <D, C> ConfigurationSnapshot<D> updateComponent(final Revision revision, final Authorizable authorizable, final Supplier<C> daoUpdate, final Function<C, D>
+        dtoCreation) {
         return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<D>() {
             @Override
             public ConfigurationResult<D> execute() {
+                // ensure write access to the flow
+                authorizable.authorize(authorizer, RequestAction.WRITE);
+
+                // also ensure read access to the flow as the component must be read in order to generate a response
+                authorizable.authorize(authorizer, RequestAction.READ);
+
+                // get the updated component
                 final C component = daoUpdate.get();
 
                 // save updated controller
@@ -439,52 +494,77 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
             return createSnippet(revision, snippetDto);
         }
 
-        return updateComponent(revision,
+        final ProcessGroup processGroup = processGroupDAO.getProcessGroup(snippetDto.getParentGroupId());
+        return updateComponent(
+            revision,
+            processGroup,
             () -> snippetDAO.updateSnippet(snippetDto),
             snippet -> {
-                final SnippetDTO responseSnippetDto = dtoFactory.createSnippetDto(snippet);
-                responseSnippetDto.setContents(snippetUtils.populateFlowSnippet(snippet, false, false));
-                return responseSnippetDto;
+                 return dtoFactory.createSnippetDto(snippet);
             });
     }
 
     @Override
-    public ConfigurationSnapshot<PortDTO> updateInputPort(final Revision revision, final PortDTO inputPortDTO) {
+    public UpdateResult<PortEntity> updateInputPort(final Revision revision, final PortDTO inputPortDTO) {
         // if input port does not exist, then create new input port
         if (inputPortDAO.hasPort(inputPortDTO.getId()) == false) {
-            return createInputPort(revision, inputPortDTO.getParentGroupId(), inputPortDTO);
+            return new UpdateResult<>(createInputPort(revision, inputPortDTO.getParentGroupId(), inputPortDTO), true);
         }
 
-        return updateComponent(revision, () -> inputPortDAO.updatePort(inputPortDTO), port -> dtoFactory.createPortDto(port));
+        final Port inputPortNode = inputPortDAO.getPort(inputPortDTO.getId());
+        final ConfigurationSnapshot<PortDTO> snapshot = updateComponent(revision,
+            inputPortNode,
+            () -> inputPortDAO.updatePort(inputPortDTO),
+            port -> dtoFactory.createPortDto(port));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(inputPortNode);
+        return new UpdateResult<>(entityFactory.createPortEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy), false);
     }
 
     @Override
-    public ConfigurationSnapshot<PortDTO> updateOutputPort(final Revision revision, final PortDTO outputPortDTO) {
+    public UpdateResult<PortEntity> updateOutputPort(final Revision revision, final PortDTO outputPortDTO) {
         // if output port does not exist, then create new output port
         if (outputPortDAO.hasPort(outputPortDTO.getId()) == false) {
-            return createOutputPort(revision, outputPortDTO.getParentGroupId(), outputPortDTO);
+            return new UpdateResult<>(createOutputPort(revision, outputPortDTO.getParentGroupId(), outputPortDTO), true);
         }
 
-        return updateComponent(revision, () -> outputPortDAO.updatePort(outputPortDTO), port -> dtoFactory.createPortDto(port));
+        final Port outputPortNode = outputPortDAO.getPort(outputPortDTO.getId());
+        final ConfigurationSnapshot<PortDTO> snapshot = updateComponent(revision,
+            outputPortNode,
+            () -> outputPortDAO.updatePort(outputPortDTO),
+            port -> dtoFactory.createPortDto(port));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(outputPortNode);
+        return new UpdateResult<>(entityFactory.createPortEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy), false);
     }
 
     @Override
-    public ConfigurationSnapshot<RemoteProcessGroupDTO> updateRemoteProcessGroup(final Revision revision, final RemoteProcessGroupDTO remoteProcessGroupDTO) {
+    public UpdateResult<RemoteProcessGroupEntity> updateRemoteProcessGroup(final Revision revision, final RemoteProcessGroupDTO remoteProcessGroupDTO) {
         // if controller reference does not exist, then create new controller reference
         if (remoteProcessGroupDAO.hasRemoteProcessGroup(remoteProcessGroupDTO.getId()) == false) {
-            return createRemoteProcessGroup(revision, remoteProcessGroupDTO.getParentGroupId(), remoteProcessGroupDTO);
+            return new UpdateResult<>(createRemoteProcessGroup(revision, remoteProcessGroupDTO.getParentGroupId(), remoteProcessGroupDTO), true);
         }
 
-        return updateComponent(revision,
+        final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId());
+        final ConfigurationSnapshot<RemoteProcessGroupDTO> snapshot = updateComponent(
+            revision,
+            remoteProcessGroupNode,
             () -> remoteProcessGroupDAO.updateRemoteProcessGroup(remoteProcessGroupDTO),
             remoteProcessGroup -> dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(remoteProcessGroupNode);
+        final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId());
+        return new UpdateResult<>(entityFactory.createRemoteProcessGroupEntity(snapshot.getConfiguration(), updateRevision, accessPolicy), false);
     }
 
     @Override
     public ConfigurationSnapshot<RemoteProcessGroupPortDTO> updateRemoteProcessGroupInputPort(
             final Revision revision, final String remoteProcessGroupId, final RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) {
 
-        return updateComponent(revision,
+        final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupPortDTO.getGroupId());
+        return updateComponent(
+            revision,
+            remoteProcessGroupNode,
             () -> remoteProcessGroupDAO.updateRemoteProcessGroupInputPort(remoteProcessGroupId, remoteProcessGroupPortDTO),
             remoteGroupPort -> dtoFactory.createRemoteProcessGroupPortDto(remoteGroupPort));
     }
@@ -493,28 +573,42 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     public ConfigurationSnapshot<RemoteProcessGroupPortDTO> updateRemoteProcessGroupOutputPort(
             final Revision revision, final String remoteProcessGroupId, final RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) {
 
-        return updateComponent(revision,
+        final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupPortDTO.getGroupId());
+        return updateComponent(
+            revision,
+            remoteProcessGroupNode,
             () -> remoteProcessGroupDAO.updateRemoteProcessGroupOutputPort(remoteProcessGroupId, remoteProcessGroupPortDTO),
             remoteGroupPort -> dtoFactory.createRemoteProcessGroupPortDto(remoteGroupPort));
     }
 
     @Override
-    public ConfigurationSnapshot<ProcessGroupDTO> updateProcessGroup(final Revision revision, final ProcessGroupDTO processGroupDTO) {
+    public UpdateResult<ProcessGroupEntity> updateProcessGroup(final Revision revision, final ProcessGroupDTO processGroupDTO) {
         // if process group does not exist, then create new process group
         if (processGroupDAO.hasProcessGroup(processGroupDTO.getId()) == false) {
             if (processGroupDTO.getParentGroupId() == null) {
                 throw new IllegalArgumentException("Unable to create the specified process group since the parent group was not specified.");
             } else {
-                return createProcessGroup(processGroupDTO.getParentGroupId(), revision, processGroupDTO);
+                return new UpdateResult<>(createProcessGroup(processGroupDTO.getParentGroupId(), revision, processGroupDTO), true);
             }
         }
 
-        return updateComponent(revision, () -> processGroupDAO.updateProcessGroup(processGroupDTO), processGroup -> dtoFactory.createProcessGroupDto(processGroup));
+        final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(processGroupDTO.getId());
+        final ConfigurationSnapshot<ProcessGroupDTO> snapshot = updateComponent(revision,
+            processGroupNode,
+            () -> processGroupDAO.updateProcessGroup(processGroupDTO),
+            processGroup -> dtoFactory.createProcessGroupDto(processGroup));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(processGroupNode);
+        final RevisionDTO updatedRevision = dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId());
+        return new UpdateResult<>(entityFactory.createProcessGroupEntity(snapshot.getConfiguration(), updatedRevision, accessPolicy), false);
     }
 
     @Override
     public ConfigurationSnapshot<ControllerConfigurationDTO> updateControllerConfiguration(final Revision revision, final ControllerConfigurationDTO controllerConfigurationDTO) {
-        return updateComponent(revision,
+
+        return updateComponent(
+            revision,
+            controllerFacade,
             () -> {
                 // update the controller configuration through the proxy
                 if (controllerConfigurationDTO.getName() != null) {
@@ -611,21 +705,33 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteConnection(final Revision revision, final String connectionId) {
-        return deleteComponent(revision, () -> connectionDAO.deleteConnection(connectionId));
+    public ConnectionEntity deleteConnection(final Revision revision, final String connectionId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            connection,
+            () -> connectionDAO.deleteConnection(connectionId));
+
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(connection);
+        return entityFactory.createConnectionEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
     public DropRequestDTO deleteFlowFileDropRequest(String connectionId, String dropRequestId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
+
         return dtoFactory.createDropRequestDTO(connectionDAO.deleteFlowFileDropRequest(connectionId, dropRequestId));
     }
 
     @Override
     public ListingRequestDTO deleteFlowFileListingRequest(String connectionId, String listingRequestId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
+
         final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.deleteFlowFileListingRequest(connectionId, listingRequestId));
 
         // include whether the source and destination are running
-        final Connection connection = connectionDAO.getConnection(connectionId);
         if (connection.getSource() != null) {
             listRequest.setSourceRunning(connection.getSource().isRunning());
         }
@@ -637,18 +743,36 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteProcessor(final Revision revision, final String processorId) {
-        return deleteComponent(revision, () -> processorDAO.deleteProcessor(processorId));
+    public ProcessorEntity deleteProcessor(final Revision revision, final String processorId) {
+        final ProcessorNode processor = processorDAO.getProcessor(processorId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            processor,
+            () -> processorDAO.deleteProcessor(processorId));
+
+        return entityFactory.createProcessorEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteLabel(final Revision revision, final String labelId) {
-        return deleteComponent(revision, () -> labelDAO.deleteLabel(labelId));
+    public LabelEntity deleteLabel(final Revision revision, final String labelId) {
+        final Label label = labelDAO.getLabel(labelId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            label,
+            () -> labelDAO.deleteLabel(labelId));
+
+        return entityFactory.createLabelEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteFunnel(final Revision revision, final String funnelId) {
-        return deleteComponent(revision, () -> funnelDAO.deleteFunnel(funnelId));
+    public FunnelEntity deleteFunnel(final Revision revision, final String funnelId) {
+        final Funnel funnel = funnelDAO.getFunnel(funnelId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            funnel,
+            () -> funnelDAO.deleteFunnel(funnelId));
+
+        return entityFactory.createFunnelEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     /**
@@ -658,10 +782,13 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
      * @param action the action that deletes the component via the appropriate DAO object
      * @return a ConfigurationSnapshot that represents the new configuration
      */
-    private ConfigurationSnapshot<Void> deleteComponent(final Revision revision, final Runnable action) {
+    private ConfigurationSnapshot<Void> deleteComponent(final Revision revision, final Authorizable authorizable, final Runnable action) {
         return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<Void>() {
             @Override
             public ConfigurationResult<Void> execute() {
+                // ensure access to the component
+                authorizable.authorize(authorizer, RequestAction.WRITE);
+
                 action.run();
 
                 // save the flow
@@ -688,27 +815,55 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
 
     @Override
     public ConfigurationSnapshot<Void> deleteSnippet(final Revision revision, final String snippetId) {
-        return deleteComponent(revision, () -> snippetDAO.deleteSnippet(snippetId));
+        final Snippet snippet = snippetDAO.getSnippet(snippetId);
+        final ProcessGroup processGroup = processGroupDAO.getProcessGroup(snippet.getParentGroupId());
+        return deleteComponent(revision,
+            processGroup,
+            () -> snippetDAO.deleteSnippet(snippetId));
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteInputPort(final Revision revision, final String inputPortId) {
-        return deleteComponent(revision, () -> inputPortDAO.deletePort(inputPortId));
+    public PortEntity deleteInputPort(final Revision revision, final String inputPortId) {
+        final Port port = inputPortDAO.getPort(inputPortId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            port,
+            () -> inputPortDAO.deletePort(inputPortId));
+
+        return entityFactory.createPortEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteOutputPort(final Revision revision, final String outputPortId) {
-        return deleteComponent(revision, () -> outputPortDAO.deletePort(outputPortId));
+    public PortEntity deleteOutputPort(final Revision revision, final String outputPortId) {
+        final Port port = outputPortDAO.getPort(outputPortId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            port,
+            () -> outputPortDAO.deletePort(outputPortId));
+
+        return entityFactory.createPortEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteProcessGroup(final Revision revision, final String groupId) {
-        return deleteComponent(revision, () -> processGroupDAO.deleteProcessGroup(groupId));
+    public ProcessGroupEntity deleteProcessGroup(final Revision revision, final String groupId) {
+        final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            processGroup,
+            () -> processGroupDAO.deleteProcessGroup(groupId));
+
+        return entityFactory.createProcessGroupEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     @Override
-    public ConfigurationSnapshot<Void> deleteRemoteProcessGroup(final Revision revision, final String remoteProcessGroupId) {
-        return deleteComponent(revision, () -> remoteProcessGroupDAO.deleteRemoteProcessGroup(remoteProcessGroupId));
+    public RemoteProcessGroupEntity deleteRemoteProcessGroup(final Revision revision, final String remoteProcessGroupId) {
+        final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
+        final ConfigurationSnapshot<Void> snapshot = deleteComponent(
+            revision,
+            remoteProcessGroup,
+            () -> remoteProcessGroupDAO.deleteRemoteProcessGroup(remoteProcessGroupId));
+
+        return entityFactory.createRemoteProcessGroupEntity(null, dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), null);
     }
 
     @Override
@@ -718,21 +873,34 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<ConnectionDTO> createConnection(final Revision revision, final String groupId, final ConnectionDTO connectionDTO) {
-        return createComponent(revision, connectionDTO, () -> connectionDAO.createConnection(groupId, connectionDTO), connection -> dtoFactory.createConnectionDto(connection));
+    public ConnectionEntity createConnection(final Revision revision, final String groupId, final ConnectionDTO connectionDTO) {
+        final ConfigurationSnapshot<ConnectionDTO> snapshot = createComponent(
+            revision,
+            connectionDTO,
+            () -> connectionDAO.createConnection(groupId, connectionDTO),
+            connection -> dtoFactory.createConnectionDto(connection));
+
+        final Connection connection = connectionDAO.getConnection(connectionDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(connection);
+        return entityFactory.createConnectionEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
     public DropRequestDTO createFlowFileDropRequest(String connectionId, String dropRequestId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
         return dtoFactory.createDropRequestDTO(connectionDAO.createFlowFileDropRequest(connectionId, dropRequestId));
     }
 
     @Override
     public ListingRequestDTO createFlowFileListingRequest(String connectionId, String listingRequestId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
+
+        // create the listing request
         final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.createFlowFileListingRequest(connectionId, listingRequestId));
 
         // include whether the source and destination are running
-        final Connection connection = connectionDAO.getConnection(connectionId);
         if (connection.getSource() != null) {
             listRequest.setSourceRunning(connection.getSource().isRunning());
         }
@@ -744,13 +912,29 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<ProcessorDTO> createProcessor(final Revision revision, final String groupId, final ProcessorDTO processorDTO) {
-        return createComponent(revision, processorDTO, () -> processorDAO.createProcessor(groupId, processorDTO), processor -> dtoFactory.createProcessorDto(processor));
+    public ProcessorEntity createProcessor(final Revision revision, final String groupId, final ProcessorDTO processorDTO) {
+        final ConfigurationSnapshot<ProcessorDTO> snapshot = createComponent(
+            revision,
+            processorDTO,
+            () -> processorDAO.createProcessor(groupId, processorDTO),
+            processor -> dtoFactory.createProcessorDto(processor));
+
+        final ProcessorNode processor = processorDAO.getProcessor(processorDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(processor);
+        return entityFactory.createProcessorEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
-    public ConfigurationSnapshot<LabelDTO> createLabel(final Revision revision, final String groupId, final LabelDTO labelDTO) {
-        return createComponent(revision, labelDTO, () -> labelDAO.createLabel(groupId, labelDTO), label -> dtoFactory.createLabelDto(label));
+    public LabelEntity createLabel(final Revision revision, final String groupId, final LabelDTO labelDTO) {
+        final ConfigurationSnapshot<LabelDTO> snapshot = createComponent(
+            revision,
+            labelDTO,
+            () -> labelDAO.createLabel(groupId, labelDTO),
+            label -> dtoFactory.createLabelDto(label));
+
+        final Label label = labelDAO.getLabel(labelDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(label);
+        return entityFactory.createLabelEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     /**
@@ -766,7 +950,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
      *
      * @return a ConfigurationSnapshot that represents the updated configuration
      */
-    private <D, C> ConfigurationSnapshot<D> createComponent(final Revision revision, final NiFiComponentDTO componentDto,
+    private <D, C> ConfigurationSnapshot<D> createComponent(final Revision revision, final ComponentDTO componentDto,
         final Supplier<C> daoCreation, final Function<C, D> dtoCreation) {
 
         return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<D>() {
@@ -777,6 +961,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
                     componentDto.setId(UUID.randomUUID().toString());
                 }
 
+                // ensure access to process group
+                final ProcessGroup parent = processGroupDAO.getProcessGroup(componentDto.getParentGroupId());
+                parent.authorize(authorizer, RequestAction.WRITE);
+
                 // add the component
                 final C component = daoCreation.get();
 
@@ -801,14 +989,22 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
 
 
     @Override
-    public ConfigurationSnapshot<FunnelDTO> createFunnel(final Revision revision, final String groupId, final FunnelDTO funnelDTO) {
-        return createComponent(revision, funnelDTO, () -> funnelDAO.createFunnel(groupId, funnelDTO), funnel -> dtoFactory.createFunnelDto(funnel));
+    public FunnelEntity createFunnel(final Revision revision, final String groupId, final FunnelDTO funnelDTO) {
+        final ConfigurationSnapshot<FunnelDTO> snapshot = createComponent(
+            revision,
+            funnelDTO,
+            () -> funnelDAO.createFunnel(groupId, funnelDTO),
+            funnel -> dtoFactory.createFunnelDto(funnel));
+
+        final Funnel funnel = funnelDAO.getFunnel(funnelDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(funnel);
+        return entityFactory.createFunnelEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
-    private void validateSnippetContents(final FlowSnippetDTO flowSnippet) {
+    private void validateSnippetContents(final FlowSnippetDTO flow) {
         // validate any processors
-        if (flowSnippet.getProcessors() != null) {
-            for (final ProcessorDTO processorDTO : flowSnippet.getProcessors()) {
+        if (flow.getProcessors() != null) {
+            for (final ProcessorDTO processorDTO : flow.getProcessors()) {
                 final ProcessorNode processorNode = processorDAO.getProcessor(processorDTO.getId());
                 final Collection<ValidationResult> validationErrors = processorNode.getValidationErrors();
                 if (validationErrors != null && !validationErrors.isEmpty()) {
@@ -821,8 +1017,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
             }
         }
 
-        if (flowSnippet.getInputPorts() != null) {
-            for (final PortDTO portDTO : flowSnippet.getInputPorts()) {
+        if (flow.getInputPorts() != null) {
+            for (final PortDTO portDTO : flow.getInputPorts()) {
                 final Port port = inputPortDAO.getPort(portDTO.getId());
                 final Collection<ValidationResult> validationErrors = port.getValidationErrors();
                 if (validationErrors != null && !validationErrors.isEmpty()) {
@@ -835,8 +1031,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
             }
         }
 
-        if (flowSnippet.getOutputPorts() != null) {
-            for (final PortDTO portDTO : flowSnippet.getOutputPorts()) {
+        if (flow.getOutputPorts() != null) {
+            for (final PortDTO portDTO : flow.getOutputPorts()) {
                 final Port port = outputPortDAO.getPort(portDTO.getId());
                 final Collection<ValidationResult> validationErrors = port.getValidationErrors();
                 if (validationErrors != null && !validationErrors.isEmpty()) {
@@ -850,8 +1046,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         }
 
         // get any remote process group issues
-        if (flowSnippet.getRemoteProcessGroups() != null) {
-            for (final RemoteProcessGroupDTO remoteProcessGroupDTO : flowSnippet.getRemoteProcessGroups()) {
+        if (flow.getRemoteProcessGroups() != null) {
+            for (final RemoteProcessGroupDTO remoteProcessGroupDTO : flow.getRemoteProcessGroups()) {
                 final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId());
                 if (remoteProcessGroup.getAuthorizationIssue() != null) {
                     remoteProcessGroupDTO.setAuthorizationIssues(Arrays.asList(remoteProcessGroup.getAuthorizationIssue()));
@@ -861,35 +1057,31 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<FlowSnippetDTO> copySnippet(final Revision revision, final String groupId, final String snippetId, final Double originX, final Double originY) {
-        return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<FlowSnippetDTO>() {
+    public ConfigurationSnapshot<FlowDTO> copySnippet(final Revision revision, final String groupId, final String snippetId, final Double originX, final Double originY) {
+        return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<FlowDTO>() {
             @Override
-            public ConfigurationResult<FlowSnippetDTO> execute() {
+            public ConfigurationResult<FlowDTO> execute() {
                 String id = snippetId;
 
-                // ensure id is set
-                if (StringUtils.isBlank(id)) {
-                    id = UUID.randomUUID().toString();
-                }
-
                 // create the new snippet
-                final FlowSnippetDTO flowSnippet = snippetDAO.copySnippet(groupId, id, originX, originY);
+                final FlowSnippetDTO snippet = snippetDAO.copySnippet(groupId, id, originX, originY);
 
                 // validate the new snippet
-                validateSnippetContents(flowSnippet);
+                validateSnippetContents(snippet);
 
                 // save the flow
                 controllerFacade.save();
 
-                return new ConfigurationResult<FlowSnippetDTO>() {
+                return new ConfigurationResult<FlowDTO>() {
                     @Override
                     public boolean isNew() {
                         return false;
                     }
 
                     @Override
-                    public FlowSnippetDTO getConfiguration() {
-                        return flowSnippet;
+                    public FlowDTO getConfiguration() {
+                        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+                        return dtoFactory.createFlowDto(group, snippet);
                     }
                 };
             }
@@ -909,7 +1101,6 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
                 // add the snippet
                 final Snippet snippet = snippetDAO.createSnippet(snippetDTO);
                 final SnippetDTO responseSnippetDTO = dtoFactory.createSnippetDto(snippet);
-                responseSnippetDTO.setContents(snippetUtils.populateFlowSnippet(snippet, false, false));
 
                 return new ConfigurationResult<SnippetDTO>() {
                     @Override
@@ -927,27 +1118,53 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<PortDTO> createInputPort(final Revision revision, final String groupId, final PortDTO inputPortDTO) {
-        return createComponent(revision, inputPortDTO, () -> inputPortDAO.createPort(groupId, inputPortDTO), port -> dtoFactory.createPortDto(port));
+    public PortEntity createInputPort(final Revision revision, final String groupId, final PortDTO inputPortDTO) {
+        final ConfigurationSnapshot<PortDTO> snapshot = createComponent(
+            revision,
+            inputPortDTO,
+            () -> inputPortDAO.createPort(groupId, inputPortDTO),
+            port -> dtoFactory.createPortDto(port));
+
+        final Port port = inputPortDAO.getPort(inputPortDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(port);
+        return entityFactory.createPortEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
-    public ConfigurationSnapshot<PortDTO> createOutputPort(final Revision revision, final String groupId, final PortDTO outputPortDTO) {
-        return createComponent(revision, outputPortDTO, () -> outputPortDAO.createPort(groupId, outputPortDTO), port -> dtoFactory.createPortDto(port));
+    public PortEntity createOutputPort(final Revision revision, final String groupId, final PortDTO outputPortDTO) {
+        final ConfigurationSnapshot<PortDTO> snapshot = createComponent(
+            revision,
+            outputPortDTO,
+            () -> outputPortDAO.createPort(groupId, outputPortDTO),
+            port -> dtoFactory.createPortDto(port));
+
+        final Port port = outputPortDAO.getPort(outputPortDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(port);
+        return entityFactory.createPortEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
-    public ConfigurationSnapshot<ProcessGroupDTO> createProcessGroup(final String parentGroupId, final Revision revision, final ProcessGroupDTO processGroupDTO) {
-        return createComponent(revision, processGroupDTO,
+    public ProcessGroupEntity createProcessGroup(final String parentGroupId, final Revision revision, final ProcessGroupDTO processGroupDTO) {
+        final ConfigurationSnapshot<ProcessGroupDTO> snapshot = createComponent(revision, processGroupDTO,
             () -> processGroupDAO.createProcessGroup(parentGroupId, processGroupDTO),
             processGroup -> dtoFactory.createProcessGroupDto(processGroup));
+
+        final ProcessGroup processGroup = processGroupDAO.getProcessGroup(processGroupDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(processGroup);
+        return entityFactory.createProcessGroupEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
-    public ConfigurationSnapshot<RemoteProcessGroupDTO> createRemoteProcessGroup(final Revision revision, final String groupId, final RemoteProcessGroupDTO remoteProcessGroupDTO) {
-        return createComponent(revision, remoteProcessGroupDTO,
+    public RemoteProcessGroupEntity createRemoteProcessGroup(final Revision revision, final String groupId, final RemoteProcessGroupDTO remoteProcessGroupDTO) {
+        final ConfigurationSnapshot<RemoteProcessGroupDTO> snapshot = createComponent(
+            revision,
+            remoteProcessGroupDTO,
             () -> remoteProcessGroupDAO.createRemoteProcessGroup(groupId, remoteProcessGroupDTO),
             remoteProcessGroup -> dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup));
+
+        final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId());
+        final AccessPolicyDTO accessPolicy = dtoFactory.createAccessPolicyDto(remoteProcessGroup);
+        return entityFactory.createRemoteProcessGroupEntity(snapshot.getConfiguration(), dtoFactory.createRevisionDTO(snapshot.getVersion(), revision.getClientId()), accessPolicy);
     }
 
     @Override
@@ -993,29 +1210,30 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<FlowSnippetDTO> createTemplateInstance(final Revision revision, final String groupId, final Double originX, final Double originY, final String templateId) {
-        return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<FlowSnippetDTO>() {
+    public ConfigurationSnapshot<FlowDTO> createTemplateInstance(final Revision revision, final String groupId, final Double originX, final Double originY, final String templateId) {
+        return optimisticLockingManager.configureFlow(revision, new ConfigurationRequest<FlowDTO>() {
             @Override
-            public ConfigurationResult<FlowSnippetDTO> execute() {
+            public ConfigurationResult<FlowDTO> execute() {
                 // instantiate the template - there is no need to make another copy of the flow snippet since the actual template
                 // was copied and this dto is only used to instantiate it's components (which as already completed)
-                final FlowSnippetDTO flowSnippet = templateDAO.instantiateTemplate(groupId, originX, originY, templateId);
+                final FlowSnippetDTO snippet = templateDAO.instantiateTemplate(groupId, originX, originY, templateId);
 
                 // validate the new snippet
-                validateSnippetContents(flowSnippet);
+                validateSnippetContents(snippet);
 
                 // save the flow
                 controllerFacade.save();
 
-                return new ConfigurationResult<FlowSnippetDTO>() {
+                return new ConfigurationResult<FlowDTO>() {
                     @Override
                     public boolean isNew() {
                         return false;
                     }
 
                     @Override
-                    public FlowSnippetDTO getConfiguration() {
-                        return flowSnippet;
+                    public FlowDTO getConfiguration() {
+                        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+                        return dtoFactory.createFlowDto(group, snippet);
                     }
                 };
             }
@@ -1367,30 +1585,39 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public Set<ConnectionDTO> getConnections(String groupId) {
-        Set<ConnectionDTO> connectionDtos = new LinkedHashSet<>();
+    public Set<ConnectionEntity> getConnections(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        Set<ConnectionEntity> connections = new LinkedHashSet<>();
         for (Connection connection : connectionDAO.getConnections(groupId)) {
-            connectionDtos.add(dtoFactory.createConnectionDto(connection));
+            connections.add(entityFactory.createConnectionEntity(dtoFactory.createConnectionDto(connection), null, dtoFactory.createAccessPolicyDto(connection)));
         }
-        return connectionDtos;
+        return connections;
     }
 
     @Override
-    public ConnectionDTO getConnection(String connectionId) {
-        return dtoFactory.createConnectionDto(connectionDAO.getConnection(connectionId));
+    public ConnectionEntity getConnection(String connectionId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createConnectionEntity(dtoFactory.createConnectionDto(connectionDAO.getConnection(connectionId)), null, dtoFactory.createAccessPolicyDto(connection));
     }
 
     @Override
     public DropRequestDTO getFlowFileDropRequest(String connectionId, String dropRequestId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
         return dtoFactory.createDropRequestDTO(connectionDAO.getFlowFileDropRequest(connectionId, dropRequestId));
     }
 
     @Override
     public ListingRequestDTO getFlowFileListingRequest(String connectionId, String listingRequestId) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
+
         final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.getFlowFileListingRequest(connectionId, listingRequestId));
 
         // include whether the source and destination are running
-        final Connection connection = connectionDAO.getConnection(connectionId);
         if (connection.getSource() != null) {
             listRequest.setSourceRunning(connection.getSource().isRunning());
         }
@@ -1403,6 +1630,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
 
     @Override
     public FlowFileDTO getFlowFile(String connectionId, String flowFileUuid) {
+        final Connection connection = connectionDAO.getConnection(connectionId);
+        connection.authorize(authorizer, RequestAction.WRITE);
         return dtoFactory.createFlowFileDTO(connectionDAO.getFlowFile(connectionId, flowFileUuid));
     }
 
@@ -1417,12 +1646,15 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public Set<ProcessorDTO> getProcessors(String groupId) {
-        Set<ProcessorDTO> processorDtos = new LinkedHashSet<>();
+    public Set<ProcessorEntity> getProcessors(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        Set<ProcessorEntity> processors = new LinkedHashSet<>();
         for (ProcessorNode processor : processorDAO.getProcessors(groupId)) {
-            processorDtos.add(dtoFactory.createProcessorDto(processor));
+            processors.add(entityFactory.createProcessorEntity(dtoFactory.createProcessorDto(processor), null, dtoFactory.createAccessPolicyDto(processor)));
         }
-        return processorDtos;
+        return processors;
     }
 
     @Override
@@ -1470,10 +1702,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ProcessorDTO getProcessor(String id) {
+    public ProcessorEntity getProcessor(String id) {
         final ProcessorNode processor = processorDAO.getProcessor(id);
-        final ProcessorDTO processorDto = dtoFactory.createProcessorDto(processor);
-        return processorDto;
+        processor.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createProcessorEntity(dtoFactory.createProcessorDto(processor), null, dtoFactory.createAccessPolicyDto(processor));
     }
 
     @Override
@@ -1662,80 +1894,103 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public Set<LabelDTO> getLabels(String groupId) {
-        Set<LabelDTO> labelDtos = new LinkedHashSet<>();
+    public Set<LabelEntity> getLabels(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        Set<LabelEntity> labels = new LinkedHashSet<>();
         for (Label label : labelDAO.getLabels(groupId)) {
-            labelDtos.add(dtoFactory.createLabelDto(label));
+            labels.add(entityFactory.createLabelEntity(dtoFactory.createLabelDto(label), null, dtoFactory.createAccessPolicyDto(label)));
         }
-        return labelDtos;
+        return labels;
     }
 
     @Override
-    public LabelDTO getLabel(String labelId) {
-        return dtoFactory.createLabelDto(labelDAO.getLabel(labelId));
+    public LabelEntity getLabel(String labelId) {
+        final Label label = labelDAO.getLabel(labelId);
+        label.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createLabelEntity(dtoFactory.createLabelDto(label), null, dtoFactory.createAccessPolicyDto(label));
     }
 
     @Override
-    public Set<FunnelDTO> getFunnels(String groupId) {
-        Set<FunnelDTO> funnelDtos = new LinkedHashSet<>();
+    public Set<FunnelEntity> getFunnels(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        final Set<FunnelEntity> funnelDtos = new LinkedHashSet<>();
         for (Funnel funnel : funnelDAO.getFunnels(groupId)) {
-            funnelDtos.add(dtoFactory.createFunnelDto(funnel));
+            funnelDtos.add(entityFactory.createFunnelEntity(dtoFactory.createFunnelDto(funnel), null, dtoFactory.createAccessPolicyDto(funnel)));
         }
         return funnelDtos;
     }
 
     @Override
-    public FunnelDTO getFunnel(String funnelId) {
-        return dtoFactory.createFunnelDto(funnelDAO.getFunnel(funnelId));
+    public FunnelEntity getFunnel(String funnelId) {
+        final Funnel funnel = funnelDAO.getFunnel(funnelId);
+        funnel.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createFunnelEntity(dtoFactory.createFunnelDto(funnel), null, dtoFactory.createAccessPolicyDto(funnel));
     }
 
     @Override
     public SnippetDTO getSnippet(String snippetId) {
         final Snippet snippet = snippetDAO.getSnippet(snippetId);
         final SnippetDTO snippetDTO = dtoFactory.createSnippetDto(snippet);
-        snippetDTO.setContents(snippetUtils.populateFlowSnippet(snippet, false, false));
         return snippetDTO;
     }
 
     @Override
-    public Set<PortDTO> getInputPorts(String groupId) {
-        Set<PortDTO> portDtos = new LinkedHashSet<>();
+    public Set<PortEntity> getInputPorts(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        final Set<PortEntity> ports = new LinkedHashSet<>();
         for (Port port : inputPortDAO.getPorts(groupId)) {
-            portDtos.add(dtoFactory.createPortDto(port));
+            ports.add(entityFactory.createPortEntity(dtoFactory.createPortDto(port), null, dtoFactory.createAccessPolicyDto(port)));
         }
-        return portDtos;
+        return ports;
     }
 
     @Override
-    public Set<PortDTO> getOutputPorts(String groupId) {
-        Set<PortDTO> portDtos = new LinkedHashSet<>();
+    public Set<PortEntity> getOutputPorts(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        Set<PortEntity> ports = new LinkedHashSet<>();
         for (Port port : outputPortDAO.getPorts(groupId)) {
-            portDtos.add(dtoFactory.createPortDto(port));
+            ports.add(entityFactory.createPortEntity(dtoFactory.createPortDto(port), null, dtoFactory.createAccessPolicyDto(port)));
         }
-        return portDtos;
+        return ports;
     }
 
     @Override
-    public Set<ProcessGroupDTO> getProcessGroups(String parentGroupId) {
-        Set<ProcessGroupDTO> processGroupDtos = new LinkedHashSet<>();
-        for (ProcessGroup groups : processGroupDAO.getProcessGroups(parentGroupId)) {
-            processGroupDtos.add(dtoFactory.createProcessGroupDto(groups));
+    public Set<ProcessGroupEntity> getProcessGroups(String parentGroupId) {
+        final ProcessGroup parentGroup = processGroupDAO.getProcessGroup(parentGroupId);
+        parentGroup.authorize(authorizer, RequestAction.READ);
+
+        Set<ProcessGroupEntity> processGroups = new LinkedHashSet<>();
+        for (ProcessGroup group : processGroupDAO.getProcessGroups(parentGroupId)) {
+            processGroups.add(entityFactory.createProcessGroupEntity(dtoFactory.createProcessGroupDto(group), null, dtoFactory.createAccessPolicyDto(group)));
         }
-        return processGroupDtos;
+        return processGroups;
     }
 
     @Override
-    public Set<RemoteProcessGroupDTO> getRemoteProcessGroups(String groupId) {
-        Set<RemoteProcessGroupDTO> remoteProcessGroupDtos = new LinkedHashSet<>();
-        for (RemoteProcessGroup remoteProcessGroup : remoteProcessGroupDAO.getRemoteProcessGroups(groupId)) {
-            remoteProcessGroupDtos.add(dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup));
+    public Set<RemoteProcessGroupEntity> getRemoteProcessGroups(String groupId) {
+        final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
+        group.authorize(authorizer, RequestAction.READ);
+
+        Set<RemoteProcessGroupEntity> remoteProcessGroups = new LinkedHashSet<>();
+        for (RemoteProcessGroup rpg : remoteProcessGroupDAO.getRemoteProcessGroups(groupId)) {
+            remoteProcessGroups.add(entityFactory.createRemoteProcessGroupEntity(dtoFactory.createRemoteProcessGroupDto(rpg), null, dtoFactory.createAccessPolicyDto(rpg)));
         }
-        return remoteProcessGroupDtos;
+        return remoteProcessGroups;
     }
 
     @Override
-    public PortDTO getInputPort(String inputPortId) {
-        return dtoFactory.createPortDto(inputPortDAO.getPort(inputPortId));
+    public PortEntity getInputPort(String inputPortId) {
+        final Port port = inputPortDAO.getPort(inputPortId);
+        port.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createPortEntity(dtoFactory.createPortDto(port), null, dtoFactory.createAccessPolicyDto(port));
     }
 
     @Override
@@ -1744,8 +1999,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public PortDTO getOutputPort(String outputPortId) {
-        return dtoFactory.createPortDto(outputPortDAO.getPort(outputPortId));
+    public PortEntity getOutputPort(String outputPortId) {
+        final Port port = outputPortDAO.getPort(outputPortId);
+        port.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createPortEntity(dtoFactory.createPortDto(port), null, dtoFactory.createAccessPolicyDto(port));
     }
 
     @Override
@@ -1754,8 +2011,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public RemoteProcessGroupDTO getRemoteProcessGroup(String remoteProcessGroupId) {
-        return dtoFactory.createRemoteProcessGroupDto(remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId));
+    public RemoteProcessGroupEntity getRemoteProcessGroup(String remoteProcessGroupId) {
+        final RemoteProcessGroup rpg = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
+        rpg.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createRemoteProcessGroupEntity(dtoFactory.createRemoteProcessGroupDto(rpg), null, dtoFactory.createAccessPolicyDto(rpg));
     }
 
     @Override
@@ -1769,14 +2028,21 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
     }
 
     @Override
-    public ConfigurationSnapshot<ProcessGroupDTO> getProcessGroup(String groupId, final boolean recurse) {
+    public ConfigurationSnapshot<ProcessGroupFlowDTO> getProcessGroupFlow(String groupId, boolean recurse) {
         ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
         Revision revision = optimisticLockingManager.getLastModification().getRevision();
-        ConfigurationSnapshot<ProcessGroupDTO> response = new ConfigurationSnapshot<>(revision.getVersion(), dtoFactory.createProcessGroupDto(processGroup, recurse));
+        ConfigurationSnapshot<ProcessGroupFlowDTO> response = new ConfigurationSnapshot<>(revision.getVersion(), dtoFactory.createProcessGroupFlowDto(processGroup, recurse));
         return response;
     }
 
     @Override
+    public ProcessGroupEntity getProcessGroup(String groupId) {
+        final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
+        processGroup.authorize(authorizer, RequestAction.READ);
+        return entityFactory.createProcessGroupEntity(dtoFactory.createProcessGroupDto(processGroup), null, dtoFactory.createAccessPolicyDto(processGroup));
+    }
+
+    @Override
     public Set<ControllerServiceDTO> getControllerServices() {
         final Set<ControllerServiceDTO> controllerServiceDtos = new LinkedHashSet<>();
         for (ControllerServiceNode controllerService : controllerServiceDAO.getControllerServices()) {
@@ -2014,6 +2280,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         this.dtoFactory = dtoFactory;
     }
 
+    public void setEntityFactory(EntityFactory entityFactory) {
+        this.entityFactory = entityFactory;
+    }
+
     public void setInputPortDAO(PortDAO inputPortDAO) {
         this.inputPortDAO = inputPortDAO;
     }
@@ -2042,6 +2312,10 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
         this.snippetUtils = snippetUtils;
     }
 
+    public void setAuthorizer(Authorizer authorizer) {
+        this.authorizer = authorizer;
+    }
+
     private boolean isPrimaryNode(String nodeId) {
         final Node primaryNode = clusterManager.getPrimaryNode();
         return (primaryNode != null && primaryNode.getNodeId().getId().equals(nodeId));


[09/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
index b8f1350..2eb7bd6 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebConfigurationContext.java
@@ -25,12 +25,14 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
 import org.apache.nifi.admin.service.AuditService;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.controller.ControllerService;
 import org.apache.nifi.controller.ControllerServiceLookup;
 import org.apache.nifi.controller.reporting.ReportingTaskProvider;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.dto.ControllerServiceDTO;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
@@ -40,8 +42,6 @@ import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.ControllerServiceEntity;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
 import org.apache.nifi.web.api.entity.ReportingTaskEntity;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.apache.nifi.web.util.ClientResponseUtils;
 import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
@@ -288,7 +288,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 // create the request URL
                 URI requestUrl;
                 try {
-                    String path = "/nifi-api/cluster/processors/" + URLEncoder.encode(id, "UTF-8");
+                    String path = "/nifi-api/processors/" + URLEncoder.encode(id, "UTF-8");
                     requestUrl = new URI(requestContext.getScheme(), null, "localhost", 0, path, null, null);
                 } catch (final URISyntaxException | UnsupportedEncodingException use) {
                     throw new ClusterRequestException(use);
@@ -309,9 +309,9 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 if (entity == null) {
                     entity = nodeResponse.getClientResponse().getEntity(ProcessorEntity.class);
                 }
-                processor = entity.getProcessor();
+                processor = entity.getComponent();
             } else {
-                processor = serviceFacade.getProcessor(id);
+                processor = serviceFacade.getProcessor(id).getComponent();
             }
 
             // return the processor info
@@ -328,7 +328,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 // create the request URL
                 URI requestUrl;
                 try {
-                    String path = "/nifi-api/cluster/processors/" + URLEncoder.encode(id, "UTF-8");
+                    String path = "/nifi-api/processors/" + URLEncoder.encode(id, "UTF-8");
                     requestUrl = new URI(requestContext.getScheme(), null, "localhost", 0, path, null, null);
                 } catch (final URISyntaxException | UnsupportedEncodingException use) {
                     throw new ClusterRequestException(use);
@@ -345,7 +345,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
 
                 // create the processor dto
                 ProcessorDTO processorDto = new ProcessorDTO();
-                processorEntity.setProcessor(processorDto);
+                processorEntity.setComponent(processorDto);
                 processorDto.setId(id);
 
                 // create the processor configuration with the given annotation data
@@ -368,7 +368,7 @@ public class StandardNiFiWebConfigurationContext implements NiFiWebConfiguration
                 if (entity == null) {
                     entity = nodeResponse.getClientResponse().getEntity(ProcessorEntity.class);
                 }
-                processor = entity.getProcessor();
+                processor = entity.getComponent();
             } else {
                 final ConfigurationSnapshot<ProcessorDTO> response = serviceFacade.setProcessorAnnotationData(revision, id, annotationData);
                 processor = response.getConfiguration();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
index 158dbfa..6180cee 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiWebContext.java
@@ -25,18 +25,18 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
 import org.apache.nifi.admin.service.AuditService;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.controller.ControllerService;
 import org.apache.nifi.controller.ControllerServiceLookup;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.apache.nifi.web.util.ClientResponseUtils;
 import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
@@ -166,7 +166,7 @@ public class StandardNiFiWebContext implements NiFiWebContext {
             // create the request URL
             URI requestUrl;
             try {
-                String path = "/nifi-api/cluster/processors/" + URLEncoder.encode(processorId, "UTF-8");
+                String path = "/nifi-api/processors/" + URLEncoder.encode(processorId, "UTF-8");
                 requestUrl = new URI(config.getScheme(), null, "localhost", 0, path, null, null);
             } catch (final URISyntaxException | UnsupportedEncodingException use) {
                 throw new ClusterRequestException(use);
@@ -200,9 +200,9 @@ public class StandardNiFiWebContext implements NiFiWebContext {
             if (entity == null) {
                 entity = nodeResponse.getClientResponse().getEntity(ProcessorEntity.class);
             }
-            processor = entity.getProcessor();
+            processor = entity.getComponent();
         } else {
-            processor = serviceFacade.getProcessor(processorId);
+            processor = serviceFacade.getProcessor(processorId).getComponent();
         }
 
         // return the processor info
@@ -233,7 +233,7 @@ public class StandardNiFiWebContext implements NiFiWebContext {
             // create the request URL
             URI requestUrl;
             try {
-                String path = "/nifi-api/cluster/processors/" + URLEncoder.encode(processorId, "UTF-8");
+                String path = "/nifi-api/processors/" + URLEncoder.encode(processorId, "UTF-8");
                 requestUrl = new URI(config.getScheme(), null, "localhost", 0, path, null, null);
             } catch (final URISyntaxException | UnsupportedEncodingException use) {
                 throw new ClusterRequestException(use);
@@ -250,7 +250,7 @@ public class StandardNiFiWebContext implements NiFiWebContext {
 
             // create the processor dto
             ProcessorDTO processorDto = new ProcessorDTO();
-            processorEntity.setProcessor(processorDto);
+            processorEntity.setComponent(processorDto);
             processorDto.setId(processorId);
 
             // create the processor configuration with the given annotation data

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/UpdateResult.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/UpdateResult.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/UpdateResult.java
new file mode 100644
index 0000000..66247e3
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/UpdateResult.java
@@ -0,0 +1,40 @@
+/*
+ * 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.web;
+
+/**
+ * Result from an update operation.
+ */
+@SuppressWarnings("serial")
+public class UpdateResult<T>  {
+
+    private final T result;
+    private final boolean isNew;
+
+    public UpdateResult(T result, boolean isNew) {
+        this.result = result;
+        this.isNew = isNew;
+    }
+
+    public T getResult() {
+        return result;
+    }
+
+    public boolean isNew() {
+        return isNew;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
index bb8e701..22ebf29 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/AccessResource.java
@@ -29,8 +29,10 @@ import org.apache.nifi.authentication.LoginCredentials;
 import org.apache.nifi.authentication.LoginIdentityProvider;
 import org.apache.nifi.authentication.exception.IdentityAccessException;
 import org.apache.nifi.authentication.exception.InvalidLoginCredentialsException;
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.security.util.CertificateUtils;
-import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.dto.AccessConfigurationDTO;
@@ -48,12 +50,10 @@ import org.apache.nifi.web.security.kerberos.KerberosService;
 import org.apache.nifi.web.security.otp.OtpService;
 import org.apache.nifi.web.security.token.LoginAuthenticationToken;
 import org.apache.nifi.web.security.token.OtpAuthenticationToken;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.apache.nifi.web.security.x509.X509CertificateExtractor;
 import org.apache.nifi.web.security.x509.X509IdentityProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.authentication.AccountStatusException;
 import org.springframework.security.authentication.AuthenticationServiceException;
 import org.springframework.security.core.Authentication;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
index 966aa29..8026400 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java
@@ -26,6 +26,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.nifi.action.Action;
 import org.apache.nifi.action.FlowChangeAction;
 import org.apache.nifi.action.Operation;
+import org.apache.nifi.authorization.user.NiFiUserDetails;
 import org.apache.nifi.cluster.context.ClusterContext;
 import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
@@ -33,7 +34,6 @@ import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.api.entity.Entity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
-import org.apache.nifi.web.security.user.NiFiUserDetails;
 import org.apache.nifi.web.util.WebUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ClusterResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ClusterResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ClusterResource.java
index 5266632..1dce576 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ClusterResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ClusterResource.java
@@ -24,34 +24,23 @@ import com.wordnik.swagger.annotations.ApiResponse;
 import com.wordnik.swagger.annotations.ApiResponses;
 import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.cluster.node.Node;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.IllegalClusterResourceRequestException;
 import org.apache.nifi.web.NiFiServiceFacade;
-import org.apache.nifi.web.Revision;
 import org.apache.nifi.web.api.dto.ClusterDTO;
 import org.apache.nifi.web.api.dto.NodeDTO;
-import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
-import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.dto.search.NodeSearchResultDTO;
 import org.apache.nifi.web.api.entity.ClusterEntity;
 import org.apache.nifi.web.api.entity.ClusterSearchResultsEntity;
-import org.apache.nifi.web.api.entity.ProcessorEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.api.request.LongParameter;
 
-import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DefaultValue;
-import javax.ws.rs.FormParam;
 import javax.ws.rs.GET;
 import javax.ws.rs.HEAD;
-import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
@@ -233,218 +222,6 @@ public class ClusterResource extends ApplicationResource {
         throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
     }
 
-    /**
-     * Gets the processor.
-     *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
-     * @param id The id of the processor
-     * @return A processorEntity
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-    @Path("/processors/{id}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Gets the specified processor",
-            response = ProcessorEntity.class,
-            authorizations = {
-                @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
-                @Authorization(value = "DFM", type = "ROLE_DFM"),
-                @Authorization(value = "Admin", type = "ROLE_ADMIN")
-            }
-    )
-    @ApiResponses(
-            value = {
-                @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
-                @ApiResponse(code = 401, message = "Client could not be authenticated."),
-                @ApiResponse(code = 403, message = "Client is not authorized to make this request."),
-                @ApiResponse(code = 404, message = "The specified resource could not be found."),
-                @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
-            }
-    )
-    public Response getProcessor(
-            @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
-                    value = "The processor id.",
-                    required = true
-            )
-            @PathParam("id") String id) {
-
-        if (!properties.isClusterManager()) {
-
-            final ProcessorDTO dto = serviceFacade.getProcessor(id);
-
-            // create the revision
-            RevisionDTO revision = new RevisionDTO();
-            revision.setClientId(clientId.getClientId());
-
-            // create entity
-            final ProcessorEntity entity = new ProcessorEntity();
-            entity.setProcessor(dto);
-            entity.setRevision(revision);
-
-            // generate the response
-            return generateOkResponse(entity).build();
-        }
-
-        throw new IllegalClusterResourceRequestException("Only a node can process the request.");
-    }
-
-    /**
-     * Updates the processors annotation data.
-     *
-     * @param httpServletRequest request
-     * @param version The revision is used to verify the client is working with the latest version of the flow.
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
-     * @param processorId The id of the processor.
-     * @param annotationData The annotation data to set.
-     * @return A processorEntity.
-     */
-    @PUT
-    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-    @Path("/processors/{id}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_DFM')")
-    public Response updateProcessor(
-            @Context HttpServletRequest httpServletRequest,
-            @FormParam(VERSION) LongParameter version,
-            @FormParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @PathParam("id") String processorId,
-            @FormParam("annotationData") String annotationData) {
-
-        if (!properties.isClusterManager()) {
-
-            // create the processor configuration with the given annotation data
-            ProcessorConfigDTO configDto = new ProcessorConfigDTO();
-            configDto.setAnnotationData(annotationData);
-
-            // create the processor dto
-            ProcessorDTO processorDto = new ProcessorDTO();
-            processorDto.setId(processorId);
-            processorDto.setConfig(configDto);
-
-            // create the revision
-            RevisionDTO revision = new RevisionDTO();
-            revision.setClientId(clientId.getClientId());
-
-            if (version != null) {
-                revision.setVersion(version.getLong());
-            }
-
-            // create the processor entity
-            ProcessorEntity processorEntity = new ProcessorEntity();
-            processorEntity.setRevision(revision);
-            processorEntity.setProcessor(processorDto);
-
-            return updateProcessor(httpServletRequest, processorId, processorEntity);
-        }
-
-        throw new IllegalClusterResourceRequestException("Only a node can process the request.");
-    }
-
-    /**
-     * Updates the processors annotation data.
-     *
-     * @param httpServletRequest request
-     * @param processorId The id of the processor.
-     * @param processorEntity A processorEntity.
-     * @return A processorEntity.
-     */
-    @PUT
-    @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
-    @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
-    @Path("/processors/{id}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_DFM')")
-    @ApiOperation(
-            value = "Updates processor annotation data",
-            response = ProcessorEntity.class,
-            authorizations = {
-                @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
-                @Authorization(value = "DFM", type = "ROLE_DFM"),
-                @Authorization(value = "Admin", type = "ROLE_ADMIN")
-            }
-    )
-    @ApiResponses(
-            value = {
-                @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
-                @ApiResponse(code = 401, message = "Client could not be authenticated."),
-                @ApiResponse(code = 403, message = "Client is not authorized to make this request."),
-                @ApiResponse(code = 404, message = "The specified resource could not be found."),
-                @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
-            }
-    )
-    public Response updateProcessor(
-            @Context HttpServletRequest httpServletRequest,
-            @ApiParam(
-                    value = "The processor id.",
-                    required = true
-            )
-            @PathParam("id") final String processorId,
-            @ApiParam(
-                    value = "The processor configuration details. The only configuration that will be honored at this endpoint is the processor annontation data.",
-                    required = true
-            )
-            final ProcessorEntity processorEntity) {
-
-        if (!properties.isClusterManager()) {
-
-            if (processorEntity == null || processorEntity.getProcessor() == null) {
-                throw new IllegalArgumentException("Processor details must be specified.");
-            }
-
-            if (processorEntity.getRevision() == null) {
-                throw new IllegalArgumentException("Revision must be specified.");
-            }
-
-            // ensure the same id is being used
-            ProcessorDTO requestProcessorDTO = processorEntity.getProcessor();
-            if (!processorId.equals(requestProcessorDTO.getId())) {
-                throw new IllegalArgumentException(String.format("The processor id (%s) in the request body does "
-                        + "not equal the processor id of the requested resource (%s).", requestProcessorDTO.getId(), processorId));
-            }
-
-            // get the processor configuration
-            ProcessorConfigDTO config = requestProcessorDTO.getConfig();
-            if (config == null) {
-                throw new IllegalArgumentException("Processor configuration must be specified.");
-            }
-
-            // handle expects request (usually from the cluster manager)
-            final String expects = httpServletRequest.getHeader(WebClusterManager.NCM_EXPECTS_HTTP_HEADER);
-            if (expects != null) {
-                serviceFacade.verifyUpdateProcessor(requestProcessorDTO);
-                return generateContinueResponse().build();
-            }
-
-            // update the processor
-            final RevisionDTO revision = processorEntity.getRevision();
-            final ConfigurationSnapshot<ProcessorDTO> controllerResponse = serviceFacade.setProcessorAnnotationData(
-                    new Revision(revision.getVersion(), revision.getClientId()), processorId, config.getAnnotationData());
-
-            // get the processor dto
-            final ProcessorDTO responseProcessorDTO = controllerResponse.getConfiguration();
-
-            // update the revision
-            RevisionDTO updatedRevision = new RevisionDTO();
-            updatedRevision.setClientId(revision.getClientId());
-            updatedRevision.setVersion(controllerResponse.getVersion());
-
-            // generate the response entity
-            final ProcessorEntity entity = new ProcessorEntity();
-            entity.setRevision(updatedRevision);
-            entity.setProcessor(responseProcessorDTO);
-
-            return generateOkResponse(entity).build();
-        }
-
-        throw new IllegalClusterResourceRequestException("Only a node can process the request.");
-    }
-
     // setters
     public void setServiceFacade(NiFiServiceFacade serviceFacade) {
         this.serviceFacade = serviceFacade;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
index 7d5df50..d02c1ef 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectionResource.java
@@ -25,9 +25,9 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.FlowFileSummaryDTO;
 import org.apache.nifi.web.api.dto.ListingRequestDTO;
@@ -72,6 +72,32 @@ public class ConnectionResource extends ApplicationResource {
     /**
      * Populate the URIs for the specified connections.
      *
+     * @param connectionEntities connections
+     * @return dtos
+     */
+    public Set<ConnectionEntity> populateRemainingConnectionEntitiesContent(Set<ConnectionEntity> connectionEntities) {
+        for (ConnectionEntity connectionEntity : connectionEntities) {
+            populateRemainingConnectionEntityContent(connectionEntity);
+        }
+        return connectionEntities;
+    }
+
+    /**
+     * Populate the URIs for the specified connection.
+     *
+     * @param connectionEntity connection
+     * @return dto
+     */
+    public ConnectionEntity populateRemainingConnectionEntityContent(ConnectionEntity connectionEntity) {
+        if (connectionEntity.getComponent() != null) {
+            populateRemainingConnectionContent(connectionEntity.getComponent());
+        }
+        return connectionEntity;
+    }
+
+    /**
+     * Populate the URIs for the specified connections.
+     *
      * @param connections connections
      * @return dtos
      */
@@ -129,7 +155,6 @@ public class ConnectionResource extends ApplicationResource {
     /**
      * Retrieves the specified connection.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the connection.
      * @return A connectionEntity.
      */
@@ -158,11 +183,6 @@ public class ConnectionResource extends ApplicationResource {
     )
     public Response getConnection(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The connection id.",
                     required = true
             )
@@ -174,16 +194,8 @@ public class ConnectionResource extends ApplicationResource {
         }
 
         // get the specified relationship
-        ConnectionDTO connection = serviceFacade.getConnection(id);
-
-        // create the revision
-        RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        ConnectionEntity entity = new ConnectionEntity();
-        entity.setRevision(revision);
-        entity.setConnection(populateRemainingConnectionContent(connection));
+        ConnectionEntity entity = serviceFacade.getConnection(id);
+        populateRemainingConnectionEntityContent(entity);
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();
@@ -230,7 +242,7 @@ public class ConnectionResource extends ApplicationResource {
                     required = true
             ) ConnectionEntity connectionEntity) {
 
-        if (connectionEntity == null || connectionEntity.getConnection() == null) {
+        if (connectionEntity == null || connectionEntity.getComponent() == null) {
             throw new IllegalArgumentException("Connection details must be specified.");
         }
 
@@ -239,7 +251,7 @@ public class ConnectionResource extends ApplicationResource {
         }
 
         // ensure the ids are the same
-        final ConnectionDTO connection = connectionEntity.getConnection();
+        final ConnectionDTO connection = connectionEntity.getComponent();
         if (!id.equals(connection.getId())) {
             throw new IllegalArgumentException(String.format("The connection id "
                     + "(%s) in the request body does not equal the connection id of the "
@@ -265,26 +277,14 @@ public class ConnectionResource extends ApplicationResource {
 
         // update the relationship target
         final RevisionDTO revision = connectionEntity.getRevision();
-        final ConfigurationSnapshot<ConnectionDTO> controllerResponse = serviceFacade.updateConnection(
-                new Revision(revision.getVersion(), revision.getClientId()), connection);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
+        final UpdateResult<ConnectionEntity> updateResult = serviceFacade.updateConnection(new Revision(revision.getVersion(), revision.getClientId()), connection);
 
-        // marshall the target and add the source processor
-        final ConnectionDTO connectionDTO = controllerResponse.getConfiguration();
-        populateRemainingConnectionContent(connectionDTO);
-
-        // create the response entity
-        ConnectionEntity entity = new ConnectionEntity();
-        entity.setRevision(updatedRevision);
-        entity.setConnection(connectionDTO);
+        final ConnectionEntity entity = updateResult.getResult();
+        populateRemainingConnectionEntityContent(entity);
 
         // generate the response
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(connectionDTO.getUri()), entity)).build();
+        if (updateResult.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -357,16 +357,7 @@ public class ConnectionResource extends ApplicationResource {
         }
 
         // delete the connection
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteConnection(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // create the revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(clientId.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // create the response entity
-        final ConnectionEntity entity = new ConnectionEntity();
-        entity.setRevision(updatedRevision);
+        final ConnectionEntity entity = serviceFacade.deleteConnection(new Revision(clientVersion, clientId.getClientId()), id);
 
         // generate the response
         return clusterContext(generateOkResponse(entity)).build();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index 10f4456..8add2bb 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -24,6 +24,7 @@ import com.wordnik.swagger.annotations.ApiResponse;
 import com.wordnik.swagger.annotations.ApiResponses;
 import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.context.ClusterContext;
 import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
 import org.apache.nifi.cluster.manager.NodeResponse;
@@ -31,7 +32,7 @@ import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.cluster.node.Node;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
@@ -50,7 +51,6 @@ import org.apache.nifi.web.api.entity.ProcessGroupEntity;
 import org.apache.nifi.web.api.entity.ReportingTaskEntity;
 import org.apache.nifi.web.api.entity.ReportingTasksEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.apache.nifi.web.util.Availability;
 
 import javax.servlet.http.HttpServletRequest;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
index 849d9f2..3cfae3a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
@@ -152,9 +152,6 @@ public class ControllerServiceResource extends ApplicationResource {
     /**
      * Retrieves the specified controller service.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @param availability Whether the controller service is available on the
      * NCM only (ncm) or on the nodes only (node). If this instance is not
      * clustered all services should use the node availability.
@@ -186,11 +183,6 @@ public class ControllerServiceResource extends ApplicationResource {
     )
     public Response getControllerService(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "Whether the controller service is available on the NCM or nodes. If the NiFi is standalone the availability should be NODE.",
                     allowableValues = "NCM, NODE",
                     required = true
@@ -212,13 +204,8 @@ public class ControllerServiceResource extends ApplicationResource {
         // get the controller service
         final ControllerServiceDTO controllerService = serviceFacade.getControllerService(id);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // create the response entity
         final ControllerServiceEntity entity = new ControllerServiceEntity();
-        entity.setRevision(revision);
         entity.setControllerService(populateRemainingControllerServiceContent(availability, controllerService));
 
         return clusterContext(generateOkResponse(entity)).build();
@@ -227,9 +214,6 @@ public class ControllerServiceResource extends ApplicationResource {
     /**
      * Returns the descriptor for the specified property.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @param availability avail
      * @param id The id of the controller service.
      * @param propertyName The property
@@ -260,11 +244,6 @@ public class ControllerServiceResource extends ApplicationResource {
     )
     public Response getPropertyDescriptor(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "Whether the controller service is available on the NCM or nodes. If the NiFi is standalone the availability should be NODE.",
                     allowableValues = "NCM, NODE",
                     required = true
@@ -296,13 +275,8 @@ public class ControllerServiceResource extends ApplicationResource {
         // get the property descriptor
         final PropertyDescriptorDTO descriptor = serviceFacade.getControllerServicePropertyDescriptor(id, propertyName);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // generate the response entity
         final PropertyDescriptorEntity entity = new PropertyDescriptorEntity();
-        entity.setRevision(revision);
         entity.setPropertyDescriptor(descriptor);
 
         // generate the response
@@ -312,7 +286,6 @@ public class ControllerServiceResource extends ApplicationResource {
     /**
      * Gets the state for a controller service.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param availability Whether the controller service is available on the
      * NCM only (ncm) or on the nodes only (node). If this instance is not
      * clustered all services should use the node availability.
@@ -342,11 +315,6 @@ public class ControllerServiceResource extends ApplicationResource {
     )
     public Response getState(
         @ApiParam(
-            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-            required = false
-        )
-        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-        @ApiParam(
             value = "Whether the controller service is available on the NCM or nodes. If the NiFi is standalone the availability should be NODE.",
             allowableValues = "NCM, NODE",
             required = true
@@ -368,13 +336,8 @@ public class ControllerServiceResource extends ApplicationResource {
         // get the component state
         final ComponentStateDTO state = serviceFacade.getControllerServiceState(id);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // generate the response entity
         final ComponentStateEntity entity = new ComponentStateEntity();
-        entity.setRevision(revision);
         entity.setComponentState(state);
 
         // generate the response
@@ -465,9 +428,6 @@ public class ControllerServiceResource extends ApplicationResource {
     /**
      * Retrieves the references of the specified controller service.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @param availability Whether the controller service is available on the
      * NCM only (ncm) or on the nodes only (node). If this instance is not
      * clustered all services should use the node availability.
@@ -499,11 +459,6 @@ public class ControllerServiceResource extends ApplicationResource {
     )
     public Response getControllerServiceReferences(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "Whether the controller service is available on the NCM or nodes. If the NiFi is standalone the availability should be NODE.",
                     allowableValues = "NCM, NODE",
                     required = true
@@ -525,13 +480,8 @@ public class ControllerServiceResource extends ApplicationResource {
         // get the controller service
         final Set<ControllerServiceReferencingComponentDTO> controllerServiceReferences = serviceFacade.getControllerServiceReferencingComponents(id);
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
         // create the response entity
         final ControllerServiceReferencingComponentsEntity entity = new ControllerServiceReferencingComponentsEntity();
-        entity.setRevision(revision);
         entity.setControllerServiceReferencingComponents(controllerServiceReferences);
 
         return clusterContext(generateOkResponse(entity)).build();

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
index e1beecc..337cb67 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java
@@ -24,20 +24,32 @@ import com.wordnik.swagger.annotations.ApiResponse;
 import com.wordnik.swagger.annotations.ApiResponses;
 import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AuthorizationRequest;
+import org.apache.nifi.authorization.AuthorizationResult;
+import org.apache.nifi.authorization.AuthorizationResult.Result;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.cluster.node.Node;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
-import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.api.dto.AboutDTO;
 import org.apache.nifi.web.api.dto.BannerDTO;
 import org.apache.nifi.web.api.dto.BulletinBoardDTO;
 import org.apache.nifi.web.api.dto.BulletinQueryDTO;
 import org.apache.nifi.web.api.dto.ControllerConfigurationDTO;
+import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
+import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
 import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
 import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
 import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
@@ -58,6 +70,8 @@ import org.apache.nifi.web.api.entity.Entity;
 import org.apache.nifi.web.api.entity.IdentityEntity;
 import org.apache.nifi.web.api.entity.PortStatusEntity;
 import org.apache.nifi.web.api.entity.PrioritizerTypesEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
 import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
 import org.apache.nifi.web.api.entity.ProcessorTypesEntity;
@@ -69,7 +83,6 @@ import org.apache.nifi.web.api.request.BulletinBoardPatternParameter;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.IntegerParameter;
 import org.apache.nifi.web.api.request.LongParameter;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DefaultValue;
@@ -92,7 +105,7 @@ import java.util.Set;
 @Path("/flow")
 @Api(
     value = "/flow",
-    description = "Endpoint for accessing the flow structure and component statuses."
+    description = "Endpoint for accessing the flow structure and component status."
 )
 public class FlowResource extends ApplicationResource {
 
@@ -101,10 +114,164 @@ public class FlowResource extends ApplicationResource {
     private NiFiServiceFacade serviceFacade;
     private WebClusterManager clusterManager;
     private NiFiProperties properties;
+    private Authorizer authorizer;
 
     @Context
     private ResourceContext resourceContext;
 
+    private ProcessorResource processorResource;
+    private InputPortResource inputPortResource;
+    private OutputPortResource outputPortResource;
+    private FunnelResource funnelResource;
+    private LabelResource labelResource;
+    private RemoteProcessGroupResource remoteProcessGroupResource;
+    private ConnectionResource connectionResource;
+    private TemplateResource templateResource;
+    private ProcessGroupResource processGroupResource;
+    private ControllerServiceResource controllerServiceResource;
+
+    /**
+     * Populates the remaining fields in the specified process group.
+     *
+     * @param flow group
+     * @return group dto
+     */
+    private ProcessGroupFlowDTO populateRemainingFlowContent(ProcessGroupFlowDTO flow) {
+        FlowDTO flowStructure = flow.getFlow();
+
+        // populate the remaining fields for the processors, connections, process group refs, remote process groups, and labels if appropriate
+        if (flowStructure != null) {
+            populateRemainingFlowStructure(flowStructure);
+        }
+
+        // set the process group uri
+        flow.setUri(generateResourceUri("flow", "process-groups",  flow.getId()));
+
+        return flow;
+    }
+
+    /**
+     * Populates the remaining content of the specified snippet.
+     */
+    private FlowDTO populateRemainingFlowStructure(FlowDTO flowStructure) {
+        processorResource.populateRemainingProcessorEntitiesContent(flowStructure.getProcessors());
+        connectionResource.populateRemainingConnectionEntitiesContent(flowStructure.getConnections());
+        inputPortResource.populateRemainingInputPortEntitiesContent(flowStructure.getInputPorts());
+        outputPortResource.populateRemainingOutputPortEntitiesContent(flowStructure.getOutputPorts());
+        remoteProcessGroupResource.populateRemainingRemoteProcessGroupEntitiesContent(flowStructure.getRemoteProcessGroups());
+        funnelResource.populateRemainingFunnelEntitiesContent(flowStructure.getFunnels());
+        labelResource.populateRemainingLabelEntitiesContent(flowStructure.getLabels());
+        processGroupResource.populateRemainingProcessGroupEntitiesContent(flowStructure.getProcessGroups());
+
+        // go through each process group child and populate its uri
+        for (final ProcessGroupEntity processGroupEntity : flowStructure.getProcessGroups()) {
+            final ProcessGroupDTO processGroup = processGroupEntity.getComponent();
+            if (processGroup != null) {
+                processGroup.setContents(null);
+            }
+        }
+
+        return flowStructure;
+    }
+
+    private void authorizeFlow() {
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+        final AuthorizationRequest request = new AuthorizationRequest.Builder()
+            .resource(ResourceFactory.getFlowResource())
+            .identity(user.getIdentity())
+            .anonymous(user.isAnonymous())
+            .accessAttempt(true)
+            .action(RequestAction.READ)
+            .build();
+
+        final AuthorizationResult result = authorizer.authorize(request);
+        if (!Result.Approved.equals(result.getResult())) {
+            final String message = StringUtils.isNotBlank(result.getExplanation()) ? result.getExplanation() : "Access is denied";
+            throw new AccessDeniedException(message);
+        }
+    }
+
+    // ----
+    // flow
+    // ----
+
+    /**
+     * Retrieves the contents of the specified group.
+     *
+     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
+     * @param recursive Optional recursive flag that defaults to false. If set to true, all descendent groups and their content will be included if the verbose flag is also set to true.
+     * @param groupId The id of the process group.
+     * @return A processGroupEntity.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("process-groups/{id}")
+    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @ApiOperation(
+        value = "Gets a process group",
+        response = ProcessGroupEntity.class,
+        authorizations = {
+            @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
+            @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
+            @Authorization(value = "Administrator", type = "ROLE_ADMIN")
+        }
+    )
+    @ApiResponses(
+        value = {
+            @ApiResponse(code = 400, message = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."),
+            @ApiResponse(code = 401, message = "Client could not be authenticated."),
+            @ApiResponse(code = 403, message = "Client is not authorized to make this request."),
+            @ApiResponse(code = 404, message = "The specified resource could not be found."),
+            @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.")
+        }
+    )
+    public Response getFlow(
+        @ApiParam(
+            value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
+            required = false
+        )
+        @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
+        @ApiParam(
+            value = "The process group id.",
+            required = false
+        )
+        @PathParam("id") String groupId,
+        @ApiParam(
+            value = "Whether the response should contain all encapsulated components or just the immediate children.",
+            required = false
+        )
+        @QueryParam("recursive") @DefaultValue(RECURSIVE) Boolean recursive) {
+
+        authorizeFlow();
+
+        // replicate if cluster manager
+        if (properties.isClusterManager()) {
+            return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
+        }
+
+        // get this process group contents
+        final ConfigurationSnapshot<ProcessGroupFlowDTO> controllerResponse = serviceFacade.getProcessGroupFlow(groupId, recursive);
+        final ProcessGroupFlowDTO flow = controllerResponse.getConfiguration();
+
+        // create the revision
+        final RevisionDTO revision = new RevisionDTO();
+        revision.setClientId(clientId.getClientId());
+        revision.setVersion(controllerResponse.getVersion());
+
+        // create the response entity
+        final ProcessGroupFlowEntity processGroupEntity = new ProcessGroupFlowEntity();
+        processGroupEntity.setRevision(revision);
+        processGroupEntity.setProcessGroupFlow(populateRemainingFlowContent(flow));
+
+        return clusterContext(generateOkResponse(processGroupEntity)).build();
+    }
+
+    // ------
+    // search
+    // ------
+
     /**
      * Performs a search request in this flow.
      *
@@ -134,6 +301,8 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response searchFlow(@QueryParam("q") @DefaultValue(StringUtils.EMPTY) String value) {
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -186,6 +355,8 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response getRevision() {
+        authorizeFlow();
+
         // create the current revision
         final RevisionDTO revision = serviceFacade.getRevision();
 
@@ -232,6 +403,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow();
+
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
         }
@@ -327,6 +500,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow();
+
         // get the banner from the properties - will come from the NCM when clustered
         final String bannerText = properties.getBannerText();
 
@@ -383,6 +558,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -442,6 +619,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam("serviceType") String serviceType) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -495,6 +674,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -548,6 +729,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -601,6 +784,8 @@ public class FlowResource extends ApplicationResource {
             )
             @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -708,6 +893,8 @@ public class FlowResource extends ApplicationResource {
         )
         @QueryParam("limit") IntegerParameter limit) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -807,6 +994,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
             throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
@@ -907,6 +1096,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
             throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
@@ -1007,6 +1198,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
             throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
@@ -1107,6 +1300,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
             throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
@@ -1216,6 +1411,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String groupId) {
 
+        authorizeFlow();
+
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
             throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
@@ -1337,6 +1534,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
             throw new IllegalArgumentException("Nodewise requests cannot be directed at a specific node.");
@@ -1431,6 +1630,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -1490,6 +1691,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String groupId) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -1553,6 +1756,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -1616,6 +1821,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) {
 
+        authorizeFlow();
+
         // replicate if cluster manager
         if (properties.isClusterManager()) {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
@@ -1646,6 +1853,50 @@ public class FlowResource extends ApplicationResource {
         this.clusterManager = clusterManager;
     }
 
+    public void setProcessorResource(ProcessorResource processorResource) {
+        this.processorResource = processorResource;
+    }
+
+    public void setInputPortResource(InputPortResource inputPortResource) {
+        this.inputPortResource = inputPortResource;
+    }
+
+    public void setOutputPortResource(OutputPortResource outputPortResource) {
+        this.outputPortResource = outputPortResource;
+    }
+
+    public void setFunnelResource(FunnelResource funnelResource) {
+        this.funnelResource = funnelResource;
+    }
+
+    public void setLabelResource(LabelResource labelResource) {
+        this.labelResource = labelResource;
+    }
+
+    public void setRemoteProcessGroupResource(RemoteProcessGroupResource remoteProcessGroupResource) {
+        this.remoteProcessGroupResource = remoteProcessGroupResource;
+    }
+
+    public void setConnectionResource(ConnectionResource connectionResource) {
+        this.connectionResource = connectionResource;
+    }
+
+    public void setTemplateResource(TemplateResource templateResource) {
+        this.templateResource = templateResource;
+    }
+
+    public void setProcessGroupResource(ProcessGroupResource processGroupResource) {
+        this.processGroupResource = processGroupResource;
+    }
+
+    public void setControllerServiceResource(ControllerServiceResource controllerServiceResource) {
+        this.controllerServiceResource = controllerServiceResource;
+    }
+
+    public void setAuthorizer(Authorizer authorizer) {
+        this.authorizer = authorizer;
+    }
+
     public void setProperties(NiFiProperties properties) {
         this.properties = properties;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
index 1c4a0ea..b3a050f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FunnelResource.java
@@ -25,9 +25,9 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.FunnelDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.FunnelEntity;
@@ -74,6 +74,32 @@ public class FunnelResource extends ApplicationResource {
     /**
      * Populates the uri for the specified funnels.
      *
+     * @param funnelEntities funnels
+     * @return funnels
+     */
+    public Set<FunnelEntity> populateRemainingFunnelEntitiesContent(Set<FunnelEntity> funnelEntities) {
+        for (FunnelEntity funnelEntity : funnelEntities) {
+            populateRemainingFunnelEntityContent(funnelEntity);
+        }
+        return funnelEntities;
+    }
+
+    /**
+     * Populates the uri for the specified funnel.
+     *
+     * @param funnelEntity funnel
+     * @return funnel
+     */
+    public FunnelEntity populateRemainingFunnelEntityContent(FunnelEntity funnelEntity) {
+        if (funnelEntity.getComponent() != null) {
+            populateRemainingFunnelContent(funnelEntity.getComponent());
+        }
+        return funnelEntity;
+    }
+
+    /**
+     * Populates the uri for the specified funnels.
+     *
      * @param funnels funnels
      * @return funnels
      */
@@ -96,9 +122,6 @@ public class FunnelResource extends ApplicationResource {
     /**
      * Retrieves the specified funnel.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @param id The id of the funnel to retrieve
      * @return A funnelEntity.
      */
@@ -127,11 +150,6 @@ public class FunnelResource extends ApplicationResource {
     )
     public Response getFunnel(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The funnel id.",
                     required = true
             )
@@ -143,16 +161,8 @@ public class FunnelResource extends ApplicationResource {
         }
 
         // get the funnel
-        final FunnelDTO funnel = serviceFacade.getFunnel(id);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final FunnelEntity entity = new FunnelEntity();
-        entity.setRevision(revision);
-        entity.setFunnel(populateRemainingFunnelContent(funnel));
+        final FunnelEntity entity = serviceFacade.getFunnel(id);
+        populateRemainingFunnelEntityContent(entity);
 
         return clusterContext(generateOkResponse(entity)).build();
     }
@@ -198,7 +208,7 @@ public class FunnelResource extends ApplicationResource {
                     required = true
             ) FunnelEntity funnelEntity) {
 
-        if (funnelEntity == null || funnelEntity.getFunnel() == null) {
+        if (funnelEntity == null || funnelEntity.getComponent() == null) {
             throw new IllegalArgumentException("Funnel details must be specified.");
         }
 
@@ -207,7 +217,7 @@ public class FunnelResource extends ApplicationResource {
         }
 
         // ensure the ids are the same
-        final FunnelDTO requestFunnelDTO = funnelEntity.getFunnel();
+        final FunnelDTO requestFunnelDTO = funnelEntity.getComponent();
         if (!id.equals(requestFunnelDTO.getId())) {
             throw new IllegalArgumentException(String.format("The funnel id (%s) in the request body does not equal the "
                     + "funnel id of the requested resource (%s).", requestFunnelDTO.getId(), id));
@@ -231,25 +241,15 @@ public class FunnelResource extends ApplicationResource {
 
         // update the funnel
         final RevisionDTO revision = funnelEntity.getRevision();
-        final ConfigurationSnapshot<FunnelDTO> controllerResponse = serviceFacade.updateFunnel(
+        final UpdateResult<FunnelEntity> updateResult = serviceFacade.updateFunnel(
                 new Revision(revision.getVersion(), revision.getClientId()), requestFunnelDTO);
 
         // get the results
-        final FunnelDTO responseFunnelDTO = controllerResponse.getConfiguration();
-        populateRemainingFunnelContent(responseFunnelDTO);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final FunnelEntity entity = new FunnelEntity();
-        entity.setRevision(updatedRevision);
-        entity.setFunnel(responseFunnelDTO);
+        final FunnelEntity entity = updateResult.getResult();
+        populateRemainingFunnelEntityContent(entity);
 
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(responseFunnelDTO.getUri()), entity)).build();
+        if (updateResult.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -325,17 +325,7 @@ public class FunnelResource extends ApplicationResource {
         }
 
         // delete the specified funnel
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteFunnel(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final FunnelEntity entity = new FunnelEntity();
-        entity.setRevision(revision);
-
+        final FunnelEntity entity = serviceFacade.deleteFunnel(new Revision(clientVersion, clientId.getClientId()), id);
         return clusterContext(generateOkResponse(entity)).build();
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
index 1d0629f..a378ec3 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/InputPortResource.java
@@ -25,12 +25,12 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
-import org.apache.nifi.web.api.entity.InputPortEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.LongParameter;
 
@@ -70,6 +70,32 @@ public class InputPortResource extends ApplicationResource {
     /**
      * Populates the uri for the specified input ports.
      *
+     * @param inputPortEntites ports
+     * @return ports
+     */
+    public Set<PortEntity> populateRemainingInputPortEntitiesContent(Set<PortEntity> inputPortEntites) {
+        for (PortEntity inputPortEntity : inputPortEntites) {
+            populateRemainingInputPortEntityContent(inputPortEntity);
+        }
+        return inputPortEntites;
+    }
+
+        /**
+         * Populates the uri for the specified input port.
+         *
+         * @param inputPortEntity port
+         * @return ports
+         */
+    public PortEntity populateRemainingInputPortEntityContent(PortEntity inputPortEntity) {
+        if (inputPortEntity.getComponent() != null) {
+            populateRemainingInputPortContent(inputPortEntity.getComponent());
+        }
+        return inputPortEntity;
+    }
+
+    /**
+     * Populates the uri for the specified input ports.
+     *
      * @param inputPorts ports
      * @return ports
      */
@@ -92,7 +118,6 @@ public class InputPortResource extends ApplicationResource {
     /**
      * Retrieves the specified input port.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the input port to retrieve
      * @return A inputPortEntity.
      */
@@ -103,7 +128,7 @@ public class InputPortResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
     @ApiOperation(
             value = "Gets an input port",
-            response = InputPortEntity.class,
+            response = PortEntity.class,
             authorizations = {
                 @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
                 @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@@ -121,11 +146,6 @@ public class InputPortResource extends ApplicationResource {
     )
     public Response getInputPort(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The input port id.",
                     required = true
             )
@@ -137,16 +157,8 @@ public class InputPortResource extends ApplicationResource {
         }
 
         // get the port
-        final PortDTO port = serviceFacade.getInputPort(id);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final InputPortEntity entity = new InputPortEntity();
-        entity.setRevision(revision);
-        entity.setInputPort(populateRemainingInputPortContent(port));
+        final PortEntity entity = serviceFacade.getInputPort(id);
+        populateRemainingInputPortEntityContent(entity);
 
         return clusterContext(generateOkResponse(entity)).build();
     }
@@ -166,7 +178,7 @@ public class InputPortResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
             value = "Updates an input port",
-            response = InputPortEntity.class,
+            response = PortEntity.class,
             authorizations = {
                 @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
             }
@@ -190,9 +202,9 @@ public class InputPortResource extends ApplicationResource {
             @ApiParam(
                     value = "The input port configuration details.",
                     required = true
-            ) InputPortEntity portEntity) {
+            ) PortEntity portEntity) {
 
-        if (portEntity == null || portEntity.getInputPort() == null) {
+        if (portEntity == null || portEntity.getComponent() == null) {
             throw new IllegalArgumentException("Input port details must be specified.");
         }
 
@@ -201,7 +213,7 @@ public class InputPortResource extends ApplicationResource {
         }
 
         // ensure the ids are the same
-        final PortDTO requestPortDTO = portEntity.getInputPort();
+        final PortDTO requestPortDTO = portEntity.getComponent();
         if (!id.equals(requestPortDTO.getId())) {
             throw new IllegalArgumentException(String.format("The input port id (%s) in the request body does not equal the "
                     + "input port id of the requested resource (%s).", requestPortDTO.getId(), id));
@@ -226,25 +238,15 @@ public class InputPortResource extends ApplicationResource {
 
         // update the input port
         final RevisionDTO revision = portEntity.getRevision();
-        final ConfigurationSnapshot<PortDTO> controllerResponse = serviceFacade.updateInputPort(
+        final UpdateResult<PortEntity> updateResult = serviceFacade.updateInputPort(
                 new Revision(revision.getVersion(), revision.getClientId()), requestPortDTO);
 
-        // get the results
-        final PortDTO responsePortDTO = controllerResponse.getConfiguration();
-        populateRemainingInputPortContent(responsePortDTO);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
         // build the response entity
-        final InputPortEntity entity = new InputPortEntity();
-        entity.setRevision(updatedRevision);
-        entity.setInputPort(responsePortDTO);
+        final PortEntity entity = updateResult.getResult();
+        populateRemainingInputPortEntityContent(entity);
 
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(responsePortDTO.getUri()), entity)).build();
+        if (updateResult.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -266,7 +268,7 @@ public class InputPortResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
             value = "Deletes an input port",
-            response = InputPortEntity.class,
+            response = PortEntity.class,
             authorizations = {
                 @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
             }
@@ -317,17 +319,7 @@ public class InputPortResource extends ApplicationResource {
         }
 
         // delete the specified input port
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteInputPort(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final InputPortEntity entity = new InputPortEntity();
-        entity.setRevision(revision);
-
+        final PortEntity entity = serviceFacade.deleteInputPort(new Revision(clientVersion, clientId.getClientId()), id);
         return clusterContext(generateOkResponse(entity)).build();
     }
 


[11/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserUtils.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserUtils.java
new file mode 100644
index 0000000..840df69
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/user/NiFiUserUtils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.authorization.user;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * Utility methods for retrieving information about the current application user.
+ *
+ */
+public final class NiFiUserUtils {
+
+    /**
+     * Returns the current NiFiUser or null if the current user is not a NiFiUser.
+     *
+     * @return user
+     */
+    public static NiFiUser getNiFiUser() {
+        NiFiUser user = null;
+
+        // obtain the principal in the current authentication
+        final SecurityContext context = SecurityContextHolder.getContext();
+        final Authentication authentication = context.getAuthentication();
+        if (authentication != null) {
+            Object principal = authentication.getPrincipal();
+            if (principal instanceof NiFiUserDetails) {
+                user = ((NiFiUserDetails) principal).getNiFiUser();
+            }
+        }
+
+        return user;
+    }
+
+    public static String getNiFiUserName() {
+        // get the nifi user to extract the username
+        NiFiUser user = NiFiUserUtils.getNiFiUser();
+        if (user == null) {
+            return "unknown";
+        } else {
+            return user.getUserName();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/resources/nifi-framework-authorization-context.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/resources/nifi-framework-authorization-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/resources/nifi-framework-authorization-context.xml
new file mode 100644
index 0000000..71bf684
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/resources/nifi-framework-authorization-context.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<beans default-lazy-init="true"
+       xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
+
+    <!-- user/entity authorizer -->
+    <bean id="authorizer" class="org.apache.nifi.authorization.AuthorizerFactoryBean">
+        <property name="properties" ref="nifiProperties"/>
+    </bean>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/xsd/authorizers.xsd
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/xsd/authorizers.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/xsd/authorizers.xsd
new file mode 100644
index 0000000..4b68b00
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/xsd/authorizers.xsd
@@ -0,0 +1,49 @@
+<?xml version="1.0"?>
+<!--
+  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.
+-->
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- role -->
+    <xs:complexType name="Authorizer">
+        <xs:sequence>
+            <xs:element name="identifier" type="NonEmptyStringType"/>
+            <xs:element name="class" type="NonEmptyStringType"/>
+            <xs:element name="property" type="Property" minOccurs="0" maxOccurs="unbounded" />
+        </xs:sequence>
+    </xs:complexType>
+
+    <!-- Name/Value properties-->
+    <xs:complexType name="Property">
+        <xs:simpleContent>
+            <xs:extension base="xs:string">
+                <xs:attribute name="name" type="NonEmptyStringType"></xs:attribute>
+            </xs:extension>
+        </xs:simpleContent>
+    </xs:complexType>
+
+    <xs:simpleType name="NonEmptyStringType">
+        <xs:restriction base="xs:string">
+            <xs:minLength value="1"/>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <!-- users -->
+    <xs:element name="authorizers">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="authorizer" type="Authorizer" minOccurs="0" maxOccurs="unbounded"/>
+            </xs:sequence>
+        </xs:complexType>
+    </xs:element>
+</xs:schema>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
index d4ea1d4..88da5ff 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster/src/main/java/org/apache/nifi/cluster/manager/impl/WebClusterManager.java
@@ -3071,7 +3071,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
 
         if (hasSuccessfulClientResponse && isProcessorEndpoint(uri, method)) {
             final ProcessorEntity responseEntity = clientResponse.getClientResponse().getEntity(ProcessorEntity.class);
-            final ProcessorDTO processor = responseEntity.getProcessor();
+            final ProcessorDTO processor = responseEntity.getComponent();
 
             final Map<NodeIdentifier, ProcessorDTO> processorMap = new HashMap<>();
             for (final NodeResponse nodeResponse : updatedNodesMap.values()) {
@@ -3080,7 +3080,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
                 }
 
                 final ProcessorEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(ProcessorEntity.class);
-                final ProcessorDTO nodeProcessor = nodeResponseEntity.getProcessor();
+                final ProcessorDTO nodeProcessor = nodeResponseEntity.getComponent();
                 processorMap.put(nodeResponse.getNodeId(), nodeProcessor);
             }
 
@@ -3088,7 +3088,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
             clientResponse = new NodeResponse(clientResponse, responseEntity);
         } else if (hasSuccessfulClientResponse && isProcessorsEndpoint(uri, method)) {
             final ProcessorsEntity responseEntity = clientResponse.getClientResponse().getEntity(ProcessorsEntity.class);
-            final Set<ProcessorDTO> processors = responseEntity.getProcessors();
+            final Set<ProcessorEntity> processors = responseEntity.getProcessors();
 
             final Map<String, Map<NodeIdentifier, ProcessorDTO>> processorMap = new HashMap<>();
             for (final NodeResponse nodeResponse : updatedNodesMap.values()) {
@@ -3097,31 +3097,31 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
                 }
 
                 final ProcessorsEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(ProcessorsEntity.class);
-                final Set<ProcessorDTO> nodeProcessors = nodeResponseEntity.getProcessors();
+                final Set<ProcessorEntity> nodeProcessors = nodeResponseEntity.getProcessors();
 
-                for (final ProcessorDTO nodeProcessor : nodeProcessors) {
-                    Map<NodeIdentifier, ProcessorDTO> innerMap = processorMap.get(nodeProcessor.getId());
+                for (final ProcessorEntity nodeProcessor : nodeProcessors) {
+                    Map<NodeIdentifier, ProcessorDTO> innerMap = processorMap.get(nodeProcessor.getComponent().getId());
                     if (innerMap == null) {
                         innerMap = new HashMap<>();
-                        processorMap.put(nodeProcessor.getId(), innerMap);
+                        processorMap.put(nodeProcessor.getComponent().getId(), innerMap);
                     }
 
-                    innerMap.put(nodeResponse.getNodeId(), nodeProcessor);
+                    innerMap.put(nodeResponse.getNodeId(), nodeProcessor.getComponent());
                 }
             }
 
-            for (final ProcessorDTO processor : processors) {
-                final String procId = processor.getId();
+            for (final ProcessorEntity processor : processors) {
+                final String procId = processor.getComponent().getId();
                 final Map<NodeIdentifier, ProcessorDTO> mergeMap = processorMap.get(procId);
 
-                mergeProcessorValidationErrors(processor, mergeMap);
+                mergeProcessorValidationErrors(processor.getComponent(), mergeMap);
             }
 
             // create a new client response
             clientResponse = new NodeResponse(clientResponse, responseEntity);
         } else if (hasSuccessfulClientResponse && isProcessGroupEndpoint(uri, method)) {
             final ProcessGroupEntity responseEntity = clientResponse.getClientResponse().getEntity(ProcessGroupEntity.class);
-            final ProcessGroupDTO responseDto = responseEntity.getProcessGroup();
+            final ProcessGroupDTO responseDto = responseEntity.getComponent();
 
             final FlowSnippetDTO contents = responseDto.getContents();
             if (contents == null) {
@@ -3138,7 +3138,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
                     }
 
                     final ProcessGroupEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(ProcessGroupEntity.class);
-                    final ProcessGroupDTO nodeProcessGroup = nodeResponseEntity.getProcessGroup();
+                    final ProcessGroupDTO nodeProcessGroup = nodeResponseEntity.getComponent();
 
                     for (final ProcessorDTO nodeProcessor : nodeProcessGroup.getContents().getProcessors()) {
                         Map<NodeIdentifier, ProcessorDTO> innerMap = processorMap.get(nodeProcessor.getId());
@@ -3242,7 +3242,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
             clientResponse = new NodeResponse(clientResponse, responseEntity);
         } else if (hasSuccessfulClientResponse && isRemoteProcessGroupEndpoint(uri, method)) {
             final RemoteProcessGroupEntity responseEntity = clientResponse.getClientResponse().getEntity(RemoteProcessGroupEntity.class);
-            final RemoteProcessGroupDTO remoteProcessGroup = responseEntity.getRemoteProcessGroup();
+            final RemoteProcessGroupDTO remoteProcessGroup = responseEntity.getComponent();
 
             final Map<NodeIdentifier, RemoteProcessGroupDTO> remoteProcessGroupMap = new HashMap<>();
             for (final NodeResponse nodeResponse : updatedNodesMap.values()) {
@@ -3251,7 +3251,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
                 }
 
                 final RemoteProcessGroupEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(RemoteProcessGroupEntity.class);
-                final RemoteProcessGroupDTO nodeRemoteProcessGroup = nodeResponseEntity.getRemoteProcessGroup();
+                final RemoteProcessGroupDTO nodeRemoteProcessGroup = nodeResponseEntity.getComponent();
 
                 remoteProcessGroupMap.put(nodeResponse.getNodeId(), nodeRemoteProcessGroup);
             }
@@ -3260,7 +3260,7 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
             clientResponse = new NodeResponse(clientResponse, responseEntity);
         } else if (hasSuccessfulClientResponse && isRemoteProcessGroupsEndpoint(uri, method)) {
             final RemoteProcessGroupsEntity responseEntity = clientResponse.getClientResponse().getEntity(RemoteProcessGroupsEntity.class);
-            final Set<RemoteProcessGroupDTO> remoteProcessGroups = responseEntity.getRemoteProcessGroups();
+            final Set<RemoteProcessGroupEntity> remoteProcessGroups = responseEntity.getRemoteProcessGroups();
 
             final Map<String, Map<NodeIdentifier, RemoteProcessGroupDTO>> remoteProcessGroupMap = new HashMap<>();
             for (final NodeResponse nodeResponse : updatedNodesMap.values()) {
@@ -3269,24 +3269,24 @@ public class WebClusterManager implements HttpClusterManager, ProtocolHandler, C
                 }
 
                 final RemoteProcessGroupsEntity nodeResponseEntity = nodeResponse == clientResponse ? responseEntity : nodeResponse.getClientResponse().getEntity(RemoteProcessGroupsEntity.class);
-                final Set<RemoteProcessGroupDTO> nodeRemoteProcessGroups = nodeResponseEntity.getRemoteProcessGroups();
+                final Set<RemoteProcessGroupEntity> nodeRemoteProcessGroups = nodeResponseEntity.getRemoteProcessGroups();
 
-                for (final RemoteProcessGroupDTO nodeRemoteProcessGroup : nodeRemoteProcessGroups) {
+                for (final RemoteProcessGroupEntity nodeRemoteProcessGroup : nodeRemoteProcessGroups) {
                     Map<NodeIdentifier, RemoteProcessGroupDTO> innerMap = remoteProcessGroupMap.get(nodeRemoteProcessGroup.getId());
                     if (innerMap == null) {
                         innerMap = new HashMap<>();
                         remoteProcessGroupMap.put(nodeRemoteProcessGroup.getId(), innerMap);
                     }
 
-                    innerMap.put(nodeResponse.getNodeId(), nodeRemoteProcessGroup);
+                    innerMap.put(nodeResponse.getNodeId(), nodeRemoteProcessGroup.getComponent());
                 }
             }
 
-            for (final RemoteProcessGroupDTO remoteProcessGroup : remoteProcessGroups) {
+            for (final RemoteProcessGroupEntity remoteProcessGroup : remoteProcessGroups) {
                 final String remoteProcessGroupId = remoteProcessGroup.getId();
                 final Map<NodeIdentifier, RemoteProcessGroupDTO> mergeMap = remoteProcessGroupMap.get(remoteProcessGroupId);
 
-                mergeRemoteProcessGroup(remoteProcessGroup, mergeMap);
+                mergeRemoteProcessGroup(remoteProcessGroup.getComponent(), mergeMap);
             }
 
             // create a new client response

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
index 62b2611..2d0f94b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/pom.xml
@@ -50,5 +50,9 @@
             <groupId>org.quartz-scheduler</groupId>
             <artifactId>quartz</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-framework-authorization</artifactId>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connectable.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connectable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connectable.java
index 1a26f39..d430599 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connectable.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connectable.java
@@ -21,6 +21,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.controller.Triggerable;
 import org.apache.nifi.groups.ProcessGroup;
@@ -31,7 +32,7 @@ import org.apache.nifi.scheduling.SchedulingStrategy;
 /**
  * Represents a connectable component to which or from which data can flow.
  */
-public interface Connectable extends Triggerable {
+public interface Connectable extends Triggerable, Authorizable {
 
     /**
      * @return the unique identifier for this <code>Connectable</code>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connection.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connection.java
index 2e66905..1d240b5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connection.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/connectable/Connection.java
@@ -20,13 +20,14 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.controller.queue.FlowFileQueue;
 import org.apache.nifi.controller.repository.FlowFileRecord;
 import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.processor.FlowFileFilter;
 import org.apache.nifi.processor.Relationship;
 
-public interface Connection {
+public interface Connection extends Authorizable {
 
     void enqueue(FlowFileRecord flowFile);
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractPort.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractPort.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractPort.java
index e234171..398e4fb 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractPort.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/AbstractPort.java
@@ -16,7 +16,25 @@
  */
 package org.apache.nifi.controller;
 
-import static java.util.Objects.requireNonNull;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
+import org.apache.nifi.components.ValidationResult;
+import org.apache.nifi.connectable.Connectable;
+import org.apache.nifi.connectable.ConnectableType;
+import org.apache.nifi.connectable.Connection;
+import org.apache.nifi.connectable.Port;
+import org.apache.nifi.connectable.Position;
+import org.apache.nifi.groups.ProcessGroup;
+import org.apache.nifi.processor.ProcessContext;
+import org.apache.nifi.processor.ProcessSession;
+import org.apache.nifi.processor.ProcessSessionFactory;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.util.FormatUtils;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,22 +50,7 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import org.apache.nifi.components.ValidationResult;
-import org.apache.nifi.connectable.Connectable;
-import org.apache.nifi.connectable.ConnectableType;
-import org.apache.nifi.connectable.Connection;
-import org.apache.nifi.connectable.Port;
-import org.apache.nifi.connectable.Position;
-import org.apache.nifi.groups.ProcessGroup;
-import org.apache.nifi.processor.ProcessContext;
-import org.apache.nifi.processor.ProcessSession;
-import org.apache.nifi.processor.ProcessSessionFactory;
-import org.apache.nifi.processor.Relationship;
-import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.util.FormatUtils;
-
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+import static java.util.Objects.requireNonNull;
 
 public abstract class AbstractPort implements Port {
 
@@ -143,6 +146,17 @@ public abstract class AbstractPort implements Port {
     }
 
     @Override
+    public Authorizable getParentAuthorizable() {
+        return getProcessGroup();
+    }
+
+    @Override
+    public Resource getResource() {
+        final ResourceType resourceType = ConnectableType.INPUT_PORT.equals(getConnectableType()) ? ResourceType.InputPort : ResourceType.OutputPort;
+        return ResourceFactory.getComponentResource(resourceType, getIdentifier(), getName());
+    }
+
+    @Override
     public ProcessGroup getProcessGroup() {
         return processGroup.get();
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
index 7813530..9929914 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/ProcessorNode.java
@@ -16,13 +16,6 @@
  */
 package org.apache.nifi.controller;
 
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-
 import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
 import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.controller.service.ControllerServiceNode;
@@ -35,6 +28,13 @@ import org.apache.nifi.scheduling.SchedulingStrategy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
 public abstract class ProcessorNode extends AbstractConfiguredComponent implements Connectable {
 
     private static final Logger logger = LoggerFactory.getLogger(ProcessorNode.class);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/StandardFunnel.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/StandardFunnel.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/StandardFunnel.java
index 9fb13f6..289f52a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/StandardFunnel.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/StandardFunnel.java
@@ -16,22 +16,12 @@
  */
 package org.apache.nifi.controller;
 
-import static java.util.Objects.requireNonNull;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.ConnectableType;
@@ -48,8 +38,21 @@ import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.scheduling.SchedulingStrategy;
 import org.apache.nifi.util.FormatUtils;
 
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import static java.util.Objects.requireNonNull;
 
 public class StandardFunnel implements Funnel {
 
@@ -117,6 +120,16 @@ public class StandardFunnel implements Funnel {
     }
 
     @Override
+    public Authorizable getParentAuthorizable() {
+        return getProcessGroup();
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getComponentResource(ResourceType.Funnel, getIdentifier(), getName());
+    }
+
+    @Override
     public void addConnection(final Connection connection) throws IllegalArgumentException {
         writeLock.lock();
         try {

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/label/Label.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/label/Label.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/label/Label.java
index 97c44b5..2a95f13 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/label/Label.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/controller/label/Label.java
@@ -18,11 +18,12 @@ package org.apache.nifi.controller.label;
 
 import java.util.Map;
 
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.connectable.Position;
 import org.apache.nifi.connectable.Size;
 import org.apache.nifi.groups.ProcessGroup;
 
-public interface Label {
+public interface Label extends Authorizable {
 
     String getIdentifier();
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/ProcessGroup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/ProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/ProcessGroup.java
index 56038fe..5406954 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/ProcessGroup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/ProcessGroup.java
@@ -20,6 +20,7 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Funnel;
@@ -40,7 +41,7 @@ import org.apache.nifi.processor.Processor;
  * <p>
  * MUST BE THREAD-SAFE</p>
  */
-public interface ProcessGroup {
+public interface ProcessGroup extends Authorizable {
 
     /**
      * @return a reference to this ProcessGroup's parent. This will be

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/RemoteProcessGroup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/RemoteProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/RemoteProcessGroup.java
index db05313..cf0820b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/RemoteProcessGroup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/groups/RemoteProcessGroup.java
@@ -21,12 +21,13 @@ import java.util.Date;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.connectable.Position;
 import org.apache.nifi.controller.exception.CommunicationsException;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.remote.RemoteGroupPort;
 
-public interface RemoteProcessGroup {
+public interface RemoteProcessGroup extends Authorizable {
 
     String getIdentifier();
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/connectable/StandardConnection.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/connectable/StandardConnection.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/connectable/StandardConnection.java
index 1176147..0843743 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/connectable/StandardConnection.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/connectable/StandardConnection.java
@@ -16,18 +16,14 @@
  */
 package org.apache.nifi.connectable;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.controller.ProcessScheduler;
 import org.apache.nifi.controller.StandardFlowFileQueue;
 import org.apache.nifi.controller.queue.FlowFileQueue;
@@ -42,6 +38,17 @@ import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.provenance.ProvenanceEventRepository;
 import org.apache.nifi.util.NiFiProperties;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
 /**
  * Models a connection between connectable components. A connection may contain one or more relationships that map the source component to the destination component.
  */
@@ -95,6 +102,27 @@ public final class StandardConnection implements Connection {
     }
 
     @Override
+    public Authorizable getParentAuthorizable() {
+        return getSource();
+    }
+
+    @Override
+    public Resource getResource() {
+        String name = getName();
+
+        final Collection<Relationship> relationships = getRelationships();
+        if (name == null && CollectionUtils.isNotEmpty(relationships)) {
+            name = StringUtils.join(relationships.stream().map(relationship -> relationship.getName()).collect(Collectors.toSet()), ", ");
+        }
+
+        if (name == null) {
+            name = "Connection";
+        }
+
+        return ResourceFactory.getComponentResource(ResourceType.Connection, getIdentifier(), name);
+    }
+
+    @Override
     public List<Position> getBendPoints() {
         return bendPoints.get();
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
index b544f38..0d168ec 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardProcessorNode.java
@@ -16,29 +16,6 @@
  */
 package org.apache.nifi.controller;
 
-import static java.util.Objects.requireNonNull;
-
-import java.lang.reflect.InvocationTargetException;
-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.Objects;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.atomic.AtomicReference;
-
 import org.apache.commons.lang3.builder.EqualsBuilder;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.nifi.annotation.behavior.EventDriven;
@@ -53,6 +30,10 @@ import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.lifecycle.OnScheduled;
 import org.apache.nifi.annotation.lifecycle.OnStopped;
 import org.apache.nifi.annotation.lifecycle.OnUnscheduled;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.components.ValidationContext;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.connectable.Connectable;
@@ -79,6 +60,29 @@ import org.quartz.CronExpression;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.lang.reflect.InvocationTargetException;
+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.Objects;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static java.util.Objects.requireNonNull;
+
 /**
  * ProcessorNode provides thread-safe access to a FlowFileProcessor as it exists
  * within a controlled flow. This node keeps track of the processor, its
@@ -194,6 +198,16 @@ public class StandardProcessorNode extends ProcessorNode implements Connectable
         return comments.get();
     }
 
+    @Override
+    public Authorizable getParentAuthorizable() {
+        return getProcessGroup();
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getComponentResource(ResourceType.Processor, getIdentifier(), getName());
+    }
+
     /**
      * Provides and opportunity to retain information about this particular
      * processor instance

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/label/StandardLabel.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/label/StandardLabel.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/label/StandardLabel.java
index c13dd47..a95cb45 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/label/StandardLabel.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/label/StandardLabel.java
@@ -16,16 +16,19 @@
  */
 package org.apache.nifi.controller.label;
 
-import org.apache.nifi.controller.label.Label;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
+import org.apache.nifi.connectable.Position;
+import org.apache.nifi.connectable.Size;
+import org.apache.nifi.groups.ProcessGroup;
+
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.nifi.connectable.Position;
-import org.apache.nifi.connectable.Size;
-import org.apache.nifi.groups.ProcessGroup;
-
 public class StandardLabel implements Label {
 
     private final String identifier;
@@ -76,6 +79,16 @@ public class StandardLabel implements Label {
         return identifier;
     }
 
+    @Override
+    public Authorizable getParentAuthorizable() {
+        return getProcessGroup();
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getComponentResource(ResourceType.Label, getIdentifier(),"Label");
+    }
+
     public Map<String, String> getStyle() {
         return style.get();
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
index 06a5e3d..5cb39e1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
@@ -52,7 +52,7 @@ import org.apache.nifi.web.api.dto.ControllerServiceDTO;
 import org.apache.nifi.web.api.dto.FlowSnippetDTO;
 import org.apache.nifi.web.api.dto.FunnelDTO;
 import org.apache.nifi.web.api.dto.LabelDTO;
-import org.apache.nifi.web.api.dto.NiFiComponentDTO;
+import org.apache.nifi.web.api.dto.ComponentDTO;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
@@ -321,9 +321,9 @@ public final class FingerprintFactory {
     }
 
     private StringBuilder addSnippetFingerprint(final StringBuilder builder, final FlowSnippetDTO snippet) {
-        final Comparator<NiFiComponentDTO> componentComparator = new Comparator<NiFiComponentDTO>() {
+        final Comparator<ComponentDTO> componentComparator = new Comparator<ComponentDTO>() {
             @Override
-            public int compare(final NiFiComponentDTO o1, final NiFiComponentDTO o2) {
+            public int compare(final ComponentDTO o1, final ComponentDTO o2) {
                 if (o1 == null && o2 == null) {
                     return 0;
                 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
index db99771..f06ff88 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java
@@ -16,26 +16,16 @@
  */
 package org.apache.nifi.groups;
 
-import static java.util.Objects.requireNonNull;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.nifi.annotation.lifecycle.OnRemoved;
 import org.apache.nifi.annotation.lifecycle.OnShutdown;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.components.state.StateManager;
 import org.apache.nifi.components.state.StateManagerProvider;
@@ -66,6 +56,20 @@ import org.apache.nifi.util.ReflectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import static java.util.Objects.requireNonNull;
+
 public final class StandardProcessGroup implements ProcessGroup {
 
     private final String id;
@@ -119,6 +123,16 @@ public final class StandardProcessGroup implements ProcessGroup {
     }
 
     @Override
+    public Authorizable getParentAuthorizable() {
+        return getParent();
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getComponentResource(ResourceType.ProcessGroup, getIdentifier(), getName());
+    }
+
+    @Override
     public String getIdentifier() {
         return id;
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/remote/StandardRemoteProcessGroup.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/remote/StandardRemoteProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/remote/StandardRemoteProcessGroup.java
index 11d7b2f..cdabeca 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/remote/StandardRemoteProcessGroup.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/remote/StandardRemoteProcessGroup.java
@@ -16,31 +16,14 @@
  */
 package org.apache.nifi.remote;
 
-import static java.util.Objects.requireNonNull;
-
-import java.io.File;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import javax.net.ssl.SSLContext;
-import javax.ws.rs.core.Response;
-
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.ClientResponse.Status;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Port;
@@ -67,10 +50,29 @@ import org.apache.nifi.web.api.entity.ControllerEntity;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.sun.jersey.api.client.ClientHandlerException;
-import com.sun.jersey.api.client.ClientResponse;
-import com.sun.jersey.api.client.ClientResponse.Status;
-import com.sun.jersey.api.client.UniformInterfaceException;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.core.Response;
+import java.io.File;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import static java.util.Objects.requireNonNull;
 
 /**
  * Represents the Root Process Group of a remote NiFi Instance. Holds information about that remote instance, as well as {@link IncomingPort}s and {@link OutgoingPort}s for communicating with the
@@ -204,6 +206,16 @@ public class StandardRemoteProcessGroup implements RemoteProcessGroup {
     }
 
     @Override
+    public Authorizable getParentAuthorizable() {
+        return getProcessGroup();
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getComponentResource(ResourceType.RemoteProcessGroup, getIdentifier(), getName());
+    }
+
+    @Override
     public ProcessGroup getProcessGroup() {
         return processGroup.get();
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/SnippetUtils.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/SnippetUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/SnippetUtils.java
index 1521f54..87bc981 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/SnippetUtils.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/SnippetUtils.java
@@ -26,7 +26,7 @@ import java.util.Map;
 
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.FlowSnippetDTO;
-import org.apache.nifi.web.api.dto.NiFiComponentDTO;
+import org.apache.nifi.web.api.dto.ComponentDTO;
 import org.apache.nifi.web.api.dto.PositionDTO;
 
 /**
@@ -50,7 +50,7 @@ public final class SnippetUtils {
             final Collection<ConnectionDTO> connections = getConnections(snippet);
 
             // get the components and their positions from the template contents
-            final Collection<NiFiComponentDTO> components = getComponents(snippet);
+            final Collection<ComponentDTO> components = getComponents(snippet);
 
             // only perform the operation if there are components in this snippet
             if (connections.isEmpty() && components.isEmpty()) {
@@ -58,7 +58,7 @@ public final class SnippetUtils {
             }
 
             // get the component positions from the snippet contents
-            final Map<NiFiComponentDTO, PositionDTO> componentPositionLookup = getPositionLookup(components);
+            final Map<ComponentDTO, PositionDTO> componentPositionLookup = getPositionLookup(components);
             final Map<ConnectionDTO, List<PositionDTO>> connectionPositionLookup = getConnectionPositionLookup(connections);
             final PositionDTO currentOrigin = getOrigin(componentPositionLookup.values(), connectionPositionLookup.values());
 
@@ -101,8 +101,8 @@ public final class SnippetUtils {
      * @param contents snippet
      * @return component dtos
      */
-    private static Collection<NiFiComponentDTO> getComponents(FlowSnippetDTO contents) {
-        final Collection<NiFiComponentDTO> components = new HashSet<>();
+    private static Collection<ComponentDTO> getComponents(FlowSnippetDTO contents) {
+        final Collection<ComponentDTO> components = new HashSet<>();
 
         // add all components
         if (contents.getInputPorts() != null) {
@@ -136,11 +136,11 @@ public final class SnippetUtils {
      * @param components components
      * @return component and position map
      */
-    private static Map<NiFiComponentDTO, PositionDTO> getPositionLookup(Collection<NiFiComponentDTO> components) {
-        final Map<NiFiComponentDTO, PositionDTO> positionLookup = new HashMap<>();
+    private static Map<ComponentDTO, PositionDTO> getPositionLookup(Collection<ComponentDTO> components) {
+        final Map<ComponentDTO, PositionDTO> positionLookup = new HashMap<>();
 
         // determine the position for each component
-        for (final NiFiComponentDTO component : components) {
+        for (final ComponentDTO component : components) {
             positionLookup.put(component, new PositionDTO(component.getPosition().getX(), component.getPosition().getY()));
         }
 
@@ -223,9 +223,9 @@ public final class SnippetUtils {
      * @param componentPositionLookup lookup
      * @param connectionPositionLookup lookup
      */
-    private static void applyUpdatedPositions(final Map<NiFiComponentDTO, PositionDTO> componentPositionLookup, final Map<ConnectionDTO, List<PositionDTO>> connectionPositionLookup) {
-        for (final Map.Entry<NiFiComponentDTO, PositionDTO> entry : componentPositionLookup.entrySet()) {
-            final NiFiComponentDTO component = entry.getKey();
+    private static void applyUpdatedPositions(final Map<ComponentDTO, PositionDTO> componentPositionLookup, final Map<ConnectionDTO, List<PositionDTO>> connectionPositionLookup) {
+        for (final Map.Entry<ComponentDTO, PositionDTO> entry : componentPositionLookup.entrySet()) {
+            final ComponentDTO component = entry.getKey();
             final PositionDTO position = entry.getValue();
             component.setPosition(position);
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
index 9fb62df..6e1b6c8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java
@@ -161,7 +161,6 @@ public class StandardFlowServiceTest {
             return;
         }
 
-        assertEquals(expected.getParent(), actual.getParent());
         Assert.assertEquals(expected.getComments(), actual.getComments());
         assertEquals(expected.getContents(), actual.getContents());
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
index f8015d2..e174acd 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/state/providers/zookeeper/TestZooKeeperStateProvider.java
@@ -17,12 +17,6 @@
 
 package org.apache.nifi.controller.state.providers.zookeeper;
 
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.net.ssl.SSLContext;
-
 import org.apache.curator.test.TestingServer;
 import org.apache.nifi.attribute.expression.language.StandardPropertyValue;
 import org.apache.nifi.components.PropertyDescriptor;
@@ -36,6 +30,11 @@ import org.junit.Before;
 import org.junit.Test;
 import org.testng.Assert;
 
+import javax.net.ssl.SSLContext;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
 public class TestZooKeeperStateProvider extends AbstractTestStateProvider {
 
     private StateProvider provider;
@@ -147,7 +146,7 @@ public class TestZooKeeperStateProvider extends AbstractTestStateProvider {
         } catch (final StateTooLargeException stle) {
             // expected behavior.
         } catch (final Exception e) {
-            Assert.fail("Expected StateTooLargeException");
+            Assert.fail("Expected StateTooLargeException", e);
         }
 
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRemoteGroupPort.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRemoteGroupPort.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRemoteGroupPort.java
index 552c0c6..b44f562 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRemoteGroupPort.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-site-to-site/src/main/java/org/apache/nifi/remote/StandardRemoteGroupPort.java
@@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import javax.net.ssl.SSLContext;
 
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.connectable.Connection;
@@ -108,6 +109,11 @@ public class StandardRemoteGroupPort extends RemoteGroupPort {
     }
 
     @Override
+    public Authorizable getParentAuthorizable() {
+        return getRemoteProcessGroup();
+    }
+
+    @Override
     public void shutdown() {
         super.shutdown();
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ComponentStateAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ComponentStateAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ComponentStateAuditor.java
index 5a5d160..8e75cdc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ComponentStateAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ComponentStateAuditor.java
@@ -21,12 +21,12 @@ import org.apache.nifi.action.Component;
 import org.apache.nifi.action.FlowChangeAction;
 import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.components.state.StateMap;
 import org.apache.nifi.controller.ProcessorNode;
 import org.apache.nifi.controller.ReportingTaskNode;
 import org.apache.nifi.controller.service.ControllerServiceNode;
-import org.apache.nifi.user.NiFiUser;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java
index 4357633..5a6c590 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerAuditor.java
@@ -24,8 +24,8 @@ import org.apache.nifi.action.Component;
 import org.apache.nifi.action.FlowChangeAction;
 import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.web.controller.ControllerFacade;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerServiceAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerServiceAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerServiceAuditor.java
index af8428d..1fb5bb7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerServiceAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ControllerServiceAuditor.java
@@ -30,13 +30,13 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
 import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.controller.ConfiguredComponent;
 import org.apache.nifi.controller.ProcessorNode;
 import org.apache.nifi.controller.ReportingTaskNode;
 import org.apache.nifi.controller.ScheduledState;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.controller.service.ControllerServiceNode;
 import org.apache.nifi.controller.service.ControllerServiceReference;
 import org.apache.nifi.controller.service.ControllerServiceState;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/FunnelAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/FunnelAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/FunnelAuditor.java
index 40f0f34..7230f9c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/FunnelAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/FunnelAuditor.java
@@ -23,9 +23,9 @@ import org.apache.nifi.action.Component;
 import org.apache.nifi.action.FlowChangeAction;
 import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.details.ActionDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.connectable.Funnel;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.dao.FunnelDAO;
 
 import org.aspectj.lang.ProceedingJoinPoint;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/PortAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/PortAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/PortAuditor.java
index dff311e..3e5b0b5 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/PortAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/PortAuditor.java
@@ -23,14 +23,14 @@ import org.apache.nifi.action.FlowChangeAction;
 import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.connectable.Port;
 import org.apache.nifi.controller.ScheduledState;
 import org.apache.nifi.remote.RootGroupPort;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.dao.PortDAO;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessGroupAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessGroupAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessGroupAuditor.java
index 89871e6..04dca11 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessGroupAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessGroupAuditor.java
@@ -26,9 +26,9 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
 import org.apache.nifi.action.details.FlowChangeMoveDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.groups.ProcessGroup;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.dao.ProcessGroupDAO;
 import org.aspectj.lang.ProceedingJoinPoint;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
index d6bf700..718def0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
@@ -34,12 +34,12 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
 import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.controller.ProcessorNode;
 import org.apache.nifi.controller.ScheduledState;
 import org.apache.nifi.processor.Relationship;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.dao.ProcessorDAO;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RelationshipAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RelationshipAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RelationshipAuditor.java
index 8a77636..1780790 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RelationshipAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RelationshipAuditor.java
@@ -32,6 +32,7 @@ import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.ConnectDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
 import org.apache.nifi.action.details.FlowChangeConnectDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Funnel;
@@ -42,8 +43,7 @@ import org.apache.nifi.flowfile.FlowFilePrioritizer;
 import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.remote.RemoteGroupPort;
 import org.apache.nifi.remote.TransferDirection;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.dao.ConnectionDAO;
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RemoteProcessGroupAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RemoteProcessGroupAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RemoteProcessGroupAuditor.java
index 0495e99..e19bf29 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RemoteProcessGroupAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/RemoteProcessGroupAuditor.java
@@ -23,14 +23,14 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeRemoteProcessGroupDetails;
 import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.groups.RemoteProcessGroup;
 import org.apache.nifi.remote.RemoteGroupPort;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupContentsDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
 import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ReportingTaskAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ReportingTaskAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ReportingTaskAuditor.java
index 77df12a..2e242d2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ReportingTaskAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ReportingTaskAuditor.java
@@ -30,11 +30,11 @@ import org.apache.nifi.action.Operation;
 import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
 import org.apache.nifi.action.details.ActionDetails;
 import org.apache.nifi.action.details.FlowChangeConfigureDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.controller.ReportingTaskNode;
 import org.apache.nifi.controller.ScheduledState;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.ReportingTaskDTO;
 import org.apache.nifi.web.dao.ReportingTaskDAO;
 import org.aspectj.lang.ProceedingJoinPoint;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/SnippetAuditor.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/SnippetAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/SnippetAuditor.java
index 3fcc419..b71636b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/SnippetAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/SnippetAuditor.java
@@ -26,6 +26,7 @@ import org.apache.nifi.action.component.details.FlowChangeExtensionDetails;
 import org.apache.nifi.action.component.details.FlowChangeRemoteProcessGroupDetails;
 import org.apache.nifi.action.details.ConnectDetails;
 import org.apache.nifi.action.details.FlowChangeConnectDetails;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.connectable.Funnel;
@@ -34,7 +35,7 @@ import org.apache.nifi.controller.ProcessorNode;
 import org.apache.nifi.controller.Snippet;
 import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.groups.RemoteProcessGroup;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.nifi.web.api.dto.ConnectableDTO;
 import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.FlowSnippetDTO;
@@ -51,7 +52,6 @@ import org.apache.nifi.web.dao.ProcessGroupDAO;
 import org.apache.nifi.web.dao.ProcessorDAO;
 import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
 import org.apache.nifi.web.dao.SnippetDAO;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;


[08/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
index 411bad2..65dbb75 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/LabelResource.java
@@ -25,9 +25,9 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.LabelDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.LabelEntity;
@@ -74,6 +74,32 @@ public class LabelResource extends ApplicationResource {
     /**
      * Populates the uri for the specified labels.
      *
+     * @param labelEntities labels
+     * @return entites
+     */
+    public Set<LabelEntity> populateRemainingLabelEntitiesContent(Set<LabelEntity> labelEntities) {
+        for (LabelEntity labelEntity : labelEntities) {
+            populateRemainingLabelEntityContent(labelEntity);
+        }
+        return labelEntities;
+    }
+
+    /**
+     * Populates the uri for the specified labels.
+     *
+     * @param labelEntity label
+     * @return entities
+     */
+    public LabelEntity populateRemainingLabelEntityContent(LabelEntity labelEntity) {
+        if (labelEntity.getComponent() != null) {
+            populateRemainingLabelContent(labelEntity.getComponent());
+        }
+        return labelEntity;
+    }
+
+    /**
+     * Populates the uri for the specified labels.
+     *
      * @param labels labels
      * @return dtos
      */
@@ -96,7 +122,6 @@ public class LabelResource extends ApplicationResource {
     /**
      * Retrieves the specified label.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the label to retrieve
      * @return A labelEntity.
      */
@@ -125,11 +150,6 @@ public class LabelResource extends ApplicationResource {
     )
     public Response getLabel(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The label id.",
                     required = true
             )
@@ -141,16 +161,8 @@ public class LabelResource extends ApplicationResource {
         }
 
         // get the label
-        final LabelDTO label = serviceFacade.getLabel(id);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final LabelEntity entity = new LabelEntity();
-        entity.setRevision(revision);
-        entity.setLabel(populateRemainingLabelContent(label));
+        final LabelEntity entity = serviceFacade.getLabel(id);
+        populateRemainingLabelEntityContent(entity);
 
         return clusterContext(generateOkResponse(entity)).build();
     }
@@ -196,7 +208,7 @@ public class LabelResource extends ApplicationResource {
                     required = true
             ) LabelEntity labelEntity) {
 
-        if (labelEntity == null || labelEntity.getLabel() == null) {
+        if (labelEntity == null || labelEntity.getComponent() == null) {
             throw new IllegalArgumentException("Label details must be specified.");
         }
 
@@ -205,7 +217,7 @@ public class LabelResource extends ApplicationResource {
         }
 
         // ensure the ids are the same
-        final LabelDTO requestLabelDTO = labelEntity.getLabel();
+        final LabelDTO requestLabelDTO = labelEntity.getComponent();
         if (!id.equals(requestLabelDTO.getId())) {
             throw new IllegalArgumentException(String.format("The label id (%s) in the request body does not equal the "
                     + "label id of the requested resource (%s).", requestLabelDTO.getId(), id));
@@ -229,25 +241,13 @@ public class LabelResource extends ApplicationResource {
 
         // update the label
         final RevisionDTO revision = labelEntity.getRevision();
-        final ConfigurationSnapshot<LabelDTO> controllerResponse = serviceFacade.updateLabel(
+        final UpdateResult<LabelEntity> result = serviceFacade.updateLabel(
                 new Revision(revision.getVersion(), revision.getClientId()), requestLabelDTO);
+        final LabelEntity entity = result.getResult();
+        populateRemainingLabelEntityContent(entity);
 
-        // get the results
-        final LabelDTO responseLabelDTO = controllerResponse.getConfiguration();
-        populateRemainingLabelContent(responseLabelDTO);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final LabelEntity entity = new LabelEntity();
-        entity.setRevision(updatedRevision);
-        entity.setLabel(responseLabelDTO);
-
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(responseLabelDTO.getUri()), entity)).build();
+        if (result.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -319,17 +319,7 @@ public class LabelResource extends ApplicationResource {
         }
 
         // delete the specified label
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteLabel(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final LabelEntity entity = new LabelEntity();
-        entity.setRevision(revision);
-
+        final LabelEntity entity = serviceFacade.deleteLabel(new Revision(clientVersion, clientId.getClientId()), id);
         return clusterContext(generateOkResponse(entity)).build();
     }
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
index 1335390..398350f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/OutputPortResource.java
@@ -25,12 +25,12 @@ import com.wordnik.swagger.annotations.Authorization;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.cluster.manager.impl.WebClusterManager;
 import org.apache.nifi.util.NiFiProperties;
-import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.PortDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
-import org.apache.nifi.web.api.entity.OutputPortEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
 import org.apache.nifi.web.api.request.LongParameter;
 import org.slf4j.Logger;
@@ -74,6 +74,32 @@ public class OutputPortResource extends ApplicationResource {
     /**
      * Populates the uri for the specified output ports.
      *
+     * @param outputPortEntities ports
+     * @return dtos
+     */
+    public Set<PortEntity> populateRemainingOutputPortEntitiesContent(Set<PortEntity> outputPortEntities) {
+        for (PortEntity outputPortEntity : outputPortEntities) {
+            populateRemainingOutputPortEntityContent(outputPortEntity);
+        }
+        return outputPortEntities;
+    }
+
+    /**
+     * Populates the uri for the specified output ports.
+     *
+     * @param outputPortEntity ports
+     * @return dtos
+     */
+    public PortEntity populateRemainingOutputPortEntityContent(PortEntity outputPortEntity) {
+        if (outputPortEntity.getComponent() != null) {
+            populateRemainingOutputPortContent(outputPortEntity.getComponent());
+        }
+        return outputPortEntity;
+    }
+
+    /**
+     * Populates the uri for the specified output ports.
+     *
      * @param outputPorts ports
      * @return dtos
      */
@@ -96,7 +122,6 @@ public class OutputPortResource extends ApplicationResource {
     /**
      * Retrieves the specified output port.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param id The id of the output port to retrieve
      * @return A outputPortEntity.
      */
@@ -107,7 +132,7 @@ public class OutputPortResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
     @ApiOperation(
             value = "Gets an output port",
-            response = OutputPortEntity.class,
+            response = PortEntity.class,
             authorizations = {
                 @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
                 @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
@@ -125,11 +150,6 @@ public class OutputPortResource extends ApplicationResource {
     )
     public Response getOutputPort(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The output port id.",
                     required = true
             )
@@ -141,16 +161,8 @@ public class OutputPortResource extends ApplicationResource {
         }
 
         // get the port
-        final PortDTO port = serviceFacade.getOutputPort(id);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final OutputPortEntity entity = new OutputPortEntity();
-        entity.setRevision(revision);
-        entity.setOutputPort(populateRemainingOutputPortContent(port));
+        final PortEntity entity = serviceFacade.getOutputPort(id);
+        populateRemainingOutputPortEntityContent(entity);
 
         return clusterContext(generateOkResponse(entity)).build();
     }
@@ -170,7 +182,7 @@ public class OutputPortResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
             value = "Updates an output port",
-            response = OutputPortEntity.class,
+            response = PortEntity.class,
             authorizations = {
                 @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
             }
@@ -194,9 +206,9 @@ public class OutputPortResource extends ApplicationResource {
             @ApiParam(
                     value = "The output port configuration details.",
                     required = true
-            ) OutputPortEntity portEntity) {
+            ) PortEntity portEntity) {
 
-        if (portEntity == null || portEntity.getOutputPort() == null) {
+        if (portEntity == null || portEntity.getComponent() == null) {
             throw new IllegalArgumentException("Output port details must be specified.");
         }
 
@@ -205,7 +217,7 @@ public class OutputPortResource extends ApplicationResource {
         }
 
         // ensure the ids are the same
-        PortDTO requestPortDTO = portEntity.getOutputPort();
+        PortDTO requestPortDTO = portEntity.getComponent();
         if (!id.equals(requestPortDTO.getId())) {
             throw new IllegalArgumentException(String.format("The output port id (%s) in the request body does not equal the "
                     + "output port id of the requested resource (%s).", requestPortDTO.getId(), id));
@@ -230,25 +242,15 @@ public class OutputPortResource extends ApplicationResource {
 
         // update the output port
         final RevisionDTO revision = portEntity.getRevision();
-        final ConfigurationSnapshot<PortDTO> controllerResponse = serviceFacade.updateOutputPort(
+        final UpdateResult<PortEntity> updateResult = serviceFacade.updateOutputPort(
                 new Revision(revision.getVersion(), revision.getClientId()), requestPortDTO);
 
         // get the results
-        final PortDTO responsePortDTO = controllerResponse.getConfiguration();
-        populateRemainingOutputPortContent(responsePortDTO);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final OutputPortEntity entity = new OutputPortEntity();
-        entity.setRevision(updatedRevision);
-        entity.setOutputPort(responsePortDTO);
+        final PortEntity entity = updateResult.getResult();
+        populateRemainingOutputPortEntityContent(entity);
 
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(responsePortDTO.getUri()), entity)).build();
+        if (updateResult.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }
@@ -270,7 +272,7 @@ public class OutputPortResource extends ApplicationResource {
     // TODO - @PreAuthorize("hasRole('ROLE_DFM')")
     @ApiOperation(
             value = "Deletes an output port",
-            response = OutputPortEntity.class,
+            response = PortEntity.class,
             authorizations = {
                 @Authorization(value = "Data Flow Manager", type = "ROLE_DFM")
             }
@@ -321,17 +323,7 @@ public class OutputPortResource extends ApplicationResource {
         }
 
         // delete the specified output port
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteOutputPort(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final OutputPortEntity entity = new OutputPortEntity();
-        entity.setRevision(revision);
-
+        final PortEntity entity = serviceFacade.deleteOutputPort(new Revision(clientVersion, clientId.getClientId()), id);
         return clusterContext(generateOkResponse(entity)).build();
     }
 


[06/13] nifi git commit: NIFI-1554: - Populating component entities in the REST API to decouple key fields from the configuration DTOs. - Added initial support for components in UI when access isn't allowed. Formal styling to come later.

Posted by mc...@apache.org.
http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
index d1999d9..64fe273 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/RemoteProcessGroupResource.java
@@ -28,6 +28,7 @@ import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.ConfigurationSnapshot;
 import org.apache.nifi.web.NiFiServiceFacade;
 import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.UpdateResult;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
 import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
@@ -74,6 +75,32 @@ public class RemoteProcessGroupResource extends ApplicationResource {
     /**
      * Populates the remaining content for each remote process group. The uri must be generated and the remote process groups name must be retrieved.
      *
+     * @param remoteProcessGroupEntities groups
+     * @return dtos
+     */
+    public Set<RemoteProcessGroupEntity> populateRemainingRemoteProcessGroupEntitiesContent(Set<RemoteProcessGroupEntity> remoteProcessGroupEntities) {
+        for (RemoteProcessGroupEntity remoteProcessEntities : remoteProcessGroupEntities) {
+            populateRemainingRemoteProcessGroupEntityContent(remoteProcessEntities);
+        }
+        return remoteProcessGroupEntities;
+    }
+
+    /**
+     * Populates the remaining content for each remote process group. The uri must be generated and the remote process groups name must be retrieved.
+     *
+     * @param remoteProcessGroupEntity groups
+     * @return dtos
+     */
+    public RemoteProcessGroupEntity populateRemainingRemoteProcessGroupEntityContent(RemoteProcessGroupEntity remoteProcessGroupEntity) {
+        if (remoteProcessGroupEntity.getComponent() != null) {
+            populateRemainingRemoteProcessGroupContent(remoteProcessGroupEntity.getComponent());
+        }
+        return remoteProcessGroupEntity;
+    }
+
+    /**
+     * Populates the remaining content for each remote process group. The uri must be generated and the remote process groups name must be retrieved.
+     *
      * @param remoteProcessGroups groups
      * @return dtos
      */
@@ -100,7 +127,6 @@ public class RemoteProcessGroupResource extends ApplicationResource {
     /**
      * Retrieves the specified remote process group.
      *
-     * @param clientId Optional client id. If the client id is not specified, a new one will be generated. This value (whether specified or generated) is included in the response.
      * @param verbose Optional verbose flag that defaults to false. If the verbose flag is set to true remote group contents (ports) will be included.
      * @param id The id of the remote process group to retrieve
      * @return A remoteProcessGroupEntity.
@@ -130,11 +156,6 @@ public class RemoteProcessGroupResource extends ApplicationResource {
     )
     public Response getRemoteProcessGroup(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "Whether to include any encapulated ports or just details about the remote process group.",
                     required = false
             )
@@ -150,23 +171,17 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse();
         }
 
-        // get the label
-        final RemoteProcessGroupDTO remoteProcessGroup = serviceFacade.getRemoteProcessGroup(id);
+        // get the remote process group
+        final RemoteProcessGroupEntity entity = serviceFacade.getRemoteProcessGroup(id);
+        populateRemainingRemoteProcessGroupEntityContent(entity);
 
         // prune the response as necessary
         if (!verbose) {
-            remoteProcessGroup.setContents(null);
+            if (entity.getComponent() != null) {
+                entity.getComponent().setContents(null);
+            }
         }
 
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
-        entity.setRevision(revision);
-        entity.setRemoteProcessGroup(populateRemainingRemoteProcessGroupContent(remoteProcessGroup));
-
         return clusterContext(generateOkResponse(entity)).build();
     }
 
@@ -236,18 +251,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             clientVersion = version.getLong();
         }
 
-        final ConfigurationSnapshot<Void> controllerResponse = serviceFacade.deleteRemoteProcessGroup(new Revision(clientVersion, clientId.getClientId()), id);
-
-        // get the updated revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-        revision.setVersion(controllerResponse.getVersion());
-
-        // create the response entity
-        final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
-        entity.setRevision(revision);
-
-        // create the response
+        final RemoteProcessGroupEntity entity = serviceFacade.deleteRemoteProcessGroup(new Revision(clientVersion, clientId.getClientId()), id);
         return clusterContext(generateOkResponse(entity)).build();
     }
 
@@ -463,7 +467,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
             @PathParam("id") String id,
             RemoteProcessGroupEntity remoteProcessGroupEntity) {
 
-        if (remoteProcessGroupEntity == null || remoteProcessGroupEntity.getRemoteProcessGroup() == null) {
+        if (remoteProcessGroupEntity == null || remoteProcessGroupEntity.getComponent() == null) {
             throw new IllegalArgumentException("Remote process group details must be specified.");
         }
 
@@ -472,7 +476,7 @@ public class RemoteProcessGroupResource extends ApplicationResource {
         }
 
         // ensure the ids are the same
-        final RemoteProcessGroupDTO requestRemoteProcessGroup = remoteProcessGroupEntity.getRemoteProcessGroup();
+        final RemoteProcessGroupDTO requestRemoteProcessGroup = remoteProcessGroupEntity.getComponent();
         if (!id.equals(requestRemoteProcessGroup.getId())) {
             throw new IllegalArgumentException(String.format("The remote process group id (%s) in the request body does not equal the "
                     + "remote process group id of the requested resource (%s).", requestRemoteProcessGroup.getId(), id));
@@ -530,24 +534,14 @@ public class RemoteProcessGroupResource extends ApplicationResource {
 
         // update the specified remote process group
         final RevisionDTO revision = remoteProcessGroupEntity.getRevision();
-        final ConfigurationSnapshot<RemoteProcessGroupDTO> controllerResponse
+        final UpdateResult<RemoteProcessGroupEntity> updateResult
                 = serviceFacade.updateRemoteProcessGroup(new Revision(revision.getVersion(), revision.getClientId()), requestRemoteProcessGroup);
 
-        final RemoteProcessGroupDTO responseRemoteProcessGroup = controllerResponse.getConfiguration();
-        populateRemainingRemoteProcessGroupContent(responseRemoteProcessGroup);
-
-        // get the updated revision
-        final RevisionDTO updatedRevision = new RevisionDTO();
-        updatedRevision.setClientId(revision.getClientId());
-        updatedRevision.setVersion(controllerResponse.getVersion());
-
-        // build the response entity
-        final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
-        entity.setRevision(updatedRevision);
-        entity.setRemoteProcessGroup(responseRemoteProcessGroup);
+        final RemoteProcessGroupEntity entity = updateResult.getResult();
+        populateRemainingRemoteProcessGroupEntityContent(entity);
 
-        if (controllerResponse.isNew()) {
-            return clusterContext(generateCreatedResponse(URI.create(responseRemoteProcessGroup.getUri()), entity)).build();
+        if (updateResult.isNew()) {
+            return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
         } else {
             return clusterContext(generateOkResponse(entity)).build();
         }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
index 5657fff..ceb9455 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java
@@ -89,9 +89,6 @@ public class TemplateResource extends ApplicationResource {
     /**
      * Retrieves the specified template.
      *
-     * @param clientId Optional client id. If the client id is not specified, a
-     * new one will be generated. This value (whether specified or generated) is
-     * included in the response.
      * @param id The id of the template to retrieve
      * @return A templateEntity.
      */
@@ -120,11 +117,6 @@ public class TemplateResource extends ApplicationResource {
     )
     public Response exportTemplate(
             @ApiParam(
-                    value = "If the client id is not specified, new one will be generated. This value (whether specified or generated) is included in the response.",
-                    required = false
-            )
-            @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId,
-            @ApiParam(
                     value = "The template id.",
                     required = true
             )

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
index 5d50e70..3af22c9 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/AccessDeniedExceptionMapper.java
@@ -19,12 +19,13 @@ package org.apache.nifi.web.api.config;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.ext.ExceptionMapper;
 import javax.ws.rs.ext.Provider;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+
+import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.user.NiFiUser;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.AccessDeniedException;
 
 /**
  * Maps access denied exceptions into a client response.

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
index 79e1d55..afcf86a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java
@@ -34,7 +34,10 @@ import org.apache.nifi.action.details.PurgeDetails;
 import org.apache.nifi.annotation.behavior.Stateful;
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat;
 import org.apache.nifi.cluster.event.Event;
 import org.apache.nifi.cluster.manager.StatusMerger;
@@ -113,6 +116,9 @@ import org.apache.nifi.web.api.dto.action.details.ConfigureDetailsDTO;
 import org.apache.nifi.web.api.dto.action.details.ConnectDetailsDTO;
 import org.apache.nifi.web.api.dto.action.details.MoveDetailsDTO;
 import org.apache.nifi.web.api.dto.action.details.PurgeDetailsDTO;
+import org.apache.nifi.web.api.dto.flow.FlowBreadcrumbDTO;
+import org.apache.nifi.web.api.dto.flow.FlowDTO;
+import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
 import org.apache.nifi.web.api.dto.provenance.lineage.LineageDTO;
 import org.apache.nifi.web.api.dto.provenance.lineage.LineageRequestDTO;
 import org.apache.nifi.web.api.dto.provenance.lineage.LineageRequestDTO.LineageRequestType;
@@ -163,6 +169,8 @@ public final class DtoFactory {
     };
 
     private ControllerServiceLookup controllerServiceLookup;
+    private EntityFactory entityFactory;
+    private Authorizer authorizer;
 
     /**
      * Creates an ActionDTO for the specified Action.
@@ -537,6 +545,7 @@ public final class DtoFactory {
         if (connection == null) {
             return null;
         }
+
         final ConnectionDTO dto = new ConnectionDTO();
 
         dto.setId(connection.getIdentifier());
@@ -652,6 +661,9 @@ public final class DtoFactory {
         if (funnel == null) {
             return null;
         }
+        if (!funnel.isAuthorized(authorizer, RequestAction.READ)) {
+            return null;
+        }
 
         final FunnelDTO dto = new FunnelDTO();
         dto.setId(funnel.getIdentifier());
@@ -1385,27 +1397,34 @@ public final class DtoFactory {
     }
 
     /**
-     * Creates a ProcessGroupDTO from the specified parent ProcessGroup.
+     * Creates a FlowBreadcrumbDTO from the specified parent ProcessGroup.
      *
      * @param parentGroup group
      * @return dto
      */
-    private ProcessGroupDTO createParentProcessGroupDto(final ProcessGroup parentGroup) {
+    private FlowBreadcrumbDTO createBreadcrumbDto(final ProcessGroup parentGroup) {
         if (parentGroup == null) {
             return null;
         }
 
-        final ProcessGroupDTO dto = new ProcessGroupDTO();
+        final FlowBreadcrumbDTO dto = new FlowBreadcrumbDTO();
         dto.setId(parentGroup.getIdentifier());
         dto.setName(parentGroup.getName());
 
         if (parentGroup.getParent() != null) {
-            dto.setParent(createParentProcessGroupDto(parentGroup.getParent()));
+            dto.setParentBreadcrumb(createBreadcrumbDto(parentGroup.getParent()));
         }
 
         return dto;
     }
 
+    public AccessPolicyDTO createAccessPolicyDto(final Authorizable authorizable) {
+        final AccessPolicyDTO dto = new AccessPolicyDTO();
+        dto.setCanRead(authorizable.isAuthorized(authorizer, RequestAction.READ));
+        dto.setCanWrite(authorizable.isAuthorized(authorizer, RequestAction.WRITE));
+        return dto;
+    }
+
     /**
      * Creates a ProcessGroupDTO from the specified ProcessGroup.
      *
@@ -1416,6 +1435,125 @@ public final class DtoFactory {
         return createProcessGroupDto(group, false);
     }
 
+    public ProcessGroupFlowDTO createProcessGroupFlowDto(final ProcessGroup group, final boolean recurse) {
+        final ProcessGroupFlowDTO dto = new ProcessGroupFlowDTO();
+        dto.setId(group.getIdentifier());
+        dto.setBreadcrumb(createBreadcrumbDto(group));
+        dto.setFlow(createFlowDto(group));
+
+        final ProcessGroup parent = group.getParent();
+        if (parent != null) {
+            dto.setParentGroupId(parent.getIdentifier());
+        }
+
+        return dto;
+    }
+
+    public FlowDTO createFlowDto(final ProcessGroup group, final FlowSnippetDTO snippet) {
+        if (snippet == null) {
+            return null;
+        }
+
+        final FlowDTO flow = new FlowDTO();
+
+        for (final ConnectionDTO connection : snippet.getConnections()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getConnection(connection.getId()));
+            flow.getConnections().add(entityFactory.createConnectionEntity(connection, null, accessPolicy));
+        }
+
+        for (final ControllerServiceDTO controllerService : snippet.getControllerServices()) {
+            flow.getControllerServices().add(entityFactory.createControllerServiceEntity(controllerService, null, null));
+        }
+
+        for (final FunnelDTO funnel : snippet.getFunnels()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getFunnel(funnel.getId()));
+            flow.getFunnels().add(entityFactory.createFunnelEntity(funnel, null, accessPolicy));
+        }
+
+        for (final PortDTO inputPort : snippet.getInputPorts()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getInputPort(inputPort.getId()));
+            flow.getInputPorts().add(entityFactory.createPortEntity(inputPort, null, accessPolicy));
+        }
+
+        for (final PortDTO outputPort : snippet.getOutputPorts()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getOutputPort(outputPort.getId()));
+            flow.getOutputPorts().add(entityFactory.createPortEntity(outputPort, null, accessPolicy));
+        }
+
+        for (final LabelDTO label : snippet.getLabels()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getLabel(label.getId()));
+            flow.getLabels().add(entityFactory.createLabelEntity(label, null, accessPolicy));
+        }
+
+        for (final ProcessGroupDTO processGroup : snippet.getProcessGroups()) {
+            // clear the contents as we only return a single level/group at a time
+            processGroup.setContents(null);
+
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getProcessGroup(processGroup.getId()));
+            flow.getProcessGroups().add(entityFactory.createProcessGroupEntity(processGroup, null, accessPolicy));
+        }
+
+        for (final ProcessorDTO processor : snippet.getProcessors()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getProcessor(processor.getId()));
+            flow.getProcessors().add(entityFactory.createProcessorEntity(processor, null, accessPolicy));
+        }
+
+        for (final RemoteProcessGroupDTO remoteProcessGroup : snippet.getRemoteProcessGroups()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(group.getRemoteProcessGroup(remoteProcessGroup.getId()));
+            flow.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(remoteProcessGroup, null, accessPolicy));
+        }
+
+        return flow;
+    }
+
+    public FlowDTO createFlowDto(final ProcessGroup group) {
+        final FlowDTO dto = new FlowDTO();
+
+        for (final ProcessorNode procNode : group.getProcessors()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(procNode);
+            dto.getProcessors().add(entityFactory.createProcessorEntity(createProcessorDto(procNode), null, accessPolicy));
+        }
+
+        for (final Connection connNode : group.getConnections()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(connNode);
+            dto.getConnections().add(entityFactory.createConnectionEntity(createConnectionDto(connNode), null, accessPolicy));
+        }
+
+        for (final Label label : group.getLabels()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(label);
+            dto.getLabels().add(entityFactory.createLabelEntity(createLabelDto(label), null, accessPolicy));
+        }
+
+        for (final Funnel funnel : group.getFunnels()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(funnel);
+            dto.getFunnels().add(entityFactory.createFunnelEntity(createFunnelDto(funnel), null, accessPolicy));
+        }
+
+        for (final ProcessGroup childGroup : group.getProcessGroups()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(childGroup);
+            dto.getProcessGroups().add(entityFactory.createProcessGroupEntity(createProcessGroupDto(childGroup), null, accessPolicy));
+        }
+
+        for (final RemoteProcessGroup rpg : group.getRemoteProcessGroups()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(rpg);
+            dto.getRemoteProcessGroups().add(entityFactory.createRemoteProcessGroupEntity(createRemoteProcessGroupDto(rpg), null, accessPolicy));
+        }
+
+        for (final Port inputPort : group.getInputPorts()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(inputPort);
+            dto.getInputPorts().add(entityFactory.createPortEntity(createPortDto(inputPort), null, accessPolicy));
+        }
+
+        for (final Port outputPort : group.getOutputPorts()) {
+            final AccessPolicyDTO accessPolicy = createAccessPolicyDto(outputPort);
+            dto.getOutputPorts().add(entityFactory.createPortEntity(createPortDto(outputPort), null, accessPolicy));
+        }
+
+        // TODO - controller services once they are accessible from the group
+
+        return dto;
+    }
+
     /**
      * Creates a ProcessGroupDTO from the specified ProcessGroup.
      *
@@ -1449,7 +1587,6 @@ public final class DtoFactory {
         ProcessGroup parentGroup = group.getParent();
         if (parentGroup != null) {
             dto.setParentGroupId(parentGroup.getIdentifier());
-            dto.setParent(createParentProcessGroupDto(parentGroup));
         }
 
         final ProcessGroupCounts counts = group.getCounts();
@@ -1480,7 +1617,6 @@ public final class DtoFactory {
         final FlowSnippetDTO dto = new FlowSnippetDTO();
 
         for (final ProcessorNode procNode : group.getProcessors()) {
-            // authorization check
             dto.getProcessors().add(createProcessorDto(procNode));
         }
 
@@ -2121,7 +2257,6 @@ public final class DtoFactory {
         copy.setPosition(original.getPosition());
         copy.setWidth(original.getWidth());
         copy.setHeight(original.getHeight());
-        copy.setUri(original.getUri());
 
         return copy;
     }
@@ -2139,7 +2274,6 @@ public final class DtoFactory {
         copy.setReferencingComponents(copy(original.getReferencingComponents()));
         copy.setState(original.getState());
         copy.setType(original.getType());
-        copy.setUri(original.getUri());
         copy.setValidationErrors(copy(original.getValidationErrors()));
         return copy;
     }
@@ -2149,7 +2283,6 @@ public final class DtoFactory {
         copy.setId(original.getId());
         copy.setParentGroupId(original.getParentGroupId());
         copy.setPosition(original.getPosition());
-        copy.setUri(original.getUri());
 
         return copy;
     }
@@ -2198,7 +2331,6 @@ public final class DtoFactory {
         copy.setState(original.getState());
         copy.setStyle(copy(original.getStyle()));
         copy.setType(original.getType());
-        copy.setUri(original.getUri());
         copy.setSupportsParallelProcessing(original.getSupportsParallelProcessing());
         copy.setSupportsEventDriven(original.getSupportsEventDriven());
         copy.setValidationErrors(copy(original.getValidationErrors()));
@@ -2242,7 +2374,6 @@ public final class DtoFactory {
         copy.setBackPressureDataSizeThreshold(original.getBackPressureDataSizeThreshold());
         copy.setPrioritizers(copy(original.getPrioritizers()));
         copy.setSource(original.getSource());
-        copy.setUri(original.getUri());
         copy.setzIndex(original.getzIndex());
         copy.setLabelIndex(original.getLabelIndex());
         copy.setBends(copy(original.getBends()));
@@ -2271,7 +2402,6 @@ public final class DtoFactory {
         copy.setName(original.getName());
         copy.setComments(original.getComments());
         copy.setParentGroupId(original.getParentGroupId());
-        copy.setUri(original.getUri());
         copy.setState(original.getState());
         copy.setType(original.getType());
         copy.setTransmitting(original.isTransmitting());
@@ -2300,14 +2430,12 @@ public final class DtoFactory {
     public ProcessGroupDTO copy(final ProcessGroupDTO original, final boolean deep) {
         final ProcessGroupDTO copy = new ProcessGroupDTO();
         copy.setComments(original.getComments());
-        copy.setContents(copy(original.getContents(), deep));
         copy.setPosition(original.getPosition());
         copy.setId(original.getId());
         copy.setInputPortCount(original.getInputPortCount());
         copy.setInvalidCount(original.getInvalidCount());
         copy.setName(original.getName());
         copy.setOutputPortCount(original.getOutputPortCount());
-        copy.setParent(original.getParent());
         copy.setParentGroupId(original.getParentGroupId());
 
         copy.setRunning(original.isRunning());
@@ -2316,7 +2444,6 @@ public final class DtoFactory {
         copy.setDisabledCount(original.getDisabledCount());
         copy.setActiveRemotePortCount(original.getActiveRemotePortCount());
         copy.setInactiveRemotePortCount(original.getInactiveRemotePortCount());
-        copy.setUri(original.getUri());
 
         return copy;
     }
@@ -2356,7 +2483,6 @@ public final class DtoFactory {
         copy.setInactiveRemoteOutputPortCount(original.getInactiveRemoteOutputPortCount());
         copy.setParentGroupId(original.getParentGroupId());
         copy.setTargetUri(original.getTargetUri());
-        copy.setUri(original.getUri());
 
         copy.setContents(copyContents);
 
@@ -2545,6 +2671,12 @@ public final class DtoFactory {
         return revisionDTO;
     }
 
+    public RevisionDTO createRevisionDTO(final Long version, final String clientId) {
+        final RevisionDTO dto = new RevisionDTO();
+        dto.setVersion(version);
+        dto.setClientId(clientId);
+        return dto;
+    }
 
     public NodeDTO createNodeDTO(Node node, NodeHeartbeat nodeHeartbeat, List<Event> events, boolean primary) {
         final NodeDTO nodeDto = new NodeDTO();
@@ -2599,4 +2731,11 @@ public final class DtoFactory {
         this.controllerServiceLookup = lookup;
     }
 
+    public void setAuthorizer(Authorizer authorizer) {
+        this.authorizer = authorizer;
+    }
+
+    public void setEntityFactory(EntityFactory entityFactory) {
+        this.entityFactory = entityFactory;
+    }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java
new file mode 100644
index 0000000..0d46d94
--- /dev/null
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/EntityFactory.java
@@ -0,0 +1,155 @@
+/*
+ * 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.web.api.dto;
+
+import org.apache.nifi.web.api.entity.ConnectionEntity;
+import org.apache.nifi.web.api.entity.ControllerServiceEntity;
+import org.apache.nifi.web.api.entity.FunnelEntity;
+import org.apache.nifi.web.api.entity.LabelEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
+import org.apache.nifi.web.api.entity.ProcessGroupEntity;
+import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
+
+public final class EntityFactory {
+
+    public ProcessorEntity createProcessorEntity(final ProcessorDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final ProcessorEntity entity = new ProcessorEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+    public PortEntity createPortEntity(final PortDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final PortEntity entity = new PortEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            entity.setPortType(dto.getType());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+    public ProcessGroupEntity createProcessGroupEntity(final ProcessGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final ProcessGroupEntity entity = new ProcessGroupEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+    public LabelEntity createLabelEntity(final LabelDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final LabelEntity entity = new LabelEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+
+            final DimensionsDTO dimensions = new DimensionsDTO();
+            dimensions.setHeight(dto.getHeight());
+            dimensions.setWidth(dto.getWidth());
+            entity.setDimensions(dimensions);
+
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+    public FunnelEntity createFunnelEntity(final FunnelDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final FunnelEntity entity = new FunnelEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+    public ConnectionEntity createConnectionEntity(final ConnectionDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final ConnectionEntity entity = new ConnectionEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            entity.setBends(dto.getBends());
+            entity.setLabelIndex(dto.getLabelIndex());
+            entity.setSourceId(dto.getSource().getId());
+            entity.setSourceGroupId(dto.getSource().getGroupId());
+            entity.setDestinationId(dto.getDestination().getId());
+            entity.setDestinationGroupId(dto.getDestination().getGroupId());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+    public ControllerServiceEntity createControllerServiceEntity(final ControllerServiceDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final ControllerServiceEntity entity = new ControllerServiceEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setControllerService(dto);
+            }
+        }
+        return entity;
+    }
+
+    public RemoteProcessGroupEntity createRemoteProcessGroupEntity(final RemoteProcessGroupDTO dto, final RevisionDTO revision, final AccessPolicyDTO accessPolicy) {
+        final RemoteProcessGroupEntity entity = new RemoteProcessGroupEntity();
+        entity.setRevision(revision);
+        if (dto != null) {
+            entity.setAccessPolicy(accessPolicy);
+            entity.setId(dto.getId());
+            entity.setPosition(dto.getPosition());
+            if (accessPolicy != null && accessPolicy.getCanRead()) {
+                entity.setComponent(dto);
+            }
+        }
+        return entity;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
index e8686a3..40e2ee8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java
@@ -21,8 +21,11 @@ import org.apache.commons.lang3.ClassUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.admin.service.KeyService;
 import org.apache.nifi.authorization.Resource;
+import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.resource.ResourceFactory;
 import org.apache.nifi.authorization.resource.ResourceType;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.protocol.NodeIdentifier;
 import org.apache.nifi.components.PropertyDescriptor;
 import org.apache.nifi.connectable.Connectable;
@@ -79,7 +82,6 @@ import org.apache.nifi.search.SearchContext;
 import org.apache.nifi.search.SearchResult;
 import org.apache.nifi.search.Searchable;
 import org.apache.nifi.services.FlowService;
-import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.util.NiFiProperties;
 import org.apache.nifi.web.DownloadableContent;
@@ -108,7 +110,6 @@ import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
 import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
 import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
 import org.apache.nifi.web.security.ProxiedEntitiesUtils;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -132,7 +133,7 @@ import java.util.TimeZone;
 import java.util.TreeSet;
 import java.util.concurrent.TimeUnit;
 
-public class ControllerFacade {
+public class ControllerFacade implements Authorizable {
 
     private static final Logger logger = LoggerFactory.getLogger(ControllerFacade.class);
 
@@ -177,6 +178,16 @@ public class ControllerFacade {
         flowController.setName(name);
     }
 
+    @Override
+    public Authorizable getParentAuthorizable() {
+        return null;
+    }
+
+    @Override
+    public Resource getResource() {
+        return ResourceFactory.getControllerResource();
+    }
+
     /**
      * Sets the comments of this controller.
      *

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java
index 014a607..13fe66d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java
@@ -16,11 +16,12 @@
  */
 package org.apache.nifi.web.dao;
 
-import java.util.Set;
 import org.apache.nifi.controller.Template;
 import org.apache.nifi.web.api.dto.FlowSnippetDTO;
 import org.apache.nifi.web.api.dto.TemplateDTO;
 
+import java.util.Set;
+
 public interface TemplateDAO {
 
     /**

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
index 29bd9b3..8a6bc3e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardConnectionDAO.java
@@ -16,7 +16,10 @@
  */
 package org.apache.nifi.web.dao.impl;
 
-import org.apache.nifi.admin.service.KeyService;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.connectable.Connectable;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.connectable.Connection;
@@ -34,7 +37,6 @@ import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.groups.RemoteProcessGroup;
 import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.remote.RemoteGroupPort;
-import org.apache.nifi.user.NiFiUser;
 import org.apache.nifi.util.FormatUtils;
 import org.apache.nifi.web.DownloadableContent;
 import org.apache.nifi.web.ResourceNotFoundException;
@@ -43,7 +45,6 @@ import org.apache.nifi.web.api.dto.ConnectionDTO;
 import org.apache.nifi.web.api.dto.PositionDTO;
 import org.apache.nifi.web.dao.ConnectionDAO;
 import org.apache.nifi.web.security.ProxiedEntitiesUtils;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -63,7 +64,7 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
     private static final Logger logger = LoggerFactory.getLogger(StandardConnectionDAO.class);
 
     private FlowController flowController;
-    private KeyService keyService;
+    private Authorizer authorizer;
 
     private Connection locateConnection(final String connectionId) {
         final ProcessGroup rootGroup = flowController.getGroup(flowController.getRootGroupId());
@@ -292,6 +293,9 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
             source = sourceGroup.getConnectable(sourceConnectableDTO.getId());
         }
 
+        // ensure the user has write access to the source component
+        source.authorize(authorizer, RequestAction.WRITE);
+
         // find the destination
         final Connectable destination;
         if (ConnectableType.REMOTE_INPUT_PORT.name().equals(destinationConnectableDTO.getType())) {
@@ -315,6 +319,9 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
             destination = destinationGroup.getConnectable(destinationConnectableDTO.getId());
         }
 
+        // ensure the user has write access to the source component
+        destination.authorize(authorizer, RequestAction.WRITE);
+
         // determine the relationships
         final Set<String> relationships = new HashSet<>();
         if (isNotNull(connectionDTO.getSelectedRelationships())) {
@@ -612,7 +619,7 @@ public class StandardConnectionDAO extends ComponentDAO implements ConnectionDAO
         this.flowController = flowController;
     }
 
-    public void setKeyService(KeyService keyService) {
-        this.keyService = keyService;
+    public void setAuthorizer(Authorizer authorizer) {
+        this.authorizer = authorizer;
     }
 }

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/filter/RequestLogger.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/filter/RequestLogger.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/filter/RequestLogger.java
index 9f63611..bb30a1e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/filter/RequestLogger.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/filter/RequestLogger.java
@@ -26,9 +26,9 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 
+import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.logging.NiFiLog;
-import org.apache.nifi.web.security.user.NiFiUserUtils;
-import org.apache.nifi.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUser;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index 0f79369..9f13a23 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -49,9 +49,14 @@
         <property name="clusterManager" ref="clusterManager"/>
     </bean>
 
+    <!-- entity factory -->
+    <bean id="entityFactory" class="org.apache.nifi.web.api.dto.EntityFactory"></bean>
+
     <!-- dto factory -->
     <bean id="dtoFactory" class="org.apache.nifi.web.api.dto.DtoFactory">
         <property name="controllerServiceLookup" ref="controllerServiceProvider" />
+        <property name="entityFactory" ref="entityFactory"/>
+        <property name="authorizer" ref="authorizer"/>
     </bean>
 
     <!-- snippet utils -->
@@ -81,7 +86,7 @@
     </bean>
     <bean id="connectionDAO" class="org.apache.nifi.web.dao.impl.StandardConnectionDAO">
         <property name="flowController" ref="flowController"/>
-        <property name="keyService" ref="keyService"/>
+        <property name="authorizer" ref="authorizer"/>
     </bean>
     <bean id="processorDAO" class="org.apache.nifi.web.dao.impl.StandardProcessorDAO">
         <property name="flowController" ref="flowController"/>
@@ -115,6 +120,7 @@
     </bean>
     <bean id="serviceFacade" class="org.apache.nifi.web.StandardNiFiServiceFacade">
         <property name="properties" ref="nifiProperties"/>
+        <property name="authorizer" ref="authorizer"/>
         <property name="controllerFacade" ref="controllerFacade"/>
         <property name="processorDAO" ref="processorDAO"/>
         <property name="inputPortDAO" ref="inputPortDAO"/>
@@ -133,6 +139,7 @@
         <property name="snippetUtils" ref="snippetUtils"/>
         <property name="optimisticLockingManager" ref="webOptimisticLockingManager"/>
         <property name="dtoFactory" ref="dtoFactory"/>
+        <property name="entityFactory" ref="entityFactory"/>
         <property name="clusterManager" ref="clusterManager"/>
     </bean>
 
@@ -158,8 +165,19 @@
     <!-- rest endpoints -->
     <bean id="flowResource" class="org.apache.nifi.web.api.FlowResource" scope="singleton">
         <property name="serviceFacade" ref="serviceFacade"/>
+        <property name="authorizer" ref="authorizer"/>
         <property name="properties" ref="nifiProperties"/>
         <property name="clusterManager" ref="clusterManager"/>
+        <property name="processorResource" ref="processorResource"/>
+        <property name="inputPortResource" ref="inputPortResource"/>
+        <property name="outputPortResource" ref="outputPortResource"/>
+        <property name="funnelResource" ref="funnelResource"/>
+        <property name="labelResource" ref="labelResource"/>
+        <property name="remoteProcessGroupResource" ref="remoteProcessGroupResource"/>
+        <property name="connectionResource" ref="connectionResource"/>
+        <property name="templateResource" ref="templateResource"/>
+        <property name="controllerServiceResource" ref="controllerServiceResource"/>
+        <property name="processGroupResource" ref="processGroupResource"/>
     </bean>
     <bean id="resourceResource" class="org.apache.nifi.web.api.ResourceResource" scope="singleton">
         <property name="serviceFacade" ref="serviceFacade"/>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
index dbe158a..eecc28a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/NiFiWebApiTest.java
@@ -19,8 +19,6 @@ package org.apache.nifi.integration;
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.ClientResponse.Status;
-import java.util.HashSet;
-import java.util.Set;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.integration.accesscontrol.DfmAccessControlTest;
 import org.apache.nifi.integration.util.NiFiTestUser;
@@ -34,13 +32,15 @@ import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.api.dto.ProcessorDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
 import org.apache.nifi.web.api.entity.ConnectionEntity;
-import org.apache.nifi.web.api.entity.InputPortEntity;
 import org.apache.nifi.web.api.entity.LabelEntity;
-import org.apache.nifi.web.api.entity.OutputPortEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupEntity;
 import org.apache.nifi.web.api.entity.ProcessorEntity;
 import org.junit.Ignore;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  *
  */
@@ -66,7 +66,7 @@ public class NiFiWebApiTest {
         // create the local selection processor entity
         ProcessorEntity processorEntity = new ProcessorEntity();
         processorEntity.setRevision(revision);
-        processorEntity.setProcessor(processorDTO);
+        processorEntity.setComponent(processorDTO);
 
         // add the processor
         ClientResponse response = dfm.testPost(baseUrl + "/controller/process-groups/root/processors", processorEntity);
@@ -81,7 +81,7 @@ public class NiFiWebApiTest {
 
         // get the processors id
         processorEntity = response.getEntity(ProcessorEntity.class);
-        processorDTO = processorEntity.getProcessor();
+        processorDTO = processorEntity.getComponent();
         String localSelectionId = processorDTO.getId();
 
         // -----------------------------------------------
@@ -95,7 +95,7 @@ public class NiFiWebApiTest {
         // create the termination processor entity
         processorEntity = new ProcessorEntity();
         processorEntity.setRevision(revision);
-        processorEntity.setProcessor(processorDTO);
+        processorEntity.setComponent(processorDTO);
 
         // add the processor
         response = dfm.testPost(baseUrl + "/controller/process-groups/root/processors", processorEntity);
@@ -110,7 +110,7 @@ public class NiFiWebApiTest {
 
         // get the processors id
         processorEntity = response.getEntity(ProcessorEntity.class);
-        processorDTO = processorEntity.getProcessor();
+        processorDTO = processorEntity.getComponent();
         String terminationId = processorDTO.getId();
 
         // -----------------------------------------------
@@ -137,7 +137,7 @@ public class NiFiWebApiTest {
         // create the connection entity
         ConnectionEntity connectionEntity = new ConnectionEntity();
         connectionEntity.setRevision(revision);
-        connectionEntity.setConnection(connectionDTO);
+        connectionEntity.setComponent(connectionDTO);
 
         // add the processor
         response = dfm.testPost(baseUrl + "/controller/process-groups/root/connections", connectionEntity);
@@ -160,7 +160,7 @@ public class NiFiWebApiTest {
         // create the label entity
         LabelEntity labelEntity = new LabelEntity();
         labelEntity.setRevision(revision);
-        labelEntity.setLabel(labelDTO);
+        labelEntity.setComponent(labelDTO);
 
         // add the label
         response = dfm.testPost(baseUrl + "/controller/process-groups/root/labels", labelEntity);
@@ -183,7 +183,7 @@ public class NiFiWebApiTest {
         // create the process group entity
         ProcessGroupEntity processGroupEntity = new ProcessGroupEntity();
         processGroupEntity.setRevision(revision);
-        processGroupEntity.setProcessGroup(processGroup);
+        processGroupEntity.setComponent(processGroup);
 
         // add the process group
         response = dfm.testPost(baseUrl + "/controller/process-groups/root/process-group-references", processGroupEntity);
@@ -204,9 +204,9 @@ public class NiFiWebApiTest {
         inputPort.setName("input");
 
         // create the input port entity
-        InputPortEntity inputPortEntity = new InputPortEntity();
+        PortEntity inputPortEntity = new PortEntity();
         inputPortEntity.setRevision(revision);
-        inputPortEntity.setInputPort(inputPort);
+        inputPortEntity.setComponent(inputPort);
 
         // add the input port
         response = dfm.testPost(baseUrl + "/controller/process-groups/root/input-ports", inputPortEntity);
@@ -227,9 +227,9 @@ public class NiFiWebApiTest {
         outputPort.setName("output");
 
         // create the process group entity
-        OutputPortEntity outputPortEntity = new OutputPortEntity();
+        PortEntity outputPortEntity = new PortEntity();
         outputPortEntity.setRevision(revision);
-        outputPortEntity.setOutputPort(outputPort);
+        outputPortEntity.setComponent(outputPort);
 
         // add the output port
         response = dfm.testPost(baseUrl + "/controller/process-groups/root/output-ports", outputPortEntity);

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessTokenEndpointTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessTokenEndpointTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessTokenEndpointTest.java
index 5b96c6e..e43747d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessTokenEndpointTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AccessTokenEndpointTest.java
@@ -166,7 +166,7 @@ public class AccessTokenEndpointTest {
         // create the entity body
         ProcessorEntity entity = new ProcessorEntity();
         entity.setRevision(revision);
-        entity.setProcessor(processor);
+        entity.setComponent(processor);
 
         // perform the request
         ClientResponse response = TOKEN_USER.testPostWithHeaders(url, entity, headers);
@@ -178,7 +178,7 @@ public class AccessTokenEndpointTest {
         entity = response.getEntity(ProcessorEntity.class);
 
         // verify creation
-        processor = entity.getProcessor();
+        processor = entity.getComponent();
         Assert.assertEquals("Copy", processor.getName());
         Assert.assertEquals("org.apache.nifi.integration.util.SourceTestProcessor", processor.getType());
 

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java
index dd69954..12693b2 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/AdminAccessControlTest.java
@@ -17,9 +17,7 @@
 package org.apache.nifi.integration.accesscontrol;
 
 import com.sun.jersey.api.client.ClientResponse;
-import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.nifi.integration.NiFiWebApiTest;
 import org.apache.nifi.integration.util.NiFiTestServer;
 import org.apache.nifi.integration.util.NiFiTestUser;
@@ -35,12 +33,11 @@ import org.apache.nifi.web.api.entity.BannerEntity;
 import org.apache.nifi.web.api.entity.ConnectionEntity;
 import org.apache.nifi.web.api.entity.ConnectionsEntity;
 import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
-import org.apache.nifi.web.api.entity.InputPortEntity;
 import org.apache.nifi.web.api.entity.InputPortsEntity;
 import org.apache.nifi.web.api.entity.LabelEntity;
 import org.apache.nifi.web.api.entity.LabelsEntity;
-import org.apache.nifi.web.api.entity.OutputPortEntity;
 import org.apache.nifi.web.api.entity.OutputPortsEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.entity.PrioritizerTypesEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupsEntity;
@@ -49,13 +46,16 @@ import org.apache.nifi.web.api.entity.ProcessorTypesEntity;
 import org.apache.nifi.web.api.entity.ProcessorsEntity;
 import org.apache.nifi.web.api.entity.UserEntity;
 import org.apache.nifi.web.api.entity.UsersEntity;
-import org.apache.commons.collections4.CollectionUtils;
 import org.junit.AfterClass;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Access control test for the admin user.
  */
@@ -129,7 +129,7 @@ public class AdminAccessControlTest {
         Assert.assertNotNull(processGroupEntity);
 
         // extract the process group dto
-        ProcessGroupDTO processGroupDTO = processGroupEntity.getProcessGroup();
+        ProcessGroupDTO processGroupDTO = processGroupEntity.getComponent();
         FlowSnippetDTO processGroupContentsDTO = processGroupDTO.getContents();
 
         // verify graph
@@ -634,7 +634,7 @@ public class AdminAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        InputPortEntity entity = new InputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request
@@ -659,7 +659,7 @@ public class AdminAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        InputPortEntity entity = new InputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request
@@ -724,7 +724,7 @@ public class AdminAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        OutputPortEntity entity = new OutputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request
@@ -749,7 +749,7 @@ public class AdminAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        OutputPortEntity entity = new OutputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java
index 914cf60..ecbb374 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/DfmAccessControlTest.java
@@ -20,19 +20,6 @@ import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.multipart.BodyPart;
 import com.sun.jersey.multipart.FormDataBodyPart;
 import com.sun.jersey.multipart.FormDataMultiPart;
-import java.io.File;
-import java.nio.file.DirectoryStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import javax.ws.rs.core.MediaType;
-import org.junit.Assert;
 import org.apache.nifi.connectable.ConnectableType;
 import org.apache.nifi.controller.ScheduledState;
 import org.apache.nifi.integration.NiFiWebApiTest;
@@ -57,12 +44,11 @@ import org.apache.nifi.web.api.entity.BannerEntity;
 import org.apache.nifi.web.api.entity.ConnectionEntity;
 import org.apache.nifi.web.api.entity.ConnectionsEntity;
 import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
-import org.apache.nifi.web.api.entity.InputPortEntity;
 import org.apache.nifi.web.api.entity.InputPortsEntity;
 import org.apache.nifi.web.api.entity.LabelEntity;
 import org.apache.nifi.web.api.entity.LabelsEntity;
-import org.apache.nifi.web.api.entity.OutputPortEntity;
 import org.apache.nifi.web.api.entity.OutputPortsEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.entity.PrioritizerTypesEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupsEntity;
@@ -71,10 +57,24 @@ import org.apache.nifi.web.api.entity.ProcessorTypesEntity;
 import org.apache.nifi.web.api.entity.ProcessorsEntity;
 import org.apache.nifi.web.api.entity.TemplateEntity;
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import javax.ws.rs.core.MediaType;
+import java.io.File;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
 /**
  * Access control test for the dfm user.
  */
@@ -159,7 +159,7 @@ public class DfmAccessControlTest {
         Assert.assertNotNull(processGroupEntity);
 
         // extract the process group dto
-        ProcessGroupDTO processGroupDTO = processGroupEntity.getProcessGroup();
+        ProcessGroupDTO processGroupDTO = processGroupEntity.getComponent();
         FlowSnippetDTO processGroupContentsDTO = processGroupDTO.getContents();
 
         // verify graph
@@ -371,7 +371,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ProcessGroupEntity entity = new ProcessGroupEntity();
         entity.setRevision(revision);
-        entity.setProcessGroup(processGroup);
+        entity.setComponent(processGroup);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + processGroup.getId(), entity);
@@ -401,7 +401,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ProcessGroupEntity entity = new ProcessGroupEntity();
         entity.setRevision(revision);
-        entity.setProcessGroup(processGroup);
+        entity.setComponent(processGroup);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + processGroup.getId(), entity);
@@ -411,8 +411,8 @@ public class DfmAccessControlTest {
 
         // get the result
         entity = response.getEntity(ProcessGroupEntity.class);
-        Assert.assertNotNull(entity.getProcessGroup());
-        Assert.assertEquals("new group name", entity.getProcessGroup().getName());
+        Assert.assertNotNull(entity.getComponent());
+        Assert.assertEquals("new group name", entity.getComponent().getName());
     }
 
     /**
@@ -436,7 +436,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ProcessorEntity entity = new ProcessorEntity();
         entity.setRevision(revision);
-        entity.setProcessor(processor);
+        entity.setComponent(processor);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + processor.getId(), entity);
@@ -466,7 +466,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ProcessorEntity entity = new ProcessorEntity();
         entity.setRevision(revision);
-        entity.setProcessor(processor);
+        entity.setComponent(processor);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + processor.getId(), entity);
@@ -476,8 +476,8 @@ public class DfmAccessControlTest {
 
         // get the result
         entity = response.getEntity(ProcessorEntity.class);
-        Assert.assertNotNull(entity.getProcessor());
-        Assert.assertEquals("new processor name", entity.getProcessor().getName());
+        Assert.assertNotNull(entity.getComponent());
+        Assert.assertEquals("new processor name", entity.getComponent().getName());
     }
 
     /**
@@ -501,7 +501,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ConnectionEntity entity = new ConnectionEntity();
         entity.setRevision(revision);
-        entity.setConnection(connection);
+        entity.setComponent(connection);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + connection.getId(), entity);
@@ -531,7 +531,7 @@ public class DfmAccessControlTest {
         // create the entity body
         LabelEntity entity = new LabelEntity();
         entity.setRevision(revision);
-        entity.setLabel(label);
+        entity.setComponent(label);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + label.getId(), entity);
@@ -541,8 +541,8 @@ public class DfmAccessControlTest {
 
         // get the result
         entity = response.getEntity(LabelEntity.class);
-        Assert.assertNotNull(entity.getLabel());
-        Assert.assertEquals("new label", entity.getLabel().getLabel());
+        Assert.assertNotNull(entity.getComponent());
+        Assert.assertEquals("new label", entity.getComponent().getLabel());
     }
 
     /**
@@ -564,9 +564,9 @@ public class DfmAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        InputPortEntity entity = new InputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
-        entity.setInputPort(inputPort);
+        entity.setComponent(inputPort);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + inputPort.getId(), entity);
@@ -575,9 +575,9 @@ public class DfmAccessControlTest {
         Assert.assertEquals(200, response.getStatus());
 
         // get the result
-        entity = response.getEntity(InputPortEntity.class);
-        Assert.assertNotNull(entity.getInputPort());
-        Assert.assertEquals("new input port name", entity.getInputPort().getName());
+        entity = response.getEntity(PortEntity.class);
+        Assert.assertNotNull(entity.getComponent());
+        Assert.assertEquals("new input port name", entity.getComponent().getName());
     }
 
     /**
@@ -599,9 +599,9 @@ public class DfmAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        OutputPortEntity entity = new OutputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
-        entity.setOutputPort(outputPort);
+        entity.setComponent(outputPort);
 
         // perform the request
         ClientResponse response = DFM_USER.testPut(url + "/" + outputPort.getId(), entity);
@@ -610,9 +610,9 @@ public class DfmAccessControlTest {
         Assert.assertEquals(200, response.getStatus());
 
         // get the result
-        entity = response.getEntity(OutputPortEntity.class);
-        Assert.assertNotNull(entity.getOutputPort());
-        Assert.assertEquals("new output port name", entity.getOutputPort().getName());
+        entity = response.getEntity(PortEntity.class);
+        Assert.assertNotNull(entity.getComponent());
+        Assert.assertEquals("new output port name", entity.getComponent().getName());
     }
 
     // ----------------------------------------------
@@ -761,15 +761,15 @@ public class DfmAccessControlTest {
 
         // get the process group dtos
         ProcessGroupsEntity processGroupEntity = response.getEntity(ProcessGroupsEntity.class);
-        Collection<ProcessGroupDTO> processGroups = processGroupEntity.getProcessGroups();
+        Collection<ProcessGroupEntity> processGroups = processGroupEntity.getProcessGroups();
 
         // ensure the correct number of processor groups
         Assert.assertFalse(processGroups.isEmpty());
 
         // use the first process group as the target
-        Iterator<ProcessGroupDTO> processorIter = processGroups.iterator();
+        Iterator<ProcessGroupEntity> processorIter = processGroups.iterator();
         Assert.assertTrue(processorIter.hasNext());
-        return processorIter.next();
+        return processorIter.next().getComponent();
     }
 
     private ProcessorDTO getRandomProcessor() throws Exception {
@@ -783,15 +783,15 @@ public class DfmAccessControlTest {
 
         // get the processor dtos
         ProcessorsEntity processorsEntity = response.getEntity(ProcessorsEntity.class);
-        Collection<ProcessorDTO> processors = processorsEntity.getProcessors();
+        Collection<ProcessorEntity> processors = processorsEntity.getProcessors();
 
         // ensure the correct number of processors
         Assert.assertFalse(processors.isEmpty());
 
         // use the first processor as the target
-        Iterator<ProcessorDTO> processorIter = processors.iterator();
+        Iterator<ProcessorEntity> processorIter = processors.iterator();
         Assert.assertTrue(processorIter.hasNext());
-        return processorIter.next();
+        return processorIter.next().getComponent();
     }
 
     private ConnectionDTO getRandomConnection() throws Exception {
@@ -805,15 +805,15 @@ public class DfmAccessControlTest {
 
         // get the connection dtos
         ConnectionsEntity connectionEntity = response.getEntity(ConnectionsEntity.class);
-        Collection<ConnectionDTO> connections = connectionEntity.getConnections();
+        Collection<ConnectionEntity> connections = connectionEntity.getConnections();
 
         // ensure the correct number of connections
         Assert.assertFalse(connections.isEmpty());
 
         // use the first connection as the target
-        Iterator<ConnectionDTO> connectionIter = connections.iterator();
+        Iterator<ConnectionEntity> connectionIter = connections.iterator();
         Assert.assertTrue(connectionIter.hasNext());
-        return connectionIter.next();
+        return connectionIter.next().getComponent();
     }
 
     private LabelDTO getRandomLabel() throws Exception {
@@ -827,15 +827,15 @@ public class DfmAccessControlTest {
 
         // get the label dtos
         LabelsEntity labelEntity = response.getEntity(LabelsEntity.class);
-        Collection<LabelDTO> labels = labelEntity.getLabels();
+        Collection<LabelEntity> labels = labelEntity.getLabels();
 
         // ensure the correct number of labels
         Assert.assertFalse(labels.isEmpty());
 
         // use the first label as the target
-        Iterator<LabelDTO> labelIter = labels.iterator();
+        Iterator<LabelEntity> labelIter = labels.iterator();
         Assert.assertTrue(labelIter.hasNext());
-        return labelIter.next();
+        return labelIter.next().getComponent();
     }
 
     private PortDTO getRandomInputPort() throws Exception {
@@ -849,15 +849,15 @@ public class DfmAccessControlTest {
 
         // get the port dtos
         InputPortsEntity inputPortsEntity = response.getEntity(InputPortsEntity.class);
-        Collection<PortDTO> inputPorts = inputPortsEntity.getInputPorts();
+        Collection<PortEntity> inputPorts = inputPortsEntity.getInputPorts();
 
         // ensure the correct number of ports
         Assert.assertFalse(inputPorts.isEmpty());
 
         // use the first port as the target
-        Iterator<PortDTO> inputPortsIter = inputPorts.iterator();
+        Iterator<PortEntity> inputPortsIter = inputPorts.iterator();
         Assert.assertTrue(inputPortsIter.hasNext());
-        return inputPortsIter.next();
+        return inputPortsIter.next().getComponent();
     }
 
     private PortDTO getRandomOutputPort() throws Exception {
@@ -871,15 +871,15 @@ public class DfmAccessControlTest {
 
         // get the port dtos
         OutputPortsEntity outputPortsEntity = response.getEntity(OutputPortsEntity.class);
-        Collection<PortDTO> outputPorts = outputPortsEntity.getOutputPorts();
+        Collection<PortEntity> outputPorts = outputPortsEntity.getOutputPorts();
 
         // ensure the correct number of ports
         Assert.assertFalse(outputPorts.isEmpty());
 
         // use the first port as the target
-        Iterator<PortDTO> inputPortsIter = outputPorts.iterator();
+        Iterator<PortEntity> inputPortsIter = outputPorts.iterator();
         Assert.assertTrue(inputPortsIter.hasNext());
-        return inputPortsIter.next();
+        return inputPortsIter.next().getComponent();
     }
 
     // ----------------------------------------------
@@ -900,7 +900,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ProcessGroupEntity entity = new ProcessGroupEntity();
         entity.setRevision(revision);
-        entity.setProcessGroup(processGroup);
+        entity.setComponent(processGroup);
 
         // perform the request
         ClientResponse response = DFM_USER.testPost(url, entity);
@@ -912,7 +912,7 @@ public class DfmAccessControlTest {
         entity = response.getEntity(ProcessGroupEntity.class);
 
         // verify creation
-        processGroup = entity.getProcessGroup();
+        processGroup = entity.getComponent();
         Assert.assertEquals("Group1", processGroup.getName());
 
         // get the process group
@@ -932,9 +932,9 @@ public class DfmAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        InputPortEntity entity = new InputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
-        entity.setInputPort(portDTO);
+        entity.setComponent(portDTO);
 
         // perform the request
         ClientResponse response = DFM_USER.testPost(url, entity);
@@ -943,10 +943,10 @@ public class DfmAccessControlTest {
         Assert.assertEquals(201, response.getStatus());
 
         // get the entity body
-        entity = response.getEntity(InputPortEntity.class);
+        entity = response.getEntity(PortEntity.class);
 
         // verify creation
-        portDTO = entity.getInputPort();
+        portDTO = entity.getComponent();
         Assert.assertEquals("Input Port", portDTO.getName());
 
         // get the process group
@@ -966,9 +966,9 @@ public class DfmAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        OutputPortEntity entity = new OutputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
-        entity.setOutputPort(portDTO);
+        entity.setComponent(portDTO);
 
         // perform the request
         ClientResponse response = DFM_USER.testPost(url, entity);
@@ -977,10 +977,10 @@ public class DfmAccessControlTest {
         Assert.assertEquals(201, response.getStatus());
 
         // get the entity body
-        entity = response.getEntity(OutputPortEntity.class);
+        entity = response.getEntity(PortEntity.class);
 
         // verify creation
-        portDTO = entity.getOutputPort();
+        portDTO = entity.getComponent();
         Assert.assertEquals("Output Port", portDTO.getName());
 
         // get the process group
@@ -1003,7 +1003,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ProcessorEntity entity = new ProcessorEntity();
         entity.setRevision(revision);
-        entity.setProcessor(processor);
+        entity.setComponent(processor);
 
         // perform the request
         ClientResponse response = DFM_USER.testPost(url, entity);
@@ -1015,7 +1015,7 @@ public class DfmAccessControlTest {
         entity = response.getEntity(ProcessorEntity.class);
 
         // verify creation
-        processor = entity.getProcessor();
+        processor = entity.getComponent();
         Assert.assertEquals("Copy", processor.getName());
         Assert.assertEquals("org.apache.nifi.integration.util.SourceTestProcessor", processor.getType());
 
@@ -1054,7 +1054,7 @@ public class DfmAccessControlTest {
         // create the entity body
         ConnectionEntity entity = new ConnectionEntity();
         entity.setRevision(revision);
-        entity.setConnection(connection);
+        entity.setComponent(connection);
 
         // perform the request
         ClientResponse response = DFM_USER.testPost(url, entity);
@@ -1066,7 +1066,7 @@ public class DfmAccessControlTest {
         entity = response.getEntity(ConnectionEntity.class);
 
         // verify the results
-        connection = entity.getConnection();
+        connection = entity.getComponent();
         Assert.assertEquals(sourceId, connection.getSource().getId());
         Assert.assertEquals(targetId, connection.getDestination().getId());
         Assert.assertEquals(1, connection.getSelectedRelationships().size());
@@ -1091,7 +1091,7 @@ public class DfmAccessControlTest {
         // create the entity body
         LabelEntity entity = new LabelEntity();
         entity.setRevision(revision);
-        entity.setLabel(label);
+        entity.setComponent(label);
 
         // perform the request
         ClientResponse response = DFM_USER.testPost(url, entity);
@@ -1103,7 +1103,7 @@ public class DfmAccessControlTest {
         entity = response.getEntity(LabelEntity.class);
 
         // verify the results
-        label = entity.getLabel();
+        label = entity.getComponent();
         Assert.assertEquals("Label2", label.getLabel());
 
         // get the label id

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java
index 2ed653a..98a8cd0 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/accesscontrol/ReadOnlyAccessControlTest.java
@@ -17,9 +17,6 @@
 package org.apache.nifi.integration.accesscontrol;
 
 import com.sun.jersey.api.client.ClientResponse;
-import java.io.File;
-import java.util.HashMap;
-import java.util.Map;
 import org.apache.nifi.integration.NiFiWebApiTest;
 import org.apache.nifi.integration.util.NiFiTestServer;
 import org.apache.nifi.integration.util.NiFiTestUser;
@@ -34,12 +31,11 @@ import org.apache.nifi.web.api.entity.BannerEntity;
 import org.apache.nifi.web.api.entity.ConnectionEntity;
 import org.apache.nifi.web.api.entity.ConnectionsEntity;
 import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
-import org.apache.nifi.web.api.entity.InputPortEntity;
 import org.apache.nifi.web.api.entity.InputPortsEntity;
 import org.apache.nifi.web.api.entity.LabelEntity;
 import org.apache.nifi.web.api.entity.LabelsEntity;
-import org.apache.nifi.web.api.entity.OutputPortEntity;
 import org.apache.nifi.web.api.entity.OutputPortsEntity;
+import org.apache.nifi.web.api.entity.PortEntity;
 import org.apache.nifi.web.api.entity.PrioritizerTypesEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupEntity;
 import org.apache.nifi.web.api.entity.ProcessGroupsEntity;
@@ -52,6 +48,10 @@ import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Access control test for a read only user.
  */
@@ -125,7 +125,7 @@ public class ReadOnlyAccessControlTest {
         Assert.assertNotNull(processGroupEntity);
 
         // extract the process group dto
-        ProcessGroupDTO processGroupDTO = processGroupEntity.getProcessGroup();
+        ProcessGroupDTO processGroupDTO = processGroupEntity.getComponent();
         FlowSnippetDTO processGroupContentsDTO = processGroupDTO.getContents();
 
         // verify graph
@@ -625,7 +625,7 @@ public class ReadOnlyAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        InputPortEntity entity = new InputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request
@@ -650,7 +650,7 @@ public class ReadOnlyAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        InputPortEntity entity = new InputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request
@@ -715,7 +715,7 @@ public class ReadOnlyAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        OutputPortEntity entity = new OutputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request
@@ -740,7 +740,7 @@ public class ReadOnlyAccessControlTest {
         revision.setVersion(NiFiTestUser.REVISION);
 
         // create the entity body
-        OutputPortEntity entity = new OutputPortEntity();
+        PortEntity entity = new PortEntity();
         entity.setRevision(revision);
 
         // perform the request

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/pom.xml
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/pom.xml
index 22b387c..9a7c69e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/pom.xml
@@ -42,6 +42,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-framework-authorization</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
             <scope>provided</scope>

http://git-wip-us.apache.org/repos/asf/nifi/blob/ff98d823/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
----------------------------------------------------------------------
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
index 50ca101..00dc06f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-content-viewer/src/main/java/org/apache/nifi/web/ContentViewerController.java
@@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.authorization.AccessDeniedException;
 import org.apache.nifi.stream.io.StreamUtils;
 import org.apache.nifi.web.ViewableContent.DisplayMode;
 import org.apache.tika.detect.DefaultDetector;
@@ -39,7 +40,6 @@ import org.apache.tika.metadata.Metadata;
 import org.apache.tika.mime.MediaType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.security.access.AccessDeniedException;
 
 /**
  * Controller servlet for viewing content. This is responsible for generating