Merge branch 'NIFI-259' of https://git-wip-us.apache.org/repos/asf/nifi into NIFI-259

This commit is contained in:
Mark Payne 2016-01-13 13:57:57 -05:00
commit 06f525b674
18 changed files with 649 additions and 13 deletions

View File

@ -27,6 +27,7 @@ import javax.xml.bind.annotation.XmlType;
public class ComponentStateDTO { public class ComponentStateDTO {
private String componentId; private String componentId;
private String stateDescription;
private StateMapDTO clusterState; private StateMapDTO clusterState;
private StateMapDTO localState; private StateMapDTO localState;
@ -44,6 +45,20 @@ public class ComponentStateDTO {
this.componentId = componentId; this.componentId = componentId;
} }
/**
* @return Description of the state this component persists.
*/
@ApiModelProperty(
value = "Description of the state this component persists."
)
public String getStateDescription() {
return stateDescription;
}
public void setStateDescription(String stateDescription) {
this.stateDescription = stateDescription;
}
/** /**
* @return The cluster state for this component, or null if this NiFi is a standalone instance * @return The cluster state for this component, or null if this NiFi is a standalone instance
*/ */

View File

@ -33,6 +33,7 @@ public class ControllerServiceDTO extends NiFiComponentDTO {
private String comments; private String comments;
private String availability; private String availability;
private String state; private String state;
private Boolean persistsState;
private Map<String, String> properties; private Map<String, String> properties;
private Map<String, PropertyDescriptorDTO> descriptors; private Map<String, PropertyDescriptorDTO> descriptors;
@ -101,6 +102,20 @@ public class ControllerServiceDTO extends NiFiComponentDTO {
this.availability = availability; this.availability = availability;
} }
/**
* @return whether this controller service persists state
*/
@ApiModelProperty(
value = "Whether the controller service persists state."
)
public Boolean getPersistsState() {
return persistsState;
}
public void setPersistsState(Boolean persistsState) {
this.persistsState = persistsState;
}
/** /**
* @return The state of this controller service. Possible values are ENABLED, ENABLING, DISABLED, DISABLING * @return The state of this controller service. Possible values are ENABLED, ENABLING, DISABLED, DISABLING
*/ */

View File

@ -37,6 +37,7 @@ public class ProcessorDTO extends NiFiComponentDTO {
private Boolean supportsParallelProcessing; private Boolean supportsParallelProcessing;
private Boolean supportsEventDriven; private Boolean supportsEventDriven;
private Boolean supportsBatching; private Boolean supportsBatching;
private Boolean persistsState;
private String inputRequirement; private String inputRequirement;
private ProcessorConfigDTO config; private ProcessorConfigDTO config;
@ -122,6 +123,20 @@ public class ProcessorDTO extends NiFiComponentDTO {
this.supportsParallelProcessing = supportsParallelProcessing; this.supportsParallelProcessing = supportsParallelProcessing;
} }
/**
* @return whether this processor persists state
*/
@ApiModelProperty(
value = "Whether the processor persists state."
)
public Boolean getPersistsState() {
return persistsState;
}
public void setPersistsState(Boolean persistsState) {
this.persistsState = persistsState;
}
/** /**
* @return the input requirement of this processor * @return the input requirement of this processor
*/ */

View File

@ -33,6 +33,7 @@ public class ReportingTaskDTO extends NiFiComponentDTO {
private String state; private String state;
private String availability; private String availability;
private String comments; private String comments;
private Boolean persistsState;
private String schedulingPeriod; private String schedulingPeriod;
private String schedulingStrategy; private String schedulingStrategy;
@ -105,6 +106,20 @@ public class ReportingTaskDTO extends NiFiComponentDTO {
this.schedulingPeriod = schedulingPeriod; this.schedulingPeriod = schedulingPeriod;
} }
/**
* @return whether this reporting task persists state
*/
@ApiModelProperty(
value = "Whether the reporting task persists state."
)
public Boolean getPersistsState() {
return persistsState;
}
public void setPersistsState(Boolean persistsState) {
this.persistsState = persistsState;
}
/** /**
* @return current scheduling state of the reporting task * @return current scheduling state of the reporting task
*/ */

View File

@ -18,6 +18,7 @@ package org.apache.nifi.web;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.lf5.util.Resource;
import org.apache.nifi.action.Action; import org.apache.nifi.action.Action;
import org.apache.nifi.action.Component; import org.apache.nifi.action.Component;
import org.apache.nifi.action.FlowChangeAction; import org.apache.nifi.action.FlowChangeAction;
@ -2168,23 +2169,32 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
@Override @Override
public ComponentStateDTO getProcessorState(String groupId, String processorId) { public ComponentStateDTO getProcessorState(String groupId, String processorId) {
final StateMap clusterState = processorDAO.getState(groupId, processorId, Scope.CLUSTER); final StateMap clusterState = isClustered() ? processorDAO.getState(groupId, processorId, Scope.CLUSTER) : null;
final StateMap localState = processorDAO.getState(groupId, processorId, Scope.LOCAL); final StateMap localState = processorDAO.getState(groupId, processorId, Scope.LOCAL);
return dtoFactory.createComponentStateDTO(processorId, localState, clusterState);
// processor will be non null as it was already found when getting the state
final ProcessorNode processor = processorDAO.getProcessor(groupId, processorId);
return dtoFactory.createComponentStateDTO(processorId, processor.getProcessor().getClass(), localState, clusterState);
} }
@Override @Override
public ComponentStateDTO getControllerServiceState(String controllerServiceId) { public ComponentStateDTO getControllerServiceState(String controllerServiceId) {
final StateMap clusterState = controllerServiceDAO.getState(controllerServiceId, Scope.CLUSTER); final StateMap clusterState = isClustered() ? controllerServiceDAO.getState(controllerServiceId, Scope.CLUSTER) : null;
final StateMap localState = controllerServiceDAO.getState(controllerServiceId, Scope.LOCAL); final StateMap localState = controllerServiceDAO.getState(controllerServiceId, Scope.LOCAL);
return dtoFactory.createComponentStateDTO(controllerServiceId, localState, clusterState);
// controller service will be non null as it was already found when getting the state
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceId);
return dtoFactory.createComponentStateDTO(controllerServiceId, controllerService.getControllerServiceImplementation().getClass(), localState, clusterState);
} }
@Override @Override
public ComponentStateDTO getReportingTaskState(String reportingTaskId) { public ComponentStateDTO getReportingTaskState(String reportingTaskId) {
final StateMap clusterState = reportingTaskDAO.getState(reportingTaskId, Scope.CLUSTER); final StateMap clusterState = isClustered() ? reportingTaskDAO.getState(reportingTaskId, Scope.CLUSTER) : null;
final StateMap localState = reportingTaskDAO.getState(reportingTaskId, Scope.LOCAL); final StateMap localState = reportingTaskDAO.getState(reportingTaskId, Scope.LOCAL);
return dtoFactory.createComponentStateDTO(reportingTaskId, localState, clusterState);
// reporting task will be non null as it was already found when getting the state
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskId);
return dtoFactory.createComponentStateDTO(reportingTaskId, reportingTask.getReportingTask().getClass(), localState, clusterState);
} }
@Override @Override

View File

@ -32,6 +32,7 @@ import org.apache.nifi.action.details.FlowChangeMoveDetails;
import org.apache.nifi.action.details.FlowChangePurgeDetails; import org.apache.nifi.action.details.FlowChangePurgeDetails;
import org.apache.nifi.action.details.MoveDetails; import org.apache.nifi.action.details.MoveDetails;
import org.apache.nifi.action.details.PurgeDetails; import org.apache.nifi.action.details.PurgeDetails;
import org.apache.nifi.annotation.behavior.Stateful;
import org.apache.nifi.annotation.documentation.CapabilityDescription; import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags; import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.authorization.Authority; import org.apache.nifi.authorization.Authority;
@ -279,14 +280,30 @@ public final class DtoFactory {
* @param clusterState cluster state * @param clusterState cluster state
* @return dto * @return dto
*/ */
public ComponentStateDTO createComponentStateDTO(final String componentId, final StateMap localState, final StateMap clusterState) { public ComponentStateDTO createComponentStateDTO(final String componentId, final Class<?> componentClass, final StateMap localState, final StateMap clusterState) {
final ComponentStateDTO dto = new ComponentStateDTO(); final ComponentStateDTO dto = new ComponentStateDTO();
dto.setComponentId(componentId); dto.setComponentId(componentId);
dto.setStateDescription(getStateDescription(componentClass));
dto.setLocalState(createStateMapDTO(Scope.LOCAL, localState)); dto.setLocalState(createStateMapDTO(Scope.LOCAL, localState));
dto.setClusterState(createStateMapDTO(Scope.CLUSTER, clusterState)); dto.setClusterState(createStateMapDTO(Scope.CLUSTER, clusterState));
return dto; return dto;
} }
/**
* Gets the description of the state this component persists.
*
* @param componentClass the component class
* @return state description
*/
private String getStateDescription(final Class<?> componentClass) {
final Stateful capabilityDesc = componentClass.getAnnotation(Stateful.class);
if (capabilityDesc != null) {
return capabilityDesc.description();
} else {
return null;
}
}
/** /**
* Creates a StateMapDTO for the given scope and state map. * Creates a StateMapDTO for the given scope and state map.
* *
@ -295,6 +312,10 @@ public final class DtoFactory {
* @return dto * @return dto
*/ */
public StateMapDTO createStateMapDTO(final Scope scope, final StateMap stateMap) { public StateMapDTO createStateMapDTO(final Scope scope, final StateMap stateMap) {
if (stateMap == null) {
return null;
}
final StateMapDTO dto = new StateMapDTO(); final StateMapDTO dto = new StateMapDTO();
dto.setScope(scope.toString()); dto.setScope(scope.toString());
@ -1066,6 +1087,7 @@ public final class DtoFactory {
dto.setActiveThreadCount(reportingTaskNode.getActiveThreadCount()); dto.setActiveThreadCount(reportingTaskNode.getActiveThreadCount());
dto.setAnnotationData(reportingTaskNode.getAnnotationData()); dto.setAnnotationData(reportingTaskNode.getAnnotationData());
dto.setComments(reportingTaskNode.getComments()); dto.setComments(reportingTaskNode.getComments());
dto.setPersistsState(reportingTaskNode.getReportingTask().getClass().isAnnotationPresent(Stateful.class));
final Map<String, String> defaultSchedulingPeriod = new HashMap<>(); final Map<String, String> defaultSchedulingPeriod = new HashMap<>();
defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod()); defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod());
@ -1133,6 +1155,7 @@ public final class DtoFactory {
dto.setState(controllerServiceNode.getState().name()); dto.setState(controllerServiceNode.getState().name());
dto.setAnnotationData(controllerServiceNode.getAnnotationData()); dto.setAnnotationData(controllerServiceNode.getAnnotationData());
dto.setComments(controllerServiceNode.getComments()); dto.setComments(controllerServiceNode.getComments());
dto.setPersistsState(controllerServiceNode.getControllerServiceImplementation().getClass().isAnnotationPresent(Stateful.class));
// sort a copy of the properties // sort a copy of the properties
final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() { final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() {
@ -1610,6 +1633,7 @@ public final class DtoFactory {
dto.setStyle(node.getStyle()); dto.setStyle(node.getStyle());
dto.setParentGroupId(node.getProcessGroup().getIdentifier()); dto.setParentGroupId(node.getProcessGroup().getIdentifier());
dto.setInputRequirement(node.getInputRequirement().name()); dto.setInputRequirement(node.getInputRequirement().name());
dto.setPersistsState(node.getProcessor().getClass().isAnnotationPresent(Stateful.class));
dto.setType(node.getProcessor().getClass().getCanonicalName()); dto.setType(node.getProcessor().getClass().getCanonicalName());
dto.setName(node.getName()); dto.setName(node.getName());

View File

@ -281,6 +281,7 @@
<include>${staging.dir}/js/nf/canvas/nf-canvas-toolbox.js</include> <include>${staging.dir}/js/nf/canvas/nf-canvas-toolbox.js</include>
<include>${staging.dir}/js/nf/canvas/nf-custom-ui.js</include> <include>${staging.dir}/js/nf/canvas/nf-custom-ui.js</include>
<include>${staging.dir}/js/nf/canvas/nf-queue-listing.js</include> <include>${staging.dir}/js/nf/canvas/nf-queue-listing.js</include>
<include>${staging.dir}/js/nf/canvas/nf-component-state.js</include>
<include>${staging.dir}/js/nf/canvas/nf-controller-service.js</include> <include>${staging.dir}/js/nf/canvas/nf-controller-service.js</include>
<include>${staging.dir}/js/nf/canvas/nf-reporting-task.js</include> <include>${staging.dir}/js/nf/canvas/nf-reporting-task.js</include>
<include>${staging.dir}/js/nf/canvas/nf-processor-configuration.js</include> <include>${staging.dir}/js/nf/canvas/nf-processor-configuration.js</include>

View File

@ -22,6 +22,7 @@ nf.canvas.script.tags=<script type="text/javascript" src="js/nf/nf-namespace.js?
<script type="text/javascript" src="js/nf/nf-storage.js?${project.version}"></script>\n\ <script type="text/javascript" src="js/nf/nf-storage.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-snippet.js?${project.version}"></script>\n\ <script type="text/javascript" src="js/nf/canvas/nf-snippet.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-queue-listing.js?${project.version}"></script>\n\ <script type="text/javascript" src="js/nf/canvas/nf-queue-listing.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-component-state.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-canvas-toolbox.js?${project.version}"></script>\n\ <script type="text/javascript" src="js/nf/canvas/nf-canvas-toolbox.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-custom-ui.js?${project.version}"></script>\n\ <script type="text/javascript" src="js/nf/canvas/nf-custom-ui.js?${project.version}"></script>\n\
<script type="text/javascript" src="js/nf/canvas/nf-controller-service.js?${project.version}"></script>\n\ <script type="text/javascript" src="js/nf/canvas/nf-controller-service.js?${project.version}"></script>\n\

View File

@ -122,6 +122,7 @@
<jsp:include page="/WEB-INF/partials/canvas/flowfile-details-dialog.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/flowfile-details-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/listing-request-status-dialog.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/listing-request-status-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/queue-listing.jsp"/> <jsp:include page="/WEB-INF/partials/canvas/queue-listing.jsp"/>
<jsp:include page="/WEB-INF/partials/canvas/component-state-dialog.jsp"/>
<jsp:include page="/WEB-INF/partials/connection-details.jsp"/> <jsp:include page="/WEB-INF/partials/connection-details.jsp"/>
<div id="faded-background"></div> <div id="faded-background"></div>
<div id="glass-pane"></div> <div id="glass-pane"></div>

View File

@ -0,0 +1,45 @@
<%--
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.
--%>
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
<div id="component-state-dialog">
<div class="dialog-content">
<div class="setting">
<div class="setting-name">Name</div>
<div class="setting-field">
<span id="component-state-name"></span>
</div>
</div>
<div class="setting">
<div class="setting-name">Description</div>
<div class="setting-field">
<span id="component-state-description"></span>
</div>
</div>
<div id="component-state-filter-controls">
<div id="component-state-filter-container">
<input type="text" id="component-state-filter"/>
</div>
<div id="component-state-filter-status">
Displaying&nbsp;<span id="displayed-component-state-entries"></span>&nbsp;of&nbsp;<span id="total-component-state-entries"></span>
</div>
</div>
<div id="component-state-table"></div>
<div id="clear-link-container">
<span id="clear-link" class="link">Clear state</span>
</div>
</div>
</div>

View File

@ -22,6 +22,7 @@
@import url(queue-listing.css); @import url(queue-listing.css);
@import url(remote-process-group-configuration.css); @import url(remote-process-group-configuration.css);
@import url(controller-service.css); @import url(controller-service.css);
@import url(component-state.css);
@import url(reporting-task.css); @import url(reporting-task.css);
@import url(port-configuration.css); @import url(port-configuration.css);
@import url(port-details.css); @import url(port-details.css);

View File

@ -0,0 +1,88 @@
/*
* 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.
*/
/*
Component state
*/
#component-state-dialog {
position: absolute;
overflow: hidden;
width: 600px;
height: 500px;
font-size: 10px;
z-index: 1301;
display: none;
}
#component-state-description {
height: 50px;
}
/*
Component state filter
*/
#component-state-filter-controls {
float: right;
margin-top: 10px;
margin-right: 2px;
margin-bottom: 7px;
}
#component-state-filter-status {
font-size: 9px;
font-weight: bold;
color: #9f6000;
clear: left;
line-height: normal;
margin-left: 5px;
}
#component-state-filter {
padding: 3px 0px 1px 3px;
font-size: 12px;
height: 18px;
line-height: 20px;
width: 173px;
border: 1px solid #ccc;
float: left;
}
/*
Component state table
*/
#component-state-table {
width: 578px;
height: 235px;
border: 1px solid #666;
}
/*
Clear
*/
#clear-link-container {
margin-top: 16px;
}
#clear-link.disabled {
color: #bbb;
font-style: italic;
text-decoration: none !important;
}

View File

@ -1063,6 +1063,23 @@ nf.Actions = (function () {
nf.QueueListing.listQueue(connection); nf.QueueListing.listQueue(connection);
}, },
/**
* Views the state for the specified processor.
*
* @param {selection} selection
*/
viewState: function (selection) {
if (selection.size() !== 1 || !nf.CanvasUtils.isProcessor(selection)) {
return;
}
// get the processor data
var processor = selection.datum();
// view the state for the selected processor
nf.ComponentState.showState(processor.component, nf.CanvasUtils.supportsModification(selection));
},
/** /**
* Opens the fill color dialog for the component in the specified selection. * Opens the fill color dialog for the component in the specified selection.
* *

View File

@ -1151,6 +1151,7 @@ nf.Canvas = (function () {
nf.Settings.init(); nf.Settings.init();
nf.Actions.init(); nf.Actions.init();
nf.QueueListing.init(); nf.QueueListing.init();
nf.ComponentState.init();
// initialize the component behaviors // initialize the component behaviors
nf.Draggable.init(); nf.Draggable.init();

View File

@ -0,0 +1,358 @@
/*
* 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.
*/
/* global nf */
/**
* Views state for a given component.
*/
nf.ComponentState = (function () {
var config = {
filterText: 'Filter',
styles: {
filterList: 'filter-list'
}
};
/**
* Filters the component state table.
*/
var applyFilter = function () {
// get the dataview
var componentStateTable = $('#component-state-table').data('gridInstance');
// ensure the grid has been initialized
if (nf.Common.isDefinedAndNotNull(componentStateTable)) {
var componentStateData = componentStateTable.getData();
// update the search criteria
componentStateData.setFilterArgs({
searchString: getFilterText()
});
componentStateData.refresh();
}
};
/**
* Determines if the item matches the filter.
*
* @param {object} item The item to filter
* @param {object} args The filter criteria
* @returns {boolean} Whether the item matches the filter
*/
var filter = function (item, args) {
if (args.searchString === '') {
return true;
}
try {
// perform the row filtering
var filterExp = new RegExp(args.searchString, 'i');
} catch (e) {
// invalid regex
return false;
}
// determine if the item matches the filter
var matchesKey = item['key'].search(filterExp) >= 0;
var matchesValue = item['value'].search(filterExp) >= 0;
// conditionally consider the scope
var matchesScope = false;
if (nf.Common.isDefinedAndNotNull(item['scope'])) {
matchesScope = item['scope'].search(filterExp) >= 0;
}
return matchesKey || matchesValue || matchesScope;
};
/**
* Sorts the specified data using the specified sort details.
*
* @param {object} sortDetails
* @param {object} data
*/
var sort = function (sortDetails, data) {
// defines a function for sorting
var comparer = function (a, b) {
var aString = nf.Common.isDefinedAndNotNull(a[sortDetails.columnId]) ? a[sortDetails.columnId] : '';
var bString = nf.Common.isDefinedAndNotNull(b[sortDetails.columnId]) ? b[sortDetails.columnId] : '';
return aString === bString ? 0 : aString > bString ? 1 : -1;
};
// perform the sort
data.sort(comparer, sortDetails.sortAsc);
};
/**
* Get the text out of the filter field. If the filter field doesn't
* have any text it will contain the text 'filter list' so this method
* accounts for that.
*/
var getFilterText = function () {
var filterText = '';
var filterField = $('#component-state-filter');
if (!filterField.hasClass(config.styles.filterList)) {
filterText = filterField.val();
}
return filterText;
};
/**
* Clears the component state table.
*/
var clearTable = function () {
var componentStateGrid = $('#component-state-table').data('gridInstance');
var componentStateData = componentStateGrid.getData();
componentStateData.setItems([]);
};
/**
* Loads the table with the component state.
*
* @param {object} componentState
*/
var loadComponentState = function (localState, clusterState) {
var count = 0;
var componentStateGrid = $('#component-state-table').data('gridInstance');
var componentStateData = componentStateGrid.getData();
// begin the update
componentStateData.beginUpdate();
// local state
if (nf.Common.isDefinedAndNotNull(localState)) {
$.each(localState.state, function (i, stateEntry) {
componentStateData.addItem($.extend({
id: count++,
scope: stateEntry.nodeAddress
}, stateEntry));
});
}
if (nf.Common.isDefinedAndNotNull(clusterState)) {
$.each(clusterState.state, function (i, stateEntry) {
componentStateData.addItem($.extend({
id: count++,
scope: 'Cluster'
}, stateEntry));
});
}
// complete the update
componentStateData.endUpdate();
// update the total number of state entries
$('#total-component-state-entries').text(count);
};
/**
* Reset the dialog.
*/
var resetDialog = function () {
// clear the fields
$('#component-state-name').text('');
$('#component-state-description').text('');
$('#total-component-state-entries').text('');
// clear any filter strings
$('#component-state-filter').addClass(config.styles.filterList).val(config.filterText);
// reset clear link
$('#clear-link').removeClass('disabled').attr('title', '');
// clear the table
clearTable();
// clear the component
$('#component-state-table').removeData('component');
};
return {
init: function () {
// intialize the component state filter
$('#component-state-filter').on('focus', function () {
if ($(this).hasClass(config.styles.filterList)) {
$(this).removeClass(config.styles.filterList).val('');
}
}).on('blur', function () {
if ($(this).val() === '') {
$(this).addClass(config.styles.filterList).val(config.filterText);
}
}).on('keyup', function () {
applyFilter();
}).addClass(config.styles.filterList).val(config.filterText);
// initialize the processor configuration dialog
$('#component-state-dialog').modal({
headerText: 'Component State',
overlayBackground: true,
buttons: [{
buttonText: 'Ok',
handler: {
click: function () {
$(this).modal('hide');
}
}
}],
handler: {
close: function () {
resetDialog();
}
}
}).draggable({
containment: 'parent',
handle: '.dialog-header'
});
// clear state link
$('#clear-link').on('click', function () {
if ($(this).hasClass('disabled') === false) {
// clear the table
clearTable();
// clear the state
var revision = nf.Client.getRevision();
var component = $('#component-state-table').data('component');
$.ajax({
type: 'POST',
url: component.uri + '/state/clear-requests',
data: {
version: revision.version,
clientId: revision.clientId
},
dataType: 'json'
}).done(function (response) {
// update the revision
nf.Client.setRevision(response.revision);
// reload the table with no state
loadComponentState()
}).fail(nf.Common.handleAjaxError);
}
});
// initialize the queue listing table
var componentStateColumns = [
{id: 'key', field: 'key', name: 'Key', sortable: true, resizable: true},
{id: 'value', field: 'value', name: 'Value', sortable: true, resizable: true}
];
// conditionally show the cluster node identifier
if (nf.Canvas.isClustered()) {
componentStateColumns.push({id: 'scope', field: 'scope', name: 'Scope', sortable: true, resizable: true, formatter: scopeFormatter});
}
var componentStateOptions = {
forceFitColumns: true,
enableTextSelectionOnCells: true,
enableCellNavigation: false,
enableColumnReorder: false,
autoEdit: false
};
// initialize the dataview
var componentStateData = new Slick.Data.DataView({
inlineFilters: false
});
componentStateData.setItems([]);
componentStateData.setFilterArgs({
searchString: '',
property: 'key'
});
componentStateData.setFilter(filter);
// initialize the sort
sort({
columnId: 'key',
sortAsc: true
}, componentStateData);
// initialize the grid
var componentStateGrid = new Slick.Grid('#component-state-table', componentStateData, componentStateColumns, componentStateOptions);
componentStateGrid.setSelectionModel(new Slick.RowSelectionModel());
componentStateGrid.registerPlugin(new Slick.AutoTooltips());
componentStateGrid.setSortColumn('key', true);
componentStateGrid.onSort.subscribe(function (e, args) {
sort({
columnId: args.sortCol.field,
sortAsc: args.sortAsc
}, componentStateData);
});
// wire up the dataview to the grid
componentStateData.onRowCountChanged.subscribe(function (e, args) {
componentStateGrid.updateRowCount();
componentStateGrid.render();
// update the total number of displayed items
$('#displayed-component-state-entries').text(args.current);
});
componentStateData.onRowsChanged.subscribe(function (e, args) {
componentStateGrid.invalidateRows(args.rows);
componentStateGrid.render();
});
// hold onto an instance of the grid
$('#component-state-table').data('gridInstance', componentStateGrid);
// initialize the number of display items
$('#displayed-component-state-entries').text('0');
},
/**
* Shows the state for a given component.
*
* @param {object} component
* @param {boolean} canClear
*/
showState: function (component, canClear) {
return $.ajax({
type: 'GET',
url: component.uri + '/state',
dataType: 'json'
}).done(function (response) {
var componentState = response.componentState;
var componentStateTable = $('#component-state-table');
// load the table
loadComponentState(componentState.localState, componentState.clusterState);
// populate the name/description
$('#component-state-name').text(component.name);
$('#component-state-description').text(componentState.stateDescription);
// store the component
componentStateTable.data('component', component);
// show the dialog
$('#component-state-dialog').modal('show');
// only activate the link when appropriate
if (canClear === false) {
$('#clear-link').addClass('disabled').attr('title', 'Component state can only be cleared when the component is not actively running');
}
// reset the grid size
var componentStateGrid = componentStateTable.data('gridInstance');
componentStateGrid.resizeCanvas();
}).fail(nf.Common.handleAjaxError);
}
};
}());

View File

@ -231,6 +231,25 @@ nf.ContextMenu = (function () {
(nf.CanvasUtils.isInputPort(selection) && nf.Canvas.getParentGroupId() !== null); (nf.CanvasUtils.isInputPort(selection) && nf.Canvas.getParentGroupId() !== null);
}; };
/**
* Determines whether the current selection is a processor.
*
* @param {selection} selection
*/
var isStatefulProcessor = function (selection) {
// ensure the correct number of components are selected
if (selection.size() !== 1) {
return false;
}
if (nf.CanvasUtils.isProcessor(selection)) {
var processorData = selection.datum();
return processorData.component.persistsState === true;
} else {
return false;
}
};
/** /**
* Determines whether the current selection is a process group. * Determines whether the current selection is a process group.
* *
@ -399,6 +418,7 @@ nf.ContextMenu = (function () {
{condition: canStopTransmission, menuItem: {img: 'images/iconTransmissionInactive.png', text: 'Disable transmission', action: 'disableTransmission'}}, {condition: canStopTransmission, menuItem: {img: 'images/iconTransmissionInactive.png', text: 'Disable transmission', action: 'disableTransmission'}},
{condition: supportsStats, menuItem: {img: 'images/iconChart.png', text: 'Stats', action: 'showStats'}}, {condition: supportsStats, menuItem: {img: 'images/iconChart.png', text: 'Stats', action: 'showStats'}},
{condition: canAccessProvenance, menuItem: {img: 'images/iconProvenance.png', imgStyle: 'context-menu-provenance', text: 'Data provenance', action: 'openProvenance'}}, {condition: canAccessProvenance, menuItem: {img: 'images/iconProvenance.png', imgStyle: 'context-menu-provenance', text: 'Data provenance', action: 'openProvenance'}},
{condition: isStatefulProcessor, menuItem: {img: 'images/iconViewState.png', text: 'View state', action: 'viewState'}},
{condition: canMoveToFront, menuItem: {img: 'images/iconToFront.png', text: 'Bring to front', action: 'toFront'}}, {condition: canMoveToFront, menuItem: {img: 'images/iconToFront.png', text: 'Bring to front', action: 'toFront'}},
{condition: isConnection, menuItem: {img: 'images/iconGoTo.png', text: 'Go to source', action: 'showSource'}}, {condition: isConnection, menuItem: {img: 'images/iconGoTo.png', text: 'Go to source', action: 'showSource'}},
{condition: isConnection, menuItem: {img: 'images/iconGoTo.png', text: 'Go to destination', action: 'showDestination'}}, {condition: isConnection, menuItem: {img: 'images/iconGoTo.png', text: 'Go to destination', action: 'showDestination'}},

View File

@ -572,24 +572,33 @@ nf.ProcessorConfiguration = (function () {
// get the processor details // get the processor details
var processor = selectionData.component; var processor = selectionData.component;
var requests = [];
// reload the processor in case an property descriptors have updated // reload the processor in case an property descriptors have updated
var reloadProcessor = nf.Processor.reload(processor); requests.push(nf.Processor.reload(processor));
// get the processor history // get the processor history
var loadHistory = $.ajax({ requests.push($.ajax({
type: 'GET', type: 'GET',
url: '../nifi-api/controller/history/processors/' + encodeURIComponent(processor.id), url: '../nifi-api/controller/history/processors/' + encodeURIComponent(processor.id),
dataType: 'json' dataType: 'json'
}); }));
// get the processor state if we're a DFM
if (nf.Common.isDFM()) {
requests.push();
}
// once everything is loaded, show the dialog // once everything is loaded, show the dialog
$.when(reloadProcessor, loadHistory).done(function (processorResponse, historyResponse) { $.when.apply(window, requests).done(function (processorResponse, historyResponse, stateResponse) {
// get the updated processor // get the updated processor
processor = processorResponse[0].processor; processor = processorResponse[0].processor;
// get the processor history // get the processor history
var processorHistory = historyResponse[0].componentHistory; var processorHistory = historyResponse[0].componentHistory;
console.log(stateResponse);
// record the processor details // record the processor details
$('#processor-configuration').data('processorDetails', processor); $('#processor-configuration').data('processorDetails', processor);