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/06/23 21:10:47 UTC

[08/11] nifi git commit: NIFI-1554: - Addressing access controls for the Controller resource. - Addressing access controls for RAW site to site clients. - Addressing access controls for downloading content (from provenance and queue). - Addressing access

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/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 1e3c776..e04ed44 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
@@ -46,6 +46,9 @@ import org.apache.nifi.web.api.dto.BulletinBoardDTO;
 import org.apache.nifi.web.api.dto.BulletinQueryDTO;
 import org.apache.nifi.web.api.dto.ProcessGroupDTO;
 import org.apache.nifi.web.api.dto.RevisionDTO;
+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.search.SearchResultsDTO;
@@ -59,15 +62,19 @@ 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.AboutEntity;
+import org.apache.nifi.web.api.entity.ActionEntity;
 import org.apache.nifi.web.api.entity.AuthorityEntity;
 import org.apache.nifi.web.api.entity.BannerEntity;
 import org.apache.nifi.web.api.entity.BulletinBoardEntity;
+import org.apache.nifi.web.api.entity.ComponentHistoryEntity;
 import org.apache.nifi.web.api.entity.ConnectionStatusEntity;
 import org.apache.nifi.web.api.entity.ControllerServiceEntity;
 import org.apache.nifi.web.api.entity.ControllerServiceTypesEntity;
 import org.apache.nifi.web.api.entity.ControllerServicesEntity;
 import org.apache.nifi.web.api.entity.ControllerStatusEntity;
 import org.apache.nifi.web.api.entity.Entity;
+import org.apache.nifi.web.api.entity.FlowConfigurationEntity;
+import org.apache.nifi.web.api.entity.HistoryEntity;
 import org.apache.nifi.web.api.entity.IdentityEntity;
 import org.apache.nifi.web.api.entity.PortStatusEntity;
 import org.apache.nifi.web.api.entity.PrioritizerTypesEntity;
@@ -85,6 +92,7 @@ import org.apache.nifi.web.api.entity.SearchResultsEntity;
 import org.apache.nifi.web.api.entity.StatusHistoryEntity;
 import org.apache.nifi.web.api.request.BulletinBoardPatternParameter;
 import org.apache.nifi.web.api.request.ClientIdParameter;
+import org.apache.nifi.web.api.request.DateTimeParameter;
 import org.apache.nifi.web.api.request.IntegerParameter;
 import org.apache.nifi.web.api.request.LongParameter;
 
@@ -187,7 +195,7 @@ public class FlowResource extends ApplicationResource {
     /**
      * Authorizes access to the flow.
      */
-    private void authorizeFlow() {
+    private void authorizeFlow(final RequestAction action) {
         final NiFiUser user = NiFiUserUtils.getNiFiUser();
 
         final AuthorizationRequest request = new AuthorizationRequest.Builder()
@@ -195,7 +203,7 @@ public class FlowResource extends ApplicationResource {
             .identity(user.getIdentity())
             .anonymous(user.isAnonymous())
             .accessAttempt(true)
-            .action(RequestAction.READ)
+            .action(action)
             .build();
 
         final AuthorizationResult result = authorizer.authorize(request);
@@ -233,11 +241,51 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response generateClientId() {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
         return clusterContext(generateOkResponse(generateUuid())).build();
     }
 
     /**
+     * Retrieves the configuration for the flow.
+     *
+     * @return A flowConfigurationEntity.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("config")
+    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN', 'ROLE_NIFI')")
+    @ApiOperation(
+            value = "Retrieves the configuration for this NiFi flow",
+            response = FlowConfigurationEntity.class,
+            authorizations = {
+                    @Authorization(value = "Read Only", type = "ROLE_MONITOR"),
+                    @Authorization(value = "Data Flow Manager", type = "ROLE_DFM"),
+                    @Authorization(value = "Administrator", type = "ROLE_ADMIN"),
+                    @Authorization(value = "ROLE_NIFI", type = "ROLE_NIFI")
+            }
+    )
+    @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 = 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 getFlowConfig() {
+
+        authorizeFlow(RequestAction.READ);
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        final FlowConfigurationEntity entity = serviceFacade.getFlowConfiguration();
+        return clusterContext(generateOkResponse(entity)).build();
+    }
+
+    /**
      * Retrieves the identity of the user making the request.
      *
      * @return An identityEntity
@@ -252,7 +300,7 @@ public class FlowResource extends ApplicationResource {
     )
     public Response getIdentity() {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // note that the cluster manager will handle this request directly
         final NiFiUser user = NiFiUserUtils.getNiFiUser();
@@ -301,9 +349,8 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response getAuthorities() {
-
-        // TODO - Remove
-        authorizeFlow();
+        // TODO - remove this method once authorities are completely removed
+        authorizeFlow(RequestAction.READ);
 
         // note that the cluster manager will handle this request directly
         final NiFiUser user = NiFiUserUtils.getNiFiUser();
@@ -368,7 +415,7 @@ public class FlowResource extends ApplicationResource {
         )
         @QueryParam("recursive") @DefaultValue(RECURSIVE) Boolean recursive) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
@@ -413,6 +460,8 @@ public class FlowResource extends ApplicationResource {
     )
     public Response getControllerServicesFromController() {
 
+        authorizeFlow(RequestAction.READ);
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -464,6 +513,8 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String groupId) throws InterruptedException {
 
+        authorizeFlow(RequestAction.READ);
+
         // get all the controller services
         final Set<ControllerServiceEntity> controllerServices = serviceFacade.getControllerServices(groupId);
         controllerServiceResource.populateRemainingControllerServiceEntitiesContent(controllerServices);
@@ -517,6 +568,8 @@ public class FlowResource extends ApplicationResource {
         )
         @QueryParam(CLIENT_ID) @DefaultValue(StringUtils.EMPTY) ClientIdParameter clientId) {
 
+        authorizeFlow(RequestAction.READ);
+
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
         }
@@ -571,6 +624,8 @@ public class FlowResource extends ApplicationResource {
         @PathParam("id") String id,
         ScheduleComponentsEntity scheduleComponentsEntity) {
 
+        authorizeFlow(RequestAction.READ);
+
         // ensure the same id is being used
         if (!id.equals(scheduleComponentsEntity.getId())) {
             throw new IllegalArgumentException(String.format("The process group id (%s) in the request body does "
@@ -595,7 +650,6 @@ public class FlowResource extends ApplicationResource {
 
         // if the components are not specified, gather all components and their current revision
         if (scheduleComponentsEntity.getComponents() == null) {
-            // TODO - this will break while clustered until nodes are able to process/replicate requests
             // get the current revisions for the components being updated
             final Set<Revision> revisions = serviceFacade.getRevisionsFromGroup(id, group -> {
                 final Set<String> componentIds = new HashSet<>();
@@ -652,9 +706,6 @@ public class FlowResource extends ApplicationResource {
             serviceFacade,
             revisions,
             lookup -> {
-                // ensure access to the flow
-                authorizeFlow();
-
                 // ensure access to every component being scheduled
                 componentsToSchedule.keySet().forEach(componentId -> {
                     final Authorizable connectable = lookup.getConnectable(componentId);
@@ -704,7 +755,7 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response searchFlow(@QueryParam("q") @DefaultValue(StringUtils.EMPTY) String value) throws InterruptedException {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // query the controller
         final SearchResultsDTO results = serviceFacade.searchController(value);
@@ -747,7 +798,7 @@ public class FlowResource extends ApplicationResource {
     )
     public Response getControllerStatus() throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         if (isReplicateRequest()) {
             return replicate(HttpMethod.GET);
@@ -792,7 +843,7 @@ public class FlowResource extends ApplicationResource {
     )
     public Response getBanners() {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // get the banner from the properties - will come from the NCM when clustered
         final String bannerText = getProperties().getBannerText();
@@ -839,7 +890,7 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response getProcessorTypes() throws InterruptedException {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // create response entity
         final ProcessorTypesEntity entity = new ProcessorTypesEntity();
@@ -884,7 +935,7 @@ public class FlowResource extends ApplicationResource {
                     required = false
             )
         @QueryParam("serviceType") String serviceType) throws InterruptedException {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // create response entity
         final ControllerServiceTypesEntity entity = new ControllerServiceTypesEntity();
@@ -923,7 +974,7 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response getReportingTaskTypes() throws InterruptedException {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // create response entity
         final ReportingTaskTypesEntity entity = new ReportingTaskTypesEntity();
@@ -962,7 +1013,7 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response getPrioritizers() throws InterruptedException {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // create response entity
         final PrioritizerTypesEntity entity = new PrioritizerTypesEntity();
@@ -1000,7 +1051,7 @@ public class FlowResource extends ApplicationResource {
             }
     )
     public Response getAboutInfo() {
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // create the about dto
         final AboutDTO aboutDTO = new AboutDTO();
@@ -1090,7 +1141,7 @@ public class FlowResource extends ApplicationResource {
         )
         @QueryParam("limit") IntegerParameter limit) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // replicate if cluster manager
         if (isReplicateRequest()) {
@@ -1181,7 +1232,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
@@ -1263,7 +1314,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
@@ -1345,7 +1396,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
@@ -1427,7 +1478,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
@@ -1518,7 +1569,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String groupId) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
@@ -1621,7 +1672,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // ensure a valid request
         if (Boolean.TRUE.equals(nodewise) && clusterNodeId != null) {
@@ -1697,7 +1748,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // replicate if cluster manager
         if (isReplicateRequest()) {
@@ -1752,7 +1803,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String groupId) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // replicate if cluster manager
         if (isReplicateRequest()) {
@@ -1807,7 +1858,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // replicate if cluster manager
         if (isReplicateRequest()) {
@@ -1862,7 +1913,7 @@ public class FlowResource extends ApplicationResource {
         )
         @PathParam("id") String id) throws InterruptedException {
 
-        authorizeFlow();
+        authorizeFlow(RequestAction.READ);
 
         // replicate if cluster manager
         if (isReplicateRequest()) {
@@ -1880,6 +1931,279 @@ public class FlowResource extends ApplicationResource {
         return clusterContext(generateOkResponse(entity)).build();
     }
 
+    // -------
+    // history
+    // -------
+
+    /**
+     * Queries the history of this Controller.
+     *
+     * @param offset The offset into the data. This parameter is required and is
+     * used in conjunction with count.
+     * @param count The number of rows that should be returned. This parameter
+     * is required and is used in conjunction with page.
+     * @param sortColumn The column to sort on. This parameter is optional. If
+     * not specified the results will be returned with the most recent first.
+     * @param sortOrder The sort order.
+     * @param startDate The start date/time for the query. The start date/time
+     * must be formatted as 'MM/dd/yyyy HH:mm:ss'. This parameter is optional
+     * and must be specified in the timezone of the server. The server's
+     * timezone can be determined by inspecting the result of a status or
+     * history request.
+     * @param endDate The end date/time for the query. The end date/time must be
+     * formatted as 'MM/dd/yyyy HH:mm:ss'. This parameter is optional and must
+     * be specified in the timezone of the server. The server's timezone can be
+     * determined by inspecting the result of a status or history request.
+     * @param userName The user name of the user who's actions are being
+     * queried. This parameter is optional.
+     * @param sourceId The id of the source being queried (usually a processor
+     * id). This parameter is optional.
+     * @return A historyEntity.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("history")
+    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @ApiOperation(
+            value = "Gets configuration history",
+            response = HistoryEntity.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 = 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 queryHistory(
+            @ApiParam(
+                    value = "The offset into the result set.",
+                    required = true
+            )
+            @QueryParam("offset") IntegerParameter offset,
+            @ApiParam(
+                    value = "The number of actions to return.",
+                    required = true
+            )
+            @QueryParam("count") IntegerParameter count,
+            @ApiParam(
+                    value = "The field to sort on.",
+                    required = false
+            )
+            @QueryParam("sortColumn") String sortColumn,
+            @ApiParam(
+                    value = "The direction to sort.",
+                    required = false
+            )
+            @QueryParam("sortOrder") String sortOrder,
+            @ApiParam(
+                    value = "Include actions after this date.",
+                    required = false
+            )
+            @QueryParam("startDate") DateTimeParameter startDate,
+            @ApiParam(
+                    value = "Include actions before this date.",
+                    required = false
+            )
+            @QueryParam("endDate") DateTimeParameter endDate,
+            @ApiParam(
+                    value = "Include actions performed by this user.",
+                    required = false
+            )
+            @QueryParam("userName") String userName,
+            @ApiParam(
+                    value = "Include actions on this component.",
+                    required = false
+            )
+            @QueryParam("sourceId") String sourceId) {
+
+        authorizeFlow(RequestAction.READ);
+
+        // ensure the page is specified
+        if (offset == null) {
+            throw new IllegalArgumentException("The desired offset must be specified.");
+        } else if (offset.getInteger() < 0) {
+            throw new IllegalArgumentException("The desired offset must be an integer value greater than or equal to 0.");
+        }
+
+        // ensure the row count is specified
+        if (count == null) {
+            throw new IllegalArgumentException("The desired row count must be specified.");
+        } else if (count.getInteger() < 1) {
+            throw new IllegalArgumentException("The desired row count must be an integer value greater than 0.");
+        }
+
+        // normalize the sort order
+        if (sortOrder != null) {
+            if (!sortOrder.equalsIgnoreCase("asc") && !sortOrder.equalsIgnoreCase("desc")) {
+                throw new IllegalArgumentException("The sort order must be 'asc' or 'desc'.");
+            }
+        }
+
+        // ensure the start and end dates are specified
+        if (endDate != null && startDate != null) {
+            if (endDate.getDateTime().before(startDate.getDateTime())) {
+                throw new IllegalArgumentException("The start date/time must come before the end date/time.");
+            }
+        }
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        // create a history query
+        final HistoryQueryDTO query = new HistoryQueryDTO();
+        query.setSortColumn(sortColumn);
+        query.setSortOrder(sortOrder);
+        query.setOffset(offset.getInteger());
+        query.setCount(count.getInteger());
+
+        // optionally set the start date
+        if (startDate != null) {
+            query.setStartDate(startDate.getDateTime());
+        }
+
+        // optionally set the end date
+        if (endDate != null) {
+            query.setEndDate(endDate.getDateTime());
+        }
+
+        // optionally set the user id
+        if (userName != null) {
+            query.setUserName(userName);
+        }
+
+        // optionally set the processor id
+        if (sourceId != null) {
+            query.setSourceId(sourceId);
+        }
+
+        // perform the query
+        final HistoryDTO history = serviceFacade.getActions(query);
+
+        // create the response entity
+        final HistoryEntity entity = new HistoryEntity();
+        entity.setHistory(history);
+
+        // generate the response
+        return generateOkResponse(entity).build();
+    }
+
+    /**
+     * Gets the action for the corresponding id.
+     *
+     * @param id The id of the action to get.
+     * @return An actionEntity.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @Path("history/{id}")
+    @ApiOperation(
+            value = "Gets an action",
+            response = ActionEntity.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 getAction(
+            @ApiParam(
+                    value = "The action id.",
+                    required = true
+            )
+            @PathParam("id") IntegerParameter id) {
+
+        authorizeFlow(RequestAction.READ);
+
+        // ensure the id was specified
+        if (id == null) {
+            throw new IllegalArgumentException("The action id must be specified.");
+        }
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        // get the specified action
+        final ActionDTO action = serviceFacade.getAction(id.getInteger());
+
+        // create the response entity
+        final ActionEntity entity = new ActionEntity();
+        entity.setAction(action);
+
+        // generate the response
+        return generateOkResponse(entity).build();
+    }
+
+    /**
+     * Gets the actions for the specified component.
+     *
+     * @param componentId The id of the component.
+     * @return An processorHistoryEntity.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("history/components/{componentId}")
+    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
+    @ApiOperation(
+            value = "Gets configuration history for a processor",
+            response = ComponentHistoryEntity.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 getComponentHistory(
+            @ApiParam(
+                    value = "The component id.",
+                    required = true
+            )
+            @PathParam("componentId") final String componentId) {
+
+        authorizeFlow(RequestAction.READ);
+
+        if (isReplicateRequest()) {
+            return replicate(HttpMethod.GET);
+        }
+
+        // create the response entity
+        final ComponentHistoryEntity entity = new ComponentHistoryEntity();
+        entity.setComponentHistory(serviceFacade.getComponentHistory(componentId));
+
+        // generate the response
+        return generateOkResponse(entity).build();
+    }
+
     // setters
     public void setServiceFacade(NiFiServiceFacade serviceFacade) {
         this.serviceFacade = serviceFacade;

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/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 acaa2b4..de2179c 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
@@ -28,7 +28,6 @@ import org.apache.nifi.authorization.RequestAction;
 import org.apache.nifi.authorization.resource.Authorizable;
 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.entity.FunnelEntity;
 import org.apache.nifi.web.api.request.ClientIdParameter;
@@ -48,7 +47,6 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.net.URI;
 import java.util.Set;
 
 /**
@@ -231,23 +229,16 @@ public class FunnelResource extends ApplicationResource {
             serviceFacade,
             revision,
             lookup -> {
-                final Authorizable funnel = lookup.getFunnel(id);
-                funnel.authorize(authorizer, RequestAction.WRITE);
+                Authorizable authorizable = lookup.getFunnel(id);
+                authorizable.authorize(authorizer, RequestAction.WRITE);
             },
             null,
             () -> {
                 // update the funnel
-                final UpdateResult<FunnelEntity> updateResult = serviceFacade.updateFunnel(revision, requestFunnelDTO);
-
-                // get the results
-                final FunnelEntity entity = updateResult.getResult();
+                final FunnelEntity entity = serviceFacade.updateFunnel(revision, requestFunnelDTO);
                 populateRemainingFunnelEntityContent(entity);
 
-                if (updateResult.isNew()) {
-                    return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
-                } else {
-                    return clusterContext(generateOkResponse(entity)).build();
-                }
+                return clusterContext(generateOkResponse(entity)).build();
             }
         );
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/HistoryResource.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/HistoryResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/HistoryResource.java
deleted file mode 100644
index 714d83e..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/HistoryResource.java
+++ /dev/null
@@ -1,525 +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;
-
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-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.web.NiFiServiceFacade;
-import org.apache.nifi.web.api.dto.RevisionDTO;
-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.entity.ActionEntity;
-import org.apache.nifi.web.api.entity.ComponentHistoryEntity;
-import org.apache.nifi.web.api.entity.HistoryEntity;
-import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.api.request.DateTimeParameter;
-import org.apache.nifi.web.api.request.IntegerParameter;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.GET;
-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.MediaType;
-import javax.ws.rs.core.Response;
-
-/**
- * RESTful endpoint for querying the history of this Controller.
- */
-@Path("/history")
-@Api(
-    value = "/history",
-    description = "Endpoint for accessing flow history."
-)
-public class HistoryResource extends ApplicationResource {
-
-    private NiFiServiceFacade serviceFacade;
-
-    /**
-     * Queries the history of this Controller.
-     *
-     * @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 offset The offset into the data. This parameter is required and is
-     * used in conjunction with count.
-     * @param count The number of rows that should be returned. This parameter
-     * is required and is used in conjunction with page.
-     * @param sortColumn The column to sort on. This parameter is optional. If
-     * not specified the results will be returned with the most recent first.
-     * @param sortOrder The sort order.
-     * @param startDate The start date/time for the query. The start date/time
-     * must be formatted as 'MM/dd/yyyy HH:mm:ss'. This parameter is optional
-     * and must be specified in the timezone of the server. The server's
-     * timezone can be determined by inspecting the result of a status or
-     * history request.
-     * @param endDate The end date/time for the query. The end date/time must be
-     * formatted as 'MM/dd/yyyy HH:mm:ss'. This parameter is optional and must
-     * be specified in the timezone of the server. The server's timezone can be
-     * determined by inspecting the result of a status or history request.
-     * @param userName The user name of the user who's actions are being
-     * queried. This parameter is optional.
-     * @param sourceId The id of the source being queried (usually a processor
-     * id). This parameter is optional.
-     * @return A historyEntity.
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("") // necessary due to bug in swagger
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Gets configuration history",
-            response = HistoryEntity.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 = 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 queryHistory(
-            @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 offset into the result set.",
-                    required = true
-            )
-            @QueryParam("offset") IntegerParameter offset,
-            @ApiParam(
-                    value = "The number of actions to return.",
-                    required = true
-            )
-            @QueryParam("count") IntegerParameter count,
-            @ApiParam(
-                    value = "The field to sort on.",
-                    required = false
-            )
-            @QueryParam("sortColumn") String sortColumn,
-            @ApiParam(
-                    value = "The direction to sort.",
-                    required = false
-            )
-            @QueryParam("sortOrder") String sortOrder,
-            @ApiParam(
-                    value = "Include actions after this date.",
-                    required = false
-            )
-            @QueryParam("startDate") DateTimeParameter startDate,
-            @ApiParam(
-                    value = "Include actions before this date.",
-                    required = false
-            )
-            @QueryParam("endDate") DateTimeParameter endDate,
-            @ApiParam(
-                    value = "Include actions performed by this user.",
-                    required = false
-            )
-            @QueryParam("userName") String userName,
-            @ApiParam(
-                    value = "Include actions on this component.",
-                    required = false
-            )
-            @QueryParam("sourceId") String sourceId) {
-
-        // ensure the page is specified
-        if (offset == null) {
-            throw new IllegalArgumentException("The desired offset must be specified.");
-        } else if (offset.getInteger() < 0) {
-            throw new IllegalArgumentException("The desired offset must be an integer value greater than or equal to 0.");
-        }
-
-        // ensure the row count is specified
-        if (count == null) {
-            throw new IllegalArgumentException("The desired row count must be specified.");
-        } else if (count.getInteger() < 1) {
-            throw new IllegalArgumentException("The desired row count must be an integer value greater than 0.");
-        }
-
-        // normalize the sort order
-        if (sortOrder != null) {
-            if (!sortOrder.equalsIgnoreCase("asc") && !sortOrder.equalsIgnoreCase("desc")) {
-                throw new IllegalArgumentException("The sort order must be 'asc' or 'desc'.");
-            }
-        }
-
-        // ensure the start and end dates are specified
-        if (endDate != null && startDate != null) {
-            if (endDate.getDateTime().before(startDate.getDateTime())) {
-                throw new IllegalArgumentException("The start date/time must come before the end date/time.");
-            }
-        }
-
-        // create a history query
-        final HistoryQueryDTO query = new HistoryQueryDTO();
-        query.setSortColumn(sortColumn);
-        query.setSortOrder(sortOrder);
-        query.setOffset(offset.getInteger());
-        query.setCount(count.getInteger());
-
-        // optionally set the start date
-        if (startDate != null) {
-            query.setStartDate(startDate.getDateTime());
-        }
-
-        // optionally set the end date
-        if (endDate != null) {
-            query.setEndDate(endDate.getDateTime());
-        }
-
-        // optionally set the user id
-        if (userName != null) {
-            query.setUserName(userName);
-        }
-
-        // optionally set the processor id
-        if (sourceId != null) {
-            query.setSourceId(sourceId);
-        }
-
-        // perform the query
-        final HistoryDTO history = serviceFacade.getActions(query);
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final HistoryEntity entity = new HistoryEntity();
-        entity.setHistory(history);
-
-        // generate the response
-        return generateOkResponse(entity).build();
-    }
-
-    /**
-     * Gets the action for the corresponding id.
-     *
-     * @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 action to get.
-     * @return An actionEntity.
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @Path("{id}")
-    @ApiOperation(
-            value = "Gets an action",
-            response = ActionEntity.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 getAction(
-            @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 action id.",
-                    required = true
-            )
-            @PathParam("id") IntegerParameter id) {
-
-        // ensure the id was specified
-        if (id == null) {
-            throw new IllegalArgumentException("The action id must be specified.");
-        }
-
-        // get the specified action
-        final ActionDTO action = serviceFacade.getAction(id.getInteger());
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final ActionEntity entity = new ActionEntity();
-        entity.setAction(action);
-
-        // generate the response
-        return generateOkResponse(entity).build();
-    }
-
-    /**
-     * Deletes flow history from the specified end date.
-     *
-     * @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 endDate The end date for the purge action.
-     * @return A historyEntity
-     */
-    @DELETE
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("") // necessary due to bug in swagger
-    // TODO - @PreAuthorize("hasRole('ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Purges history",
-            response = HistoryEntity.class,
-            authorizations = {
-                @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 = 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 deleteHistory(
-            @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 = "Purge actions before this date/time.",
-                    required = true
-            )
-            @QueryParam("endDate") DateTimeParameter endDate) {
-
-        // ensure the end date is specified
-        if (endDate == null) {
-            throw new IllegalArgumentException("The end date must be specified.");
-        }
-
-        // purge the actions
-        serviceFacade.deleteActions(endDate.getDateTime());
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final HistoryEntity entity = new HistoryEntity();
-
-        // generate the response
-        return generateOkResponse(entity).build();
-    }
-
-    /**
-     * Gets the actions for 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 processorId The id of the processor.
-     * @return An processorHistoryEntity.
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("processors/{processorId}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Gets configuration history for a processor",
-            response = ComponentHistoryEntity.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 getProcessorHistory(
-            @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("processorId") final String processorId) {
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final ComponentHistoryEntity entity = new ComponentHistoryEntity();
-        entity.setComponentHistory(serviceFacade.getComponentHistory(processorId));
-
-        // generate the response
-        return generateOkResponse(entity).build();
-    }
-
-    /**
-     * Gets the actions for 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 controllerServiceId The id of the controller service.
-     * @return An componentHistoryEntity.
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("controller-services/{controllerServiceId}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Gets configuration history for a controller service",
-            response = ComponentHistoryEntity.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 getControllerServiceHistory(
-            @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 controller service id.",
-                    required = true
-            )
-            @PathParam("controllerServiceId") final String controllerServiceId) {
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final ComponentHistoryEntity entity = new ComponentHistoryEntity();
-        entity.setComponentHistory(serviceFacade.getComponentHistory(controllerServiceId));
-
-        // generate the response
-        return generateOkResponse(entity).build();
-    }
-
-    /**
-     * Gets the actions for the specified reporting task.
-     *
-     * @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 reportingTaskId The id of the reporting task.
-     * @return An componentHistoryEntity.
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("reporting-tasks/{reportingTaskId}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Gets configuration history for a reporting task",
-            response = ComponentHistoryEntity.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 getReportingTaskHistory(
-            @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 reporting task id.",
-                    required = true
-            )
-            @PathParam("reportingTaskId") final String reportingTaskId) {
-
-        // create the revision
-        final RevisionDTO revision = new RevisionDTO();
-        revision.setClientId(clientId.getClientId());
-
-        // create the response entity
-        final ComponentHistoryEntity entity = new ComponentHistoryEntity();
-        entity.setComponentHistory(serviceFacade.getComponentHistory(reportingTaskId));
-
-        // generate the response
-        return generateOkResponse(entity).build();
-    }
-
-    /* setters */
-    public void setServiceFacade(NiFiServiceFacade serviceFacade) {
-        this.serviceFacade = serviceFacade;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/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 e0b92a9..53e11ba 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
@@ -16,8 +16,22 @@
  */
 package org.apache.nifi.web.api;
 
-import java.net.URI;
-import java.util.Set;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+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.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.api.dto.PortDTO;
+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 javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
@@ -33,25 +47,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.RequestAction;
-import org.apache.nifi.authorization.resource.Authorizable;
-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.entity.PortEntity;
-import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.api.request.LongParameter;
-
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
+import java.util.Set;
 
 /**
  * RESTful endpoint for managing an Input Port.
@@ -233,23 +229,16 @@ public class InputPortResource extends ApplicationResource {
             serviceFacade,
             revision,
             lookup -> {
-                final Authorizable inputPort = lookup.getInputPort(id);
-                inputPort.authorize(authorizer, RequestAction.WRITE);
+                Authorizable authorizable = lookup.getInputPort(id);
+                authorizable.authorize(authorizer, RequestAction.WRITE);
             },
             () -> serviceFacade.verifyUpdateInputPort(requestPortDTO),
             () -> {
                 // update the input port
-                final UpdateResult<PortEntity> updateResult = serviceFacade.updateInputPort(revision, requestPortDTO);
-
-                // build the response entity
-                final PortEntity entity = updateResult.getResult();
+                final PortEntity entity = serviceFacade.updateInputPort(revision, requestPortDTO);
                 populateRemainingInputPortEntityContent(entity);
 
-                if (updateResult.isNew()) {
-                    return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
-                } else {
-                    return clusterContext(generateOkResponse(entity)).build();
-                }
+                return clusterContext(generateOkResponse(entity)).build();
             }
         );
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/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 157260f..f21882b 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
@@ -16,8 +16,22 @@
  */
 package org.apache.nifi.web.api;
 
-import java.net.URI;
-import java.util.Set;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+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.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.api.dto.LabelDTO;
+import org.apache.nifi.web.api.entity.LabelEntity;
+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;
@@ -33,25 +47,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.RequestAction;
-import org.apache.nifi.authorization.resource.Authorizable;
-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.entity.LabelEntity;
-import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.api.request.LongParameter;
-
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
+import java.util.Set;
 
 /**
  * RESTful endpoint for managing a Label.
@@ -233,21 +229,16 @@ public class LabelResource extends ApplicationResource {
             serviceFacade,
             revision,
             lookup -> {
-                final Authorizable label = lookup.getLabel(id);
-                label.authorize(authorizer, RequestAction.WRITE);
+                Authorizable authorizable  = lookup.getLabel(id);
+                authorizable.authorize(authorizer, RequestAction.WRITE);
             },
             null,
             () -> {
                 // update the label
-                final UpdateResult<LabelEntity> result = serviceFacade.updateLabel(revision, requestLabelDTO);
-                final LabelEntity entity = result.getResult();
+                final LabelEntity entity = serviceFacade.updateLabel(revision, requestLabelDTO);
                 populateRemainingLabelEntityContent(entity);
 
-                if (result.isNew()) {
-                    return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
-                } else {
-                    return clusterContext(generateOkResponse(entity)).build();
-                }
+                return clusterContext(generateOkResponse(entity)).build();
             }
         );
     }

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/NodeResource.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/NodeResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/NodeResource.java
deleted file mode 100644
index 6722e52..0000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/NodeResource.java
+++ /dev/null
@@ -1,219 +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;
-
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-
-import org.apache.nifi.web.IllegalClusterResourceRequestException;
-import org.apache.nifi.web.NiFiServiceFacade;
-import org.apache.nifi.web.api.dto.NodeDTO;
-import org.apache.nifi.web.api.entity.NodeEntity;
-
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
-
-/**
- * RESTful endpoint for managing a cluster connection.
- */
-@Api(hidden = true)
-public class NodeResource extends ApplicationResource {
-
-    private NiFiServiceFacade serviceFacade;
-
-    /**
-     * Gets the contents of the specified node in this NiFi cluster.
-     *
-     * @param id The node id.
-     * @return A nodeEntity.
-     */
-    @GET
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/{id}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_MONITOR', 'ROLE_DFM', 'ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Gets a node in the cluster",
-            response = NodeEntity.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 getNode(
-            @ApiParam(
-                    value = "The node id.",
-                    required = true
-            )
-            @PathParam("id") String id) {
-
-        if (isConnectedToCluster()) {
-            // get the specified relationship
-            final NodeDTO dto = serviceFacade.getNode(id);
-
-            // create the response entity
-            final NodeEntity entity = new NodeEntity();
-            entity.setNode(dto);
-
-            // generate the response
-            return generateOkResponse(entity).build();
-
-        }
-
-        throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
-    }
-
-    /**
-     * Updates the contents of the specified node in this NiFi cluster.
-     *
-     * @param id The id of the node
-     * @param nodeEntity A nodeEntity
-     * @return A nodeEntity
-     */
-    @PUT
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/{id}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Updates a node in the cluster",
-            response = NodeEntity.class,
-            authorizations = {
-                @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 updateNode(
-            @ApiParam(
-                    value = "The node id.",
-                    required = true
-            )
-            @PathParam("id") String id,
-            @ApiParam(
-                    value = "The node configuration. The only configuration that will be honored at this endpoint is the status or primary flag.",
-                    required = true
-            )
-            NodeEntity nodeEntity) {
-
-        if (isConnectedToCluster()) {
-            if (nodeEntity == null || nodeEntity.getNode() == null) {
-                throw new IllegalArgumentException("Node details must be specified.");
-            }
-
-            // get the request node
-            final NodeDTO requestNodeDTO = nodeEntity.getNode();
-            if (!id.equals(requestNodeDTO.getNodeId())) {
-                throw new IllegalArgumentException(String.format("The node id (%s) in the request body does "
-                        + "not equal the node id of the requested resource (%s).", requestNodeDTO.getNodeId(), id));
-            }
-
-            // update the node
-            final NodeDTO node = serviceFacade.updateNode(requestNodeDTO);
-
-            // create the response entity
-            NodeEntity entity = new NodeEntity();
-            entity.setNode(node);
-
-            // generate the response
-            return generateOkResponse(entity).build();
-        }
-
-        throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
-    }
-
-    /**
-     * Removes the specified from this NiFi cluster.
-     *
-     * @param id The id of the node
-     * @return A nodeEntity
-     */
-    @DELETE
-    @Consumes(MediaType.WILDCARD)
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/{id}")
-    // TODO - @PreAuthorize("hasAnyRole('ROLE_ADMIN')")
-    @ApiOperation(
-            value = "Removes a node from the cluster",
-            response = NodeEntity.class,
-            authorizations = {
-                @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 deleteNode(
-            @ApiParam(
-                    value = "The node id.",
-                    required = true
-            )
-            @PathParam("id") String id) {
-
-        if (isConnectedToCluster()) {
-            serviceFacade.deleteNode(id);
-
-            // create the response entity
-            final NodeEntity entity = new NodeEntity();
-
-            // generate the response
-            return generateOkResponse(entity).build();
-        }
-
-        throw new IllegalClusterResourceRequestException("Only a cluster manager can process the request.");
-
-    }
-
-    // setters
-    public void setServiceFacade(NiFiServiceFacade serviceFacade) {
-        this.serviceFacade = serviceFacade;
-    }
-}

http://git-wip-us.apache.org/repos/asf/nifi/blob/f0811ca4/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 13dc8c3..bfaed4b 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
@@ -16,8 +16,22 @@
  */
 package org.apache.nifi.web.api;
 
-import java.net.URI;
-import java.util.Set;
+import com.wordnik.swagger.annotations.Api;
+import com.wordnik.swagger.annotations.ApiOperation;
+import com.wordnik.swagger.annotations.ApiParam;
+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.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.Revision;
+import org.apache.nifi.web.api.dto.PortDTO;
+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 javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
@@ -33,25 +47,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.authorization.Authorizer;
-import org.apache.nifi.authorization.RequestAction;
-import org.apache.nifi.authorization.resource.Authorizable;
-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.entity.PortEntity;
-import org.apache.nifi.web.api.request.ClientIdParameter;
-import org.apache.nifi.web.api.request.LongParameter;
-
-import com.wordnik.swagger.annotations.Api;
-import com.wordnik.swagger.annotations.ApiOperation;
-import com.wordnik.swagger.annotations.ApiParam;
-import com.wordnik.swagger.annotations.ApiResponse;
-import com.wordnik.swagger.annotations.ApiResponses;
-import com.wordnik.swagger.annotations.Authorization;
+import java.util.Set;
 
 /**
  * RESTful endpoint for managing an Output Port.
@@ -233,23 +229,16 @@ public class OutputPortResource extends ApplicationResource {
             serviceFacade,
             revision,
             lookup -> {
-                final Authorizable outputPort = lookup.getOutputPort(id);
-                outputPort.authorize(authorizer, RequestAction.WRITE);
+                Authorizable authorizable = lookup.getOutputPort(id);
+                authorizable.authorize(authorizer, RequestAction.WRITE);
             },
             () -> serviceFacade.verifyUpdateOutputPort(requestPortDTO),
             () -> {
                 // update the output port
-                final UpdateResult<PortEntity> updateResult = serviceFacade.updateOutputPort(revision, requestPortDTO);
-
-                // get the results
-                final PortEntity entity = updateResult.getResult();
+                final PortEntity entity = serviceFacade.updateOutputPort(revision, requestPortDTO);
                 populateRemainingOutputPortEntityContent(entity);
 
-                if (updateResult.isNew()) {
-                    return clusterContext(generateCreatedResponse(URI.create(entity.getComponent().getUri()), entity)).build();
-                } else {
-                    return clusterContext(generateOkResponse(entity)).build();
-                }
+                return clusterContext(generateOkResponse(entity)).build();
             }
         );
     }