You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ma...@apache.org on 2015/04/10 15:43:46 UTC
[11/62] [abbrv] incubator-nifi git commit: Squashed commit of the
following:
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.java
new file mode 100644
index 0000000..14217c5
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardControllerServiceDAO.java
@@ -0,0 +1,320 @@
+/*
+ * 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.dao.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.nifi.controller.ScheduledState;
+import org.apache.nifi.controller.exception.ControllerServiceInstantiationException;
+
+import org.apache.nifi.controller.exception.ValidationException;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceProvider;
+import org.apache.nifi.controller.service.ControllerServiceReference;
+import org.apache.nifi.controller.service.ControllerServiceState;
+import org.apache.nifi.web.NiFiCoreException;
+import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+import org.apache.nifi.web.dao.ControllerServiceDAO;
+
+public class StandardControllerServiceDAO extends ComponentDAO implements ControllerServiceDAO {
+
+ private ControllerServiceProvider serviceProvider;
+
+ /**
+ * Locates the specified controller service.
+ *
+ * @param controllerServiceId
+ * @return
+ */
+ private ControllerServiceNode locateControllerService(final String controllerServiceId) {
+ // get the controller service
+ final ControllerServiceNode controllerService = serviceProvider.getControllerServiceNode(controllerServiceId);
+
+ // ensure the controller service exists
+ if (controllerService == null) {
+ throw new ResourceNotFoundException(String.format("Unable to locate controller service with id '%s'.", controllerServiceId));
+ }
+
+ return controllerService;
+ }
+
+ /**
+ * Creates a controller service.
+ *
+ * @param controllerServiceDTO The controller service DTO
+ * @return The controller service
+ */
+ @Override
+ public ControllerServiceNode createControllerService(final ControllerServiceDTO controllerServiceDTO) {
+ // ensure the type is specified
+ if (controllerServiceDTO.getType() == null) {
+ throw new IllegalArgumentException("The controller service type must be specified.");
+ }
+
+ try {
+ // create the controller service
+ final ControllerServiceNode controllerService = serviceProvider.createControllerService(controllerServiceDTO.getType(), controllerServiceDTO.getId(), true);
+
+ // ensure we can perform the update
+ verifyUpdate(controllerService, controllerServiceDTO);
+
+ // perform the update
+ configureControllerService(controllerService, controllerServiceDTO);
+
+ return controllerService;
+ } catch (final ControllerServiceInstantiationException csie) {
+ throw new NiFiCoreException(csie.getMessage(), csie);
+ }
+ }
+
+ /**
+ * Gets the specified controller service.
+ *
+ * @param controllerServiceId The controller service id
+ * @return The controller service
+ */
+ @Override
+ public ControllerServiceNode getControllerService(final String controllerServiceId) {
+ return locateControllerService(controllerServiceId);
+ }
+
+ /**
+ * Determines if the specified controller service exists.
+ *
+ * @param controllerServiceId
+ * @return
+ */
+ @Override
+ public boolean hasControllerService(final String controllerServiceId) {
+ return serviceProvider.getControllerServiceNode(controllerServiceId) != null;
+ }
+
+ /**
+ * Gets all of the controller services.
+ *
+ * @return The controller services
+ */
+ @Override
+ public Set<ControllerServiceNode> getControllerServices() {
+ return serviceProvider.getAllControllerServices();
+ }
+
+ /**
+ * Updates the specified controller service.
+ *
+ * @param controllerServiceDTO The controller service DTO
+ * @return The controller service
+ */
+ @Override
+ public ControllerServiceNode updateControllerService(final ControllerServiceDTO controllerServiceDTO) {
+ // get the controller service
+ final ControllerServiceNode controllerService = locateControllerService(controllerServiceDTO.getId());
+
+ // ensure we can perform the update
+ verifyUpdate(controllerService, controllerServiceDTO);
+
+ // perform the update
+ configureControllerService(controllerService, controllerServiceDTO);
+
+ // enable or disable as appropriate
+ if (isNotNull(controllerServiceDTO.getState())) {
+ final ControllerServiceState purposedControllerServiceState = ControllerServiceState.valueOf(controllerServiceDTO.getState());
+
+ // only attempt an action if it is changing
+ if (!purposedControllerServiceState.equals(controllerService.getState())) {
+ if (ControllerServiceState.ENABLED.equals(purposedControllerServiceState)) {
+ serviceProvider.enableControllerService(controllerService);
+ } else if (ControllerServiceState.DISABLED.equals(purposedControllerServiceState)) {
+ serviceProvider.disableControllerService(controllerService);
+ }
+ }
+ }
+
+ return controllerService;
+ }
+
+ @Override
+ public ControllerServiceReference updateControllerServiceReferencingComponents(final String controllerServiceId, final ScheduledState scheduledState, final ControllerServiceState controllerServiceState) {
+ // get the controller service
+ final ControllerServiceNode controllerService = locateControllerService(controllerServiceId);
+
+ // this request is either acting upon referncing services or schedulable components
+ if (controllerServiceState != null) {
+ if (ControllerServiceState.ENABLED.equals(controllerServiceState)) {
+ serviceProvider.enableReferencingServices(controllerService);
+ } else {
+ serviceProvider.disableReferencingServices(controllerService);
+ }
+ } else if (scheduledState != null) {
+ if (ScheduledState.RUNNING.equals(scheduledState)) {
+ serviceProvider.scheduleReferencingComponents(controllerService);
+ } else {
+ serviceProvider.unscheduleReferencingComponents(controllerService);
+ }
+ }
+
+ return controllerService.getReferences();
+ }
+
+ /**
+ * Validates the specified configuration for the specified controller service.
+ *
+ * @param controllerService
+ * @param controllerServiceDTO
+ * @return
+ */
+ private List<String> validateProposedConfiguration(final ControllerServiceNode controllerService, final ControllerServiceDTO controllerServiceDTO) {
+ final List<String> validationErrors = new ArrayList<>();
+ return validationErrors;
+ }
+
+ @Override
+ public void verifyDelete(final String controllerServiceId) {
+ final ControllerServiceNode controllerService = locateControllerService(controllerServiceId);
+ controllerService.verifyCanDelete();
+ }
+
+ @Override
+ public void verifyUpdate(final ControllerServiceDTO controllerServiceDTO) {
+ final ControllerServiceNode controllerService = locateControllerService(controllerServiceDTO.getId());
+ verifyUpdate(controllerService, controllerServiceDTO);
+ }
+
+ @Override
+ public void verifyUpdateReferencingComponents(String controllerServiceId, ScheduledState scheduledState, ControllerServiceState controllerServiceState) {
+ final ControllerServiceNode controllerService = locateControllerService(controllerServiceId);
+
+ if (controllerServiceState != null) {
+ if (ControllerServiceState.ENABLED.equals(controllerServiceState)) {
+ serviceProvider.verifyCanEnableReferencingServices(controllerService);
+ } else {
+ serviceProvider.verifyCanDisableReferencingServices(controllerService);
+ }
+ } else if (scheduledState != null) {
+ if (ScheduledState.RUNNING.equals(scheduledState)) {
+ serviceProvider.verifyCanScheduleReferencingComponents(controllerService);
+ } else {
+ serviceProvider.verifyCanStopReferencingComponents(controllerService);
+ }
+ }
+ }
+
+ /**
+ * Verifies the controller service can be updated.
+ *
+ * @param controllerService
+ * @param controllerServiceDTO
+ */
+ private void verifyUpdate(final ControllerServiceNode controllerService, final ControllerServiceDTO controllerServiceDTO) {
+ // validate the new controller service state if appropriate
+ if (isNotNull(controllerServiceDTO.getState())) {
+ try {
+ // attempt to parse the service state
+ final ControllerServiceState purposedControllerServiceState = ControllerServiceState.valueOf(controllerServiceDTO.getState());
+
+ // ensure the state is valid
+ if (ControllerServiceState.ENABLING.equals(purposedControllerServiceState) || ControllerServiceState.DISABLING.equals(purposedControllerServiceState)) {
+ throw new IllegalArgumentException();
+ }
+
+ // only attempt an action if it is changing
+ if (!purposedControllerServiceState.equals(controllerService.getState())) {
+ if (ControllerServiceState.ENABLED.equals(purposedControllerServiceState)) {
+ controllerService.verifyCanEnable();
+ } else if (ControllerServiceState.DISABLED.equals(purposedControllerServiceState)) {
+ controllerService.verifyCanDisable();
+ }
+ }
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException("Controller Service state: Value must be one of [ENABLED, DISABLED]");
+ }
+ }
+
+ boolean modificationRequest = false;
+ if (isAnyNotNull(controllerServiceDTO.getName(),
+ controllerServiceDTO.getAnnotationData(),
+ controllerServiceDTO.getComments(),
+ controllerServiceDTO.getProperties())) {
+ modificationRequest = true;
+
+ // validate the request
+ final List<String> requestValidation = validateProposedConfiguration(controllerService, controllerServiceDTO);
+
+ // ensure there was no validation errors
+ if (!requestValidation.isEmpty()) {
+ throw new ValidationException(requestValidation);
+ }
+ }
+
+ if (modificationRequest) {
+ controllerService.verifyCanUpdate();
+ }
+ }
+
+ /**
+ * Configures the specified controller service.
+ *
+ * @param controllerService
+ * @param controllerServiceDTO
+ */
+ private void configureControllerService(final ControllerServiceNode controllerService, final ControllerServiceDTO controllerServiceDTO) {
+ final String name = controllerServiceDTO.getName();
+ final String annotationData = controllerServiceDTO.getAnnotationData();
+ final String comments = controllerServiceDTO.getComments();
+ final Map<String, String> properties = controllerServiceDTO.getProperties();
+
+ if (isNotNull(name)) {
+ controllerService.setName(name);
+ }
+ if (isNotNull(annotationData)) {
+ controllerService.setAnnotationData(annotationData);
+ }
+ if (isNotNull(comments)) {
+ controllerService.setComments(comments);
+ }
+ if (isNotNull(properties)) {
+ for (final Map.Entry<String, String> entry : properties.entrySet()) {
+ final String propName = entry.getKey();
+ final String propVal = entry.getValue();
+ if (isNotNull(propName) && propVal == null) {
+ controllerService.removeProperty(propName);
+ } else if (isNotNull(propName)) {
+ controllerService.setProperty(propName, propVal);
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes the specified controller service.
+ *
+ * @param controllerServiceId The controller service id
+ */
+ @Override
+ public void deleteControllerService(String controllerServiceId) {
+ final ControllerServiceNode controllerService = locateControllerService(controllerServiceId);
+ serviceProvider.removeControllerService(controllerService);
+ }
+
+ /* setters */
+ public void setServiceProvider(ControllerServiceProvider serviceProvider) {
+ this.serviceProvider = serviceProvider;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
index 633f8e2..0c587fe 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardProcessorDAO.java
@@ -99,6 +99,11 @@ public class StandardProcessorDAO extends ComponentDAO implements ProcessorDAO {
if (processorDTO.getParentGroupId() != null && !flowController.areGroupsSame(groupId, processorDTO.getParentGroupId())) {
throw new IllegalArgumentException("Cannot specify a different Parent Group ID than the Group to which the Processor is being added.");
}
+
+ // ensure the type is specified
+ if (processorDTO.getType() == null) {
+ throw new IllegalArgumentException("The processor type must be specified.");
+ }
// get the group to add the processor to
ProcessGroup group = locateProcessGroup(flowController, groupId);
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardReportingTaskDAO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardReportingTaskDAO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardReportingTaskDAO.java
new file mode 100644
index 0000000..d9fd74c
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardReportingTaskDAO.java
@@ -0,0 +1,365 @@
+/*
+ * 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.dao.impl;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.regex.Matcher;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.controller.ReportingTaskNode;
+import org.apache.nifi.controller.ScheduledState;
+import org.apache.nifi.controller.exception.ProcessorLifeCycleException;
+
+import org.apache.nifi.controller.exception.ValidationException;
+import org.apache.nifi.controller.reporting.ReportingTaskInstantiationException;
+import org.apache.nifi.controller.reporting.ReportingTaskProvider;
+import org.apache.nifi.scheduling.SchedulingStrategy;
+import org.apache.nifi.util.FormatUtils;
+import org.apache.nifi.web.NiFiCoreException;
+import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.api.dto.ReportingTaskDTO;
+import org.apache.nifi.web.dao.ReportingTaskDAO;
+import org.quartz.CronExpression;
+
+public class StandardReportingTaskDAO extends ComponentDAO implements ReportingTaskDAO {
+
+ private ReportingTaskProvider reportingTaskProvider;
+
+ /**
+ * Locates the specified reporting task.
+ *
+ * @param reportingTaskId
+ * @return
+ */
+ private ReportingTaskNode locateReportingTask(final String reportingTaskId) {
+ // get the reporting task
+ final ReportingTaskNode reportingTask = reportingTaskProvider.getReportingTaskNode(reportingTaskId);
+
+ // ensure the reporting task exists
+ if (reportingTask == null) {
+ throw new ResourceNotFoundException(String.format("Unable to locate reporting task with id '%s'.", reportingTaskId));
+ }
+
+ return reportingTask;
+ }
+
+ /**
+ * Creates a reporting task.
+ *
+ * @param reportingTaskDTO The reporting task DTO
+ * @return The reporting task
+ */
+ @Override
+ public ReportingTaskNode createReportingTask(final ReportingTaskDTO reportingTaskDTO) {
+ // ensure the type is specified
+ if (reportingTaskDTO.getType() == null) {
+ throw new IllegalArgumentException("The reporting task type must be specified.");
+ }
+
+ try {
+ // create the reporting task
+ final ReportingTaskNode reportingTask = reportingTaskProvider.createReportingTask(reportingTaskDTO.getType(), reportingTaskDTO.getId(), true);
+
+ // ensure we can perform the update
+ verifyUpdate(reportingTask, reportingTaskDTO);
+
+ // perform the update
+ configureReportingTask(reportingTask, reportingTaskDTO);
+
+ return reportingTask;
+ } catch (ReportingTaskInstantiationException rtie) {
+ throw new NiFiCoreException(rtie.getMessage(), rtie);
+ }
+ }
+
+ /**
+ * Gets the specified reporting task.
+ *
+ * @param reportingTaskId The reporting task id
+ * @return The reporting task
+ */
+ @Override
+ public ReportingTaskNode getReportingTask(final String reportingTaskId) {
+ return locateReportingTask(reportingTaskId);
+ }
+
+ /**
+ * Determines if the specified reporting task exists.
+ *
+ * @param reportingTaskId
+ * @return
+ */
+ @Override
+ public boolean hasReportingTask(final String reportingTaskId) {
+ return reportingTaskProvider.getReportingTaskNode(reportingTaskId) != null;
+ }
+
+ /**
+ * Gets all of the reporting tasks.
+ *
+ * @return The reporting tasks
+ */
+ @Override
+ public Set<ReportingTaskNode> getReportingTasks() {
+ return reportingTaskProvider.getAllReportingTasks();
+ }
+
+ /**
+ * Updates the specified reporting task.
+ *
+ * @param reportingTaskDTO The reporting task DTO
+ * @return The reporting task
+ */
+ @Override
+ public ReportingTaskNode updateReportingTask(final ReportingTaskDTO reportingTaskDTO) {
+ // get the reporting task
+ final ReportingTaskNode reportingTask = locateReportingTask(reportingTaskDTO.getId());
+
+ // ensure we can perform the update
+ verifyUpdate(reportingTask, reportingTaskDTO);
+
+ // perform the update
+ configureReportingTask(reportingTask, reportingTaskDTO);
+
+ // configure scheduled state
+ // see if an update is necessary
+ if (isNotNull(reportingTaskDTO.getState())) {
+ final ScheduledState purposedScheduledState = ScheduledState.valueOf(reportingTaskDTO.getState());
+
+ // only attempt an action if it is changing
+ if (!purposedScheduledState.equals(reportingTask.getScheduledState())) {
+ try {
+ // perform the appropriate action
+ switch (purposedScheduledState) {
+ case RUNNING:
+ reportingTaskProvider.startReportingTask(reportingTask);
+ break;
+ case STOPPED:
+ switch (reportingTask.getScheduledState()) {
+ case RUNNING:
+ reportingTaskProvider.stopReportingTask(reportingTask);
+ break;
+ case DISABLED:
+ reportingTaskProvider.enableReportingTask(reportingTask);
+ break;
+ }
+ break;
+ case DISABLED:
+ reportingTaskProvider.disableReportingTask(reportingTask);
+ break;
+ }
+ } catch (IllegalStateException | ProcessorLifeCycleException ise) {
+ throw new NiFiCoreException(ise.getMessage(), ise);
+ } catch (RejectedExecutionException ree) {
+ throw new NiFiCoreException("Unable to schedule all tasks for the specified reporting task.", ree);
+ } catch (NullPointerException npe) {
+ throw new NiFiCoreException("Unable to update reporting task run state.", npe);
+ } catch (Exception e) {
+ throw new NiFiCoreException("Unable to update reporting task run state: " + e, e);
+ }
+ }
+ }
+
+ return reportingTask;
+ }
+
+ /**
+ * Validates the specified configuration for the specified reporting task.
+ *
+ * @param reportingTask
+ * @param reportingTaskDTO
+ * @return
+ */
+ private List<String> validateProposedConfiguration(final ReportingTaskNode reportingTask, final ReportingTaskDTO reportingTaskDTO) {
+ final List<String> validationErrors = new ArrayList<>();
+
+ // get the current scheduling strategy
+ SchedulingStrategy schedulingStrategy = reportingTask.getSchedulingStrategy();
+
+ // validate the new scheduling strategy if appropriate
+ if (isNotNull(reportingTaskDTO.getSchedulingStrategy())) {
+ try {
+ // this will be the new scheduling strategy so use it
+ schedulingStrategy = SchedulingStrategy.valueOf(reportingTaskDTO.getSchedulingStrategy());
+ } catch (IllegalArgumentException iae) {
+ validationErrors.add(String.format("Scheduling strategy: Value must be one of [%s]", StringUtils.join(SchedulingStrategy.values(), ", ")));
+ }
+ }
+
+ // validate the scheduling period based on the scheduling strategy
+ if (isNotNull(reportingTaskDTO.getSchedulingPeriod())) {
+ switch (schedulingStrategy) {
+ case TIMER_DRIVEN:
+ final Matcher schedulingMatcher = FormatUtils.TIME_DURATION_PATTERN.matcher(reportingTaskDTO.getSchedulingPeriod());
+ if (!schedulingMatcher.matches()) {
+ validationErrors.add("Scheduling period is not a valid time duration (ie 30 sec, 5 min)");
+ }
+ break;
+ case CRON_DRIVEN:
+ try {
+ new CronExpression(reportingTaskDTO.getSchedulingPeriod());
+ } catch (final ParseException pe) {
+ throw new IllegalArgumentException(String.format("Scheduling Period '%s' is not a valid cron expression: %s", reportingTaskDTO.getSchedulingPeriod(), pe.getMessage()));
+ } catch (final Exception e) {
+ throw new IllegalArgumentException("Scheduling Period is not a valid cron expression: " + reportingTaskDTO.getSchedulingPeriod());
+ }
+ break;
+ }
+ }
+
+ return validationErrors;
+ }
+
+ @Override
+ public void verifyDelete(final String reportingTaskId) {
+ final ReportingTaskNode reportingTask = locateReportingTask(reportingTaskId);
+ reportingTask.verifyCanDelete();
+ }
+
+ @Override
+ public void verifyUpdate(final ReportingTaskDTO reportingTaskDTO) {
+ final ReportingTaskNode reportingTask = locateReportingTask(reportingTaskDTO.getId());
+ verifyUpdate(reportingTask, reportingTaskDTO);
+ }
+
+ /**
+ * Verifies the reporting task can be updated.
+ *
+ * @param reportingTask
+ * @param reportingTaskDTO
+ */
+ private void verifyUpdate(final ReportingTaskNode reportingTask, final ReportingTaskDTO reportingTaskDTO) {
+ // ensure the state, if specified, is valid
+ if (isNotNull(reportingTaskDTO.getState())) {
+ try {
+ final ScheduledState purposedScheduledState = ScheduledState.valueOf(reportingTaskDTO.getState());
+
+ // only attempt an action if it is changing
+ if (!purposedScheduledState.equals(reportingTask.getScheduledState())) {
+ // perform the appropriate action
+ switch (purposedScheduledState) {
+ case RUNNING:
+ reportingTask.verifyCanStart();
+ break;
+ case STOPPED:
+ switch (reportingTask.getScheduledState()) {
+ case RUNNING:
+ reportingTask.verifyCanStop();
+ break;
+ case DISABLED:
+ reportingTask.verifyCanEnable();
+ break;
+ }
+ break;
+ case DISABLED:
+ reportingTask.verifyCanDisable();
+ break;
+ }
+ }
+ } catch (IllegalArgumentException iae) {
+ throw new IllegalArgumentException(String.format(
+ "The specified reporting task state (%s) is not valid. Valid options are 'RUNNING', 'STOPPED', and 'DISABLED'.",
+ reportingTaskDTO.getState()));
+ }
+ }
+
+ boolean modificationRequest = false;
+ if (isAnyNotNull(reportingTaskDTO.getName(),
+ reportingTaskDTO.getSchedulingStrategy(),
+ reportingTaskDTO.getSchedulingPeriod(),
+ reportingTaskDTO.getAnnotationData(),
+ reportingTaskDTO.getProperties())) {
+ modificationRequest = true;
+
+ // validate the request
+ final List<String> requestValidation = validateProposedConfiguration(reportingTask, reportingTaskDTO);
+
+ // ensure there was no validation errors
+ if (!requestValidation.isEmpty()) {
+ throw new ValidationException(requestValidation);
+ }
+ }
+
+ if (modificationRequest) {
+ reportingTask.verifyCanUpdate();
+ }
+ }
+
+ /**
+ * Configures the specified reporting task.
+ *
+ * @param reportingTask
+ * @param reportingTaskDTO
+ */
+ private void configureReportingTask(final ReportingTaskNode reportingTask, final ReportingTaskDTO reportingTaskDTO) {
+ final String name = reportingTaskDTO.getName();
+ final String schedulingStrategy = reportingTaskDTO.getSchedulingStrategy();
+ final String schedulingPeriod = reportingTaskDTO.getSchedulingPeriod();
+ final String annotationData = reportingTaskDTO.getAnnotationData();
+ final String comments = reportingTaskDTO.getComments();
+ final Map<String, String> properties = reportingTaskDTO.getProperties();
+
+ // ensure scheduling strategy is set first
+ if (isNotNull(schedulingStrategy)) {
+ reportingTask.setSchedulingStrategy(SchedulingStrategy.valueOf(schedulingStrategy));
+ }
+
+ if (isNotNull(name)) {
+ reportingTask.setName(name);
+ }
+ if (isNotNull(schedulingPeriod)) {
+ reportingTask.setScheduldingPeriod(schedulingPeriod);
+ }
+ if (isNotNull(annotationData)) {
+ reportingTask.setAnnotationData(annotationData);
+ }
+ if (isNotNull(comments)) {
+ reportingTask.setComments(comments);
+ }
+ if (isNotNull(properties)) {
+ for (final Map.Entry<String, String> entry : properties.entrySet()) {
+ final String propName = entry.getKey();
+ final String propVal = entry.getValue();
+ if (isNotNull(propName) && propVal == null) {
+ reportingTask.removeProperty(propName);
+ } else if (isNotNull(propName)) {
+ reportingTask.setProperty(propName, propVal);
+ }
+ }
+ }
+ }
+
+ /**
+ * Deletes the specified reporting task.
+ *
+ * @param reportingTaskId The reporting task id
+ */
+ @Override
+ public void deleteReportingTask(String reportingTaskId) {
+ final ReportingTaskNode reportingTask = locateReportingTask(reportingTaskId);
+ reportingTaskProvider.removeReportingTask(reportingTask);
+ }
+
+ /* setters */
+ public void setReportingTaskProvider(ReportingTaskProvider reportingTaskProvider) {
+ this.reportingTaskProvider = reportingTaskProvider;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardSnippetDAO.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardSnippetDAO.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardSnippetDAO.java
index 92e3a8d..6447464 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardSnippetDAO.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/impl/StandardSnippetDAO.java
@@ -26,9 +26,11 @@ import org.apache.nifi.controller.ProcessorNode;
import org.apache.nifi.controller.Snippet;
import org.apache.nifi.controller.StandardSnippet;
import org.apache.nifi.controller.exception.ProcessorInstantiationException;
+import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.web.NiFiCoreException;
import org.apache.nifi.web.ResourceNotFoundException;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
import org.apache.nifi.web.api.dto.ProcessGroupDTO;
import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
@@ -36,7 +38,6 @@ import org.apache.nifi.web.api.dto.ProcessorDTO;
import org.apache.nifi.web.api.dto.SnippetDTO;
import org.apache.nifi.web.dao.SnippetDAO;
import org.apache.nifi.web.util.SnippetUtils;
-
import org.apache.commons.lang3.StringUtils;
/**
@@ -285,9 +286,13 @@ public class StandardSnippetDAO implements SnippetDAO {
if (snippet != null) {
// go through each processor if specified
if (snippet.getProcessors() != null) {
- lookupSensitiveProperties(snippet.getProcessors());
+ lookupSensitiveProcessorProperties(snippet.getProcessors());
}
+ if ( snippet.getControllerServices() != null ) {
+ lookupSensitiveControllerServiceProperties(snippet.getControllerServices());
+ }
+
// go through each process group if specified
if (snippet.getProcessGroups() != null) {
for (final ProcessGroupDTO group : snippet.getProcessGroups()) {
@@ -303,7 +308,7 @@ public class StandardSnippetDAO implements SnippetDAO {
*
* @param snippet
*/
- private void lookupSensitiveProperties(final Set<ProcessorDTO> processors) {
+ private void lookupSensitiveProcessorProperties(final Set<ProcessorDTO> processors) {
final ProcessGroup rootGroup = flowController.getGroup(flowController.getRootGroupId());
// go through each processor
@@ -331,6 +336,31 @@ public class StandardSnippetDAO implements SnippetDAO {
}
}
}
+
+ private void lookupSensitiveControllerServiceProperties(final Set<ControllerServiceDTO> controllerServices) {
+ // go through each service
+ for (final ControllerServiceDTO serviceDTO : controllerServices) {
+
+ // ensure that some property configuration have been specified
+ final Map<String, String> serviceProperties = serviceDTO.getProperties();
+ if (serviceProperties != null) {
+ // find the corresponding controller service
+ final ControllerServiceNode serviceNode = flowController.getControllerServiceNode(serviceDTO.getId());
+ if (serviceNode == null) {
+ throw new IllegalArgumentException(String.format("Unable to create snippet because Controller Service '%s' could not be found", serviceDTO.getId()));
+ }
+
+ // look for sensitive properties get the actual value
+ for (Entry<PropertyDescriptor, String> entry : serviceNode.getProperties().entrySet()) {
+ final PropertyDescriptor descriptor = entry.getKey();
+
+ if (descriptor.isSensitive()) {
+ serviceProperties.put(descriptor.getName(), entry.getValue());
+ }
+ }
+ }
+ }
+ }
/* setters */
public void setFlowController(FlowController flowController) {
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ControllerServiceProviderFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ControllerServiceProviderFactoryBean.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ControllerServiceProviderFactoryBean.java
new file mode 100644
index 0000000..5c10de6
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ControllerServiceProviderFactoryBean.java
@@ -0,0 +1,68 @@
+/*
+ * 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.spring;
+
+import org.apache.nifi.cluster.manager.impl.WebClusterManager;
+import org.apache.nifi.controller.FlowController;
+import org.apache.nifi.controller.service.ControllerServiceProvider;
+import org.apache.nifi.util.NiFiProperties;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ *
+ */
+public class ControllerServiceProviderFactoryBean implements FactoryBean, ApplicationContextAware {
+
+ private ApplicationContext context;
+ private ControllerServiceProvider controllerServiceProvider;
+ private NiFiProperties properties;
+
+ @Override
+ public Object getObject() throws Exception {
+ if (controllerServiceProvider == null) {
+ if (properties.isClusterManager()) {
+ controllerServiceProvider = context.getBean("clusterManager", WebClusterManager.class);
+ } else {
+ controllerServiceProvider = context.getBean("flowController", FlowController.class);
+ }
+ }
+
+ return controllerServiceProvider;
+ }
+
+ @Override
+ public Class getObjectType() {
+ return ControllerServiceProvider.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void setProperties(NiFiProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext context) throws BeansException {
+ this.context = context;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/OptimisticLockingManagerFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/OptimisticLockingManagerFactoryBean.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/OptimisticLockingManagerFactoryBean.java
new file mode 100644
index 0000000..8436793
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/OptimisticLockingManagerFactoryBean.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.spring;
+
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.OptimisticLockingManager;
+import org.apache.nifi.web.StandardOptimisticLockingManager;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ *
+ */
+public class OptimisticLockingManagerFactoryBean implements FactoryBean, ApplicationContextAware {
+
+ private ApplicationContext context;
+ private OptimisticLockingManager optimisticLockingManager;
+ private NiFiProperties properties;
+
+ @Override
+ public Object getObject() throws Exception {
+ if (optimisticLockingManager == null) {
+ if (properties.isClusterManager()) {
+ optimisticLockingManager = context.getBean("clusterManagerOptimisticLockingManager", OptimisticLockingManager.class);
+ } else {
+ optimisticLockingManager = new StandardOptimisticLockingManager();
+ }
+ }
+
+ return optimisticLockingManager;
+ }
+
+ @Override
+ public Class getObjectType() {
+ return OptimisticLockingManager.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void setProperties(NiFiProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext context) throws BeansException {
+ this.context = context;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ReportingTaskProviderFactoryBean.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ReportingTaskProviderFactoryBean.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ReportingTaskProviderFactoryBean.java
new file mode 100644
index 0000000..d344fa6
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/spring/ReportingTaskProviderFactoryBean.java
@@ -0,0 +1,69 @@
+/*
+ * 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.spring;
+
+import org.apache.nifi.cluster.manager.impl.WebClusterManager;
+import org.apache.nifi.controller.FlowController;
+import org.apache.nifi.controller.reporting.ReportingTaskProvider;
+import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.dao.ControllerServiceDAO;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+/**
+ *
+ */
+public class ReportingTaskProviderFactoryBean implements FactoryBean, ApplicationContextAware {
+
+ private ApplicationContext context;
+ private ReportingTaskProvider reportingTaskProvider;
+ private NiFiProperties properties;
+
+ @Override
+ public Object getObject() throws Exception {
+ if (reportingTaskProvider == null) {
+ if (properties.isClusterManager()) {
+ reportingTaskProvider = context.getBean("clusterManager", WebClusterManager.class);
+ } else {
+ reportingTaskProvider = context.getBean("flowController", FlowController.class);
+ }
+ }
+
+ return reportingTaskProvider;
+ }
+
+ @Override
+ public Class getObjectType() {
+ return ReportingTaskProvider.class;
+ }
+
+ @Override
+ public boolean isSingleton() {
+ return true;
+ }
+
+ public void setProperties(NiFiProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext context) throws BeansException {
+ this.context = context;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/Availability.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/Availability.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/Availability.java
new file mode 100644
index 0000000..29ba4f8
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/Availability.java
@@ -0,0 +1,34 @@
+/*
+ * 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.util;
+
+/**
+ * Where a given controller service or reporting task should run.
+ */
+public enum Availability {
+
+ /**
+ * Service or reporting task will run only on the NiFi Cluster Manager (NCM)
+ */
+ NCM,
+
+ /**
+ * Service or reporting task will run only on NiFi Nodes (or standalone
+ * instance, if not clustered)
+ */
+ NODE;
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/SnippetUtils.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/SnippetUtils.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/SnippetUtils.java
index 8653094..fa9bc41 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/SnippetUtils.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/util/SnippetUtils.java
@@ -18,6 +18,7 @@ package org.apache.nifi.web.util;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -28,6 +29,7 @@ import java.util.UUID;
import org.apache.nifi.cluster.context.ClusterContext;
import org.apache.nifi.cluster.context.ClusterContextThreadLocal;
+import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.connectable.ConnectableType;
import org.apache.nifi.connectable.Connection;
import org.apache.nifi.connectable.Funnel;
@@ -37,17 +39,22 @@ import org.apache.nifi.controller.ProcessorNode;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.Snippet;
import org.apache.nifi.controller.label.Label;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.groups.RemoteProcessGroup;
import org.apache.nifi.web.api.dto.ConnectableDTO;
import org.apache.nifi.web.api.dto.ConnectionDTO;
+import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.DtoFactory;
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.ProcessorConfigDTO;
import org.apache.nifi.web.api.dto.ProcessorDTO;
+import org.apache.nifi.web.api.dto.PropertyDescriptorDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupContentsDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
@@ -181,11 +188,100 @@ public final class SnippetUtils {
snippetDto.setRemoteProcessGroups(remoteProcessGroups);
}
+ addControllerServicesToSnippet(snippetDto);
+
return snippetDto;
}
+
+ private void addControllerServicesToSnippet(final FlowSnippetDTO snippetDto) {
+ for ( final ProcessorDTO processorDto : snippetDto.getProcessors() ) {
+ addControllerServicesToSnippet(snippetDto, processorDto);
+ }
+
+ for ( final ProcessGroupDTO processGroupDto : snippetDto.getProcessGroups() ) {
+ final FlowSnippetDTO childGroupDto = processGroupDto.getContents();
+ addControllerServicesToSnippet(childGroupDto);
+ }
+ }
+
+ private void addControllerServicesToSnippet(final FlowSnippetDTO snippet, final ProcessorDTO processorDto) {
+ final ProcessorConfigDTO configDto = processorDto.getConfig();
+ if ( configDto == null ) {
+ return;
+ }
+
+ final Map<String, PropertyDescriptorDTO> descriptors = configDto.getDescriptors();
+ final Map<String, String> properties = configDto.getProperties();
+
+ if ( properties != null && descriptors != null ) {
+ for ( final Map.Entry<String, String> entry : properties.entrySet() ) {
+ final String propName = entry.getKey();
+ final String propValue = entry.getValue();
+ if ( propValue == null ) {
+ continue;
+ }
+
+ final PropertyDescriptorDTO propertyDescriptorDto = descriptors.get(propName);
+ if ( propertyDescriptorDto != null && propertyDescriptorDto.isIdentifiesControllerService() ) {
+ final ControllerServiceNode serviceNode = flowController.getControllerServiceNode(propValue);
+ if ( serviceNode != null ) {
+ addControllerServicesToSnippet(snippet, serviceNode);
+ }
+ }
+ }
+ }
+ }
+
+ private void addControllerServicesToSnippet(final FlowSnippetDTO snippet, final ControllerServiceNode serviceNode) {
+ if ( isServicePresent(serviceNode.getIdentifier(), snippet.getControllerServices()) ) {
+ return;
+ }
+
+ final ControllerServiceDTO serviceNodeDto = dtoFactory.createControllerServiceDto(serviceNode);
+ Set<ControllerServiceDTO> existingServiceDtos = snippet.getControllerServices();
+ if ( existingServiceDtos == null ) {
+ existingServiceDtos = new HashSet<>();
+ snippet.setControllerServices(existingServiceDtos);
+ }
+ existingServiceDtos.add(serviceNodeDto);
+
+ for ( final Map.Entry<PropertyDescriptor, String> entry : serviceNode.getProperties().entrySet() ) {
+ final PropertyDescriptor descriptor = entry.getKey();
+ final String propertyValue = entry.getValue();
+
+ if ( descriptor.getControllerServiceDefinition() != null ) {
+ final ControllerServiceNode referencedNode = flowController.getControllerServiceNode(propertyValue);
+ if ( referencedNode == null ) {
+ throw new IllegalStateException("Controller Service with ID " + propertyValue + " is referenced in template but cannot be found");
+ }
+
+ final String referencedNodeId = referencedNode.getIdentifier();
+
+ final boolean alreadyPresent = isServicePresent(referencedNodeId, snippet.getControllerServices());
+ if ( !alreadyPresent ) {
+ addControllerServicesToSnippet(snippet, referencedNode);
+ }
+ }
+ }
+ }
+ private boolean isServicePresent(final String serviceId, final Collection<ControllerServiceDTO> services) {
+ if ( services == null ) {
+ return false;
+ }
+
+ for ( final ControllerServiceDTO existingService : services ) {
+ if ( serviceId.equals(existingService.getId()) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
public FlowSnippetDTO copy(final FlowSnippetDTO snippetContents, final ProcessGroup group) {
- final FlowSnippetDTO snippetCopy = copyContentsForGroup(snippetContents, group.getIdentifier(), null);
+ final FlowSnippetDTO snippetCopy = copyContentsForGroup(snippetContents, group.getIdentifier(), null, null);
resolveNameConflicts(snippetCopy, group);
return snippetCopy;
}
@@ -240,10 +336,49 @@ public final class SnippetUtils {
}
}
- private FlowSnippetDTO copyContentsForGroup(final FlowSnippetDTO snippetContents, final String groupId, final Map<String, ConnectableDTO> parentConnectableMap) {
+ private FlowSnippetDTO copyContentsForGroup(final FlowSnippetDTO snippetContents, final String groupId, final Map<String, ConnectableDTO> parentConnectableMap, Map<String, String> serviceIdMap) {
final FlowSnippetDTO snippetContentsCopy = new FlowSnippetDTO();
//
+ // Copy the Controller Services
+ //
+ if ( serviceIdMap == null ) {
+ serviceIdMap = new HashMap<>();
+ final Set<ControllerServiceDTO> services = new HashSet<>();
+ if ( snippetContents.getControllerServices() != null ) {
+ for (final ControllerServiceDTO serviceDTO : snippetContents.getControllerServices() ) {
+ final ControllerServiceDTO service = dtoFactory.copy(serviceDTO);
+ service.setId(generateId(serviceDTO.getId()));
+ service.setState(ControllerServiceState.DISABLED.name());
+ services.add(service);
+
+ // Map old service ID to new service ID so that we can make sure that we reference the new ones.
+ serviceIdMap.put(serviceDTO.getId(), service.getId());
+ }
+ }
+
+ // if there is any controller service that maps to another controller service, update the id's
+ for ( final ControllerServiceDTO serviceDTO : services ) {
+ final Map<String, String> properties = serviceDTO.getProperties();
+ final Map<String, PropertyDescriptorDTO> descriptors = serviceDTO.getDescriptors();
+ if ( properties != null && descriptors != null ) {
+ for ( final PropertyDescriptorDTO descriptor : descriptors.values() ) {
+ if ( descriptor.isIdentifiesControllerService() ) {
+ final String currentServiceId = properties.get(descriptor.getName());
+ if ( currentServiceId == null ) {
+ continue;
+ }
+
+ final String newServiceId = serviceIdMap.get(currentServiceId);
+ properties.put(descriptor.getName(), newServiceId);
+ }
+ }
+ }
+ }
+ snippetContentsCopy.setControllerServices(services);
+ }
+
+ //
// Copy the labels
//
final Set<LabelDTO> labels = new HashSet<>();
@@ -332,6 +467,9 @@ public final class SnippetUtils {
}
snippetContentsCopy.setProcessors(processors);
+ // if there is any controller service that maps to another controller service, update the id's
+ updateControllerServiceIdentifiers(snippetContentsCopy, serviceIdMap);
+
//
// Copy ProcessGroups
//
@@ -344,7 +482,7 @@ public final class SnippetUtils {
cp.setParentGroupId(groupId);
// copy the contents of this group - we do not copy via the dto factory since we want to specify new ids
- final FlowSnippetDTO contentsCopy = copyContentsForGroup(groupDTO.getContents(), cp.getId(), connectableMap);
+ final FlowSnippetDTO contentsCopy = copyContentsForGroup(groupDTO.getContents(), cp.getId(), connectableMap, serviceIdMap);
cp.setContents(contentsCopy);
groups.add(cp);
}
@@ -396,6 +534,43 @@ public final class SnippetUtils {
return snippetContentsCopy;
}
+
+
+ private void updateControllerServiceIdentifiers(final FlowSnippetDTO snippet, final Map<String, String> serviceIdMap) {
+ final Set<ProcessorDTO> processors = snippet.getProcessors();
+ if ( processors != null ) {
+ for ( final ProcessorDTO processor : processors ) {
+ updateControllerServiceIdentifiers(processor.getConfig(), serviceIdMap);
+ }
+ }
+
+ for ( final ProcessGroupDTO processGroupDto : snippet.getProcessGroups() ) {
+ updateControllerServiceIdentifiers(processGroupDto.getContents(), serviceIdMap);
+ }
+ }
+
+ private void updateControllerServiceIdentifiers(final ProcessorConfigDTO configDto, final Map<String, String> serviceIdMap) {
+ if ( configDto == null ) {
+ return;
+ }
+
+ final Map<String, String> properties = configDto.getProperties();
+ final Map<String, PropertyDescriptorDTO> descriptors = configDto.getDescriptors();
+ if ( properties != null && descriptors != null ) {
+ for ( final PropertyDescriptorDTO descriptor : descriptors.values() ) {
+ if ( descriptor.isIdentifiesControllerService() ) {
+ final String currentServiceId = properties.get(descriptor.getName());
+ if ( currentServiceId == null ) {
+ continue;
+ }
+
+ final String newServiceId = serviceIdMap.get(currentServiceId);
+ properties.put(descriptor.getName(), newServiceId);
+ }
+ }
+ }
+ }
+
/**
* Generates a new id for the current id that is specified. If no seed is
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/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/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index a822442..bf4f245 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -24,11 +24,17 @@
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
+ <!-- controller service / reporting task -->
+ <bean id="controllerServiceProvider" class="org.apache.nifi.web.spring.ControllerServiceProviderFactoryBean" depends-on="clusterManager flowController">
+ <property name="properties" ref="nifiProperties"/>
+ </bean>
+ <bean id="reportingTaskProvider" class="org.apache.nifi.web.spring.ReportingTaskProviderFactoryBean" depends-on="clusterManager flowController">
+ <property name="properties" ref="nifiProperties"/>
+ </bean>
+
<!-- optimistic locking manager -->
- <bean id="optimisticLockingManager" class="org.apache.nifi.web.ClusterAwareOptimisticLockingManager">
- <constructor-arg>
- <bean class="org.apache.nifi.web.StandardOptimisticLockingManager" />
- </constructor-arg>
+ <bean id="webOptimisticLockingManager" class="org.apache.nifi.web.spring.OptimisticLockingManagerFactoryBean" depends-on="clusterManagerOptimisticLockingManager">
+ <property name="properties" ref="nifiProperties"/>
</bean>
<!-- content access -->
@@ -40,8 +46,7 @@
<!-- dto factory -->
<bean id="dtoFactory" class="org.apache.nifi.web.api.dto.DtoFactory">
- <property name="properties" ref="nifiProperties"/>
- <property name="controllerServiceLookup" ref="flowController" />
+ <property name="controllerServiceLookup" ref="controllerServiceProvider" />
</bean>
<!-- snippet utils -->
@@ -75,6 +80,12 @@
<bean id="processorDAO" class="org.apache.nifi.web.dao.impl.StandardProcessorDAO">
<property name="flowController" ref="flowController"/>
</bean>
+ <bean id="controllerServiceDAO" class="org.apache.nifi.web.dao.impl.StandardControllerServiceDAO">
+ <property name="serviceProvider" ref="controllerServiceProvider"/>
+ </bean>
+ <bean id="reportingTaskDAO" class="org.apache.nifi.web.dao.impl.StandardReportingTaskDAO">
+ <property name="reportingTaskProvider" ref="reportingTaskProvider"/>
+ </bean>
<bean id="templateDAO" class="org.apache.nifi.web.dao.impl.StandardTemplateDAO">
<property name="flowController" ref="flowController"/>
<property name="snippetUtils" ref="snippetUtils"/>
@@ -101,22 +112,35 @@
<property name="labelDAO" ref="labelDAO"/>
<property name="funnelDAO" ref="funnelDAO"/>
<property name="connectionDAO" ref="connectionDAO"/>
+ <property name="controllerServiceDAO" ref="controllerServiceDAO"/>
+ <property name="reportingTaskDAO" ref="reportingTaskDAO"/>
<property name="templateDAO" ref="templateDAO"/>
<property name="snippetDAO" ref="snippetDAO"/>
<property name="auditService" ref="auditService"/>
<property name="userService" ref="userService"/>
<property name="snippetUtils" ref="snippetUtils"/>
- <property name="optimisticLockingManager" ref="optimisticLockingManager"/>
+ <property name="optimisticLockingManager" ref="webOptimisticLockingManager"/>
<property name="dtoFactory" ref="dtoFactory"/>
<property name="clusterManager" ref="clusterManager"/>
</bean>
+ <!-- depecrated -->
<bean id="nifiWebContext" class="org.apache.nifi.web.StandardNiFiWebContext">
<property name="serviceFacade" ref="serviceFacade"/>
- <property name="controllerFacade" ref="controllerFacade"/>
<property name="properties" ref="nifiProperties"/>
<property name="clusterManager" ref="clusterManager"/>
<property name="auditService" ref="auditService"/>
+ <property name="controllerServiceLookup" ref="controllerServiceProvider"/>
+ </bean>
+
+ <!-- component ui extension configuration context -->
+ <bean id="nifiWebConfigurationContext" class="org.apache.nifi.web.StandardNiFiWebConfigurationContext">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="properties" ref="nifiProperties"/>
+ <property name="clusterManager" ref="clusterManager"/>
+ <property name="auditService" ref="auditService"/>
+ <property name="controllerServiceLookup" ref="controllerServiceProvider"/>
+ <property name="reportingTaskProvider" ref="reportingTaskProvider"/>
</bean>
<!-- rest endpoints -->
@@ -133,6 +157,16 @@
<property name="properties" ref="nifiProperties"/>
<property name="clusterManager" ref="clusterManager"/>
</bean>
+ <bean id="controllerServiceResource" class="org.apache.nifi.web.api.ControllerServiceResource" scope="singleton">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="properties" ref="nifiProperties"/>
+ <property name="clusterManager" ref="clusterManager"/>
+ </bean>
+ <bean id="reportingTaskResource" class="org.apache.nifi.web.api.ReportingTaskResource" scope="singleton">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="properties" ref="nifiProperties"/>
+ <property name="clusterManager" ref="clusterManager"/>
+ </bean>
<bean id="processGroupResource" class="org.apache.nifi.web.api.ProcessGroupResource" scope="prototype">
<property name="serviceFacade" ref="serviceFacade"/>
<property name="properties" ref="nifiProperties"/>
@@ -303,6 +337,16 @@
<property name="processorAuditor" ref="processorAuditor"/>
<property name="relationshipAuditor" ref="relationshipAuditor"/>
</bean>
+ <bean id="controllerServiceAuditor" class="org.apache.nifi.audit.ControllerServiceAuditor">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="auditService" ref="auditService"/>
+ <property name="processGroupDAO" ref="processGroupDAO"/>
+ </bean>
+ <bean id="reportingTaskAuditor" class="org.apache.nifi.audit.ReportingTaskAuditor">
+ <property name="serviceFacade" ref="serviceFacade"/>
+ <property name="auditService" ref="auditService"/>
+ <property name="processGroupDAO" ref="processGroupDAO"/>
+ </bean>
<!-- NiFi locking -->
<bean id="serviceFacadeLock" class="org.apache.nifi.web.NiFiServiceFacadeLock"/>
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java
index dd9bb73..1f28609 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/integration/util/NiFiTestServer.java
@@ -18,12 +18,14 @@ package org.apache.nifi.integration.util;
import com.sun.jersey.api.client.Client;
import java.io.File;
+import java.util.Collections;
import javax.servlet.ServletContext;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.util.WebUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.framework.security.util.SslContextFactory;
import org.apache.nifi.services.FlowService;
+import org.apache.nifi.ui.extension.UiExtensionMapping;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
@@ -160,6 +162,9 @@ public class NiFiTestServer {
*/
public void startServer() throws Exception {
jetty.start();
+
+ // ensure the ui extensions are set
+ webappContext.getServletContext().setAttribute("nifi-ui-extensions", new UiExtensionMapping(Collections.EMPTY_MAP));
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/pom.xml
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/pom.xml b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/pom.xml
index e9781f8..a9f0c3e 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/pom.xml
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/pom.xml
@@ -27,5 +27,17 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-administration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-web-security</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-framework-cluster-web</artifactId>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationRequest.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationRequest.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationRequest.java
new file mode 100644
index 0000000..939c3f0
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationRequest.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * Represents a request to configure. The implementations execute method will
+ * perform the configuration action. It will return type T which will be
+ * encapsulated in a ConfigurationSnapshot.
+ *
+ * @param <T>
+ */
+public interface ConfigurationRequest<T> {
+
+ /**
+ * Executes a configuration action and returns the updated resulting configuration.
+ *
+ * @return The resulting configuration
+ */
+ T execute();
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationSnapshot.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationSnapshot.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationSnapshot.java
index 6ad683c..8817d69 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationSnapshot.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/ConfigurationSnapshot.java
@@ -22,36 +22,36 @@ package org.apache.nifi.web;
*/
public class ConfigurationSnapshot<T> {
- private Long revision;
+ private Long version;
private T configuration;
/**
* Creates a new ConfigurationSnapshot.
*
- * @param revision The model revision
+ * @param version The revision version
*/
- public ConfigurationSnapshot(Long revision) {
- this(revision, null);
+ public ConfigurationSnapshot(Long version) {
+ this(version, null);
}
/**
* Creates a new ConfigurationSnapshot.
*
- * @param revision The model revision
+ * @param version The revision version
* @param configuration The configuration
*/
- public ConfigurationSnapshot(Long revision, T configuration) {
- this.revision = revision;
+ public ConfigurationSnapshot(Long version, T configuration) {
+ this.version = version;
this.configuration = configuration;
}
/**
- * Get the new model revision.
+ * Get the revision version.
*
- * @return The model revision
+ * @return The revision version
*/
- public Long getRevision() {
- return revision;
+ public Long getVersion() {
+ return version;
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/FlowModification.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/FlowModification.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/FlowModification.java
new file mode 100644
index 0000000..f6bccb1
--- /dev/null
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/FlowModification.java
@@ -0,0 +1,57 @@
+/*
+ * 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;
+
+/**
+ * Records a flow modification. This includes the resulting revision and the
+ * user that performed the modification.
+ */
+public class FlowModification {
+
+ private final Revision revision;
+ private final String lastModifier;
+
+ /**
+ * Creates a new FlowModification.
+ *
+ * @param revision
+ * @param lastModifier
+ */
+ public FlowModification(Revision revision, String lastModifier) {
+ this.revision = revision;
+ this.lastModifier = lastModifier;
+ }
+
+ /**
+ * Get the revision.
+ *
+ * @return
+ */
+ public Revision getRevision() {
+ return revision;
+ }
+
+ /**
+ * Get the last modifier.
+ *
+ * @return
+ */
+ public String getLastModifier() {
+ return lastModifier;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-nifi/blob/e9647717/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/OptimisticLockingManager.java
----------------------------------------------------------------------
diff --git a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/OptimisticLockingManager.java b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/OptimisticLockingManager.java
index b045247..4c54b7c 100644
--- a/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/OptimisticLockingManager.java
+++ b/nifi/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-optimistic-locking/src/main/java/org/apache/nifi/web/OptimisticLockingManager.java
@@ -26,70 +26,28 @@ package org.apache.nifi.web;
public interface OptimisticLockingManager {
/**
- * Checks the specified revision against the current revision. If the check
- * succeeds, then the current revision's version is incremented and the
- * current revision's client ID is set to the given revision's client ID.
- *
- * If the given revision's version is null, then the revision's client ID
- * must match for the current revision's client ID for the check to succeed.
- *
- * If the versions and the clientIds do not match, then an
- * InvalidRevisionException.
- *
- * @param revision the revision to check
- *
- * @return the current revision
- *
- * @throws InvalidRevisionException if the given revision does not match the
- * current revision
+ * Attempts to execute the specified configuration request using the specified revision within a lock.
+ *
+ * @param <T>
+ * @param revision
+ * @param configurationRequest
+ * @return
*/
- Revision checkRevision(Revision revision) throws InvalidRevisionException;
-
- /**
- * Returns true if the given revision matches the current revision.
- *
- * @param revision a revision
- * @return true if given revision is current; false otherwise.
- */
- boolean isCurrent(Revision revision);
-
+ <T> ConfigurationSnapshot<T> configureFlow(Revision revision, ConfigurationRequest<T> configurationRequest);
+
/**
- * @return the current revision
+ * Updates the revision using the specified revision within a lock.
+ *
+ * @param updateRevision
*/
- Revision getRevision();
+ void setRevision(UpdateRevision updateRevision);
/**
- * Sets the current revision.
- *
- * @param revision a revision
+ * Returns the last flow modification. This is a combination of the revision and the user
+ * who performed the modification.
+ *
+ * @return the last modification
*/
- void setRevision(Revision revision);
+ FlowModification getLastModification();
- /**
- * Increments the current revision's version.
- *
- * @return the current revision
- */
- Revision incrementRevision();
-
- /**
- * Increments the current revision's version and sets the current revision's
- * client ID to the given client ID.
- *
- * @param clientId a client ID
- * @return the current revision
- */
- Revision incrementRevision(String clientId);
-
- /**
- * @return the last modifier.
- */
- String getLastModifier();
-
- /**
- * Sets the last modifier.
- *
- * @param lastModifier the last modifier
- */
- void setLastModifier(String lastModifier);
}