/*
* 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;
import com.google.common.collect.Sets;
import org.apache.nifi.action.Action;
import org.apache.nifi.action.Component;
import org.apache.nifi.action.FlowChangeAction;
import org.apache.nifi.action.Operation;
import org.apache.nifi.action.details.FlowChangePurgeDetails;
import org.apache.nifi.admin.service.AuditService;
import org.apache.nifi.authorization.AccessDeniedException;
import org.apache.nifi.authorization.AccessPolicy;
import org.apache.nifi.authorization.AuthorizableLookup;
import org.apache.nifi.authorization.AuthorizationRequest;
import org.apache.nifi.authorization.AuthorizationResult;
import org.apache.nifi.authorization.AuthorizationResult.Result;
import org.apache.nifi.authorization.AuthorizeAccess;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.Resource;
import org.apache.nifi.authorization.User;
import org.apache.nifi.authorization.UserContextKeys;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.EnforcePolicyPermissionsThroughBaseResource;
import org.apache.nifi.authorization.resource.ResourceFactory;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserUtils;
import org.apache.nifi.cluster.coordination.ClusterCoordinator;
import org.apache.nifi.cluster.coordination.heartbeat.HeartbeatMonitor;
import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat;
import org.apache.nifi.cluster.coordination.node.ClusterRoles;
import org.apache.nifi.cluster.coordination.node.DisconnectionCode;
import org.apache.nifi.cluster.coordination.node.NodeConnectionState;
import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
import org.apache.nifi.cluster.event.NodeEvent;
import org.apache.nifi.cluster.manager.exception.IllegalNodeDeletionException;
import org.apache.nifi.cluster.manager.exception.UnknownNodeException;
import org.apache.nifi.cluster.protocol.NodeIdentifier;
import org.apache.nifi.components.ConfigurableComponent;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.components.state.Scope;
import org.apache.nifi.components.state.StateMap;
import org.apache.nifi.connectable.Connection;
import org.apache.nifi.connectable.Funnel;
import org.apache.nifi.connectable.Port;
import org.apache.nifi.controller.ConfiguredComponent;
import org.apache.nifi.controller.Counter;
import org.apache.nifi.controller.FlowController;
import org.apache.nifi.controller.ProcessorNode;
import org.apache.nifi.controller.ReportingTaskNode;
import org.apache.nifi.controller.ScheduledState;
import org.apache.nifi.controller.Snippet;
import org.apache.nifi.controller.Template;
import org.apache.nifi.controller.label.Label;
import org.apache.nifi.controller.leader.election.LeaderElectionManager;
import org.apache.nifi.controller.repository.claim.ContentDirection;
import org.apache.nifi.controller.service.ControllerServiceNode;
import org.apache.nifi.controller.service.ControllerServiceReference;
import org.apache.nifi.controller.service.ControllerServiceState;
import org.apache.nifi.controller.status.ProcessGroupStatus;
import org.apache.nifi.diagnostics.SystemDiagnostics;
import org.apache.nifi.events.BulletinFactory;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.groups.ProcessGroupCounts;
import org.apache.nifi.groups.RemoteProcessGroup;
import org.apache.nifi.history.History;
import org.apache.nifi.history.HistoryQuery;
import org.apache.nifi.history.PreviousValue;
import org.apache.nifi.remote.RootGroupPort;
import org.apache.nifi.reporting.Bulletin;
import org.apache.nifi.reporting.BulletinQuery;
import org.apache.nifi.reporting.BulletinRepository;
import org.apache.nifi.reporting.ComponentType;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.api.dto.AccessPolicyDTO;
import org.apache.nifi.web.api.dto.AccessPolicySummaryDTO;
import org.apache.nifi.web.api.dto.BulletinBoardDTO;
import org.apache.nifi.web.api.dto.BulletinDTO;
import org.apache.nifi.web.api.dto.BulletinQueryDTO;
import org.apache.nifi.web.api.dto.ClusterDTO;
import org.apache.nifi.web.api.dto.ComponentDTO;
import org.apache.nifi.web.api.dto.ComponentHistoryDTO;
import org.apache.nifi.web.api.dto.ComponentReferenceDTO;
import org.apache.nifi.web.api.dto.ComponentStateDTO;
import org.apache.nifi.web.api.dto.ConnectionDTO;
import org.apache.nifi.web.api.dto.ControllerConfigurationDTO;
import org.apache.nifi.web.api.dto.ControllerDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.ControllerServiceReferencingComponentDTO;
import org.apache.nifi.web.api.dto.CounterDTO;
import org.apache.nifi.web.api.dto.CountersDTO;
import org.apache.nifi.web.api.dto.CountersSnapshotDTO;
import org.apache.nifi.web.api.dto.DocumentedTypeDTO;
import org.apache.nifi.web.api.dto.DropRequestDTO;
import org.apache.nifi.web.api.dto.DtoFactory;
import org.apache.nifi.web.api.dto.EntityFactory;
import org.apache.nifi.web.api.dto.FlowConfigurationDTO;
import org.apache.nifi.web.api.dto.FlowFileDTO;
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
import org.apache.nifi.web.api.dto.FunnelDTO;
import org.apache.nifi.web.api.dto.LabelDTO;
import org.apache.nifi.web.api.dto.ListingRequestDTO;
import org.apache.nifi.web.api.dto.NodeDTO;
import org.apache.nifi.web.api.dto.PermissionsDTO;
import org.apache.nifi.web.api.dto.PortDTO;
import org.apache.nifi.web.api.dto.PreviousValueDTO;
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.PropertyHistoryDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO;
import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
import org.apache.nifi.web.api.dto.ResourceDTO;
import org.apache.nifi.web.api.dto.RevisionDTO;
import org.apache.nifi.web.api.dto.SnippetDTO;
import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
import org.apache.nifi.web.api.dto.UserDTO;
import org.apache.nifi.web.api.dto.UserGroupDTO;
import org.apache.nifi.web.api.dto.action.HistoryDTO;
import org.apache.nifi.web.api.dto.action.HistoryQueryDTO;
import org.apache.nifi.web.api.dto.flow.FlowDTO;
import org.apache.nifi.web.api.dto.provenance.ProvenanceDTO;
import org.apache.nifi.web.api.dto.provenance.ProvenanceEventDTO;
import org.apache.nifi.web.api.dto.provenance.ProvenanceOptionsDTO;
import org.apache.nifi.web.api.dto.provenance.lineage.LineageDTO;
import org.apache.nifi.web.api.dto.search.SearchResultsDTO;
import org.apache.nifi.web.api.dto.status.ConnectionStatusDTO;
import org.apache.nifi.web.api.dto.status.ControllerStatusDTO;
import org.apache.nifi.web.api.dto.status.NodeProcessGroupStatusSnapshotDTO;
import org.apache.nifi.web.api.dto.status.PortStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.ProcessGroupStatusSnapshotDTO;
import org.apache.nifi.web.api.dto.status.ProcessorStatusDTO;
import org.apache.nifi.web.api.dto.status.RemoteProcessGroupStatusDTO;
import org.apache.nifi.web.api.dto.status.StatusHistoryDTO;
import org.apache.nifi.web.api.entity.AccessPolicyEntity;
import org.apache.nifi.web.api.entity.AccessPolicySummaryEntity;
import org.apache.nifi.web.api.entity.ActionEntity;
import org.apache.nifi.web.api.entity.BulletinEntity;
import org.apache.nifi.web.api.entity.ComponentReferenceEntity;
import org.apache.nifi.web.api.entity.ConnectionEntity;
import org.apache.nifi.web.api.entity.ConnectionStatusEntity;
import org.apache.nifi.web.api.entity.ControllerBulletinsEntity;
import org.apache.nifi.web.api.entity.ControllerConfigurationEntity;
import org.apache.nifi.web.api.entity.ControllerServiceEntity;
import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentEntity;
import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentsEntity;
import org.apache.nifi.web.api.entity.CurrentUserEntity;
import org.apache.nifi.web.api.entity.FlowConfigurationEntity;
import org.apache.nifi.web.api.entity.FlowEntity;
import org.apache.nifi.web.api.entity.FunnelEntity;
import org.apache.nifi.web.api.entity.LabelEntity;
import org.apache.nifi.web.api.entity.PortEntity;
import org.apache.nifi.web.api.entity.PortStatusEntity;
import org.apache.nifi.web.api.entity.ProcessGroupEntity;
import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
import org.apache.nifi.web.api.entity.ProcessGroupStatusEntity;
import org.apache.nifi.web.api.entity.ProcessGroupStatusSnapshotEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
import org.apache.nifi.web.api.entity.ProcessorStatusEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupPortEntity;
import org.apache.nifi.web.api.entity.RemoteProcessGroupStatusEntity;
import org.apache.nifi.web.api.entity.ReportingTaskEntity;
import org.apache.nifi.web.api.entity.ScheduleComponentsEntity;
import org.apache.nifi.web.api.entity.SnippetEntity;
import org.apache.nifi.web.api.entity.StatusHistoryEntity;
import org.apache.nifi.web.api.entity.TemplateEntity;
import org.apache.nifi.web.api.entity.TenantEntity;
import org.apache.nifi.web.api.entity.UserEntity;
import org.apache.nifi.web.api.entity.UserGroupEntity;
import org.apache.nifi.web.controller.ControllerFacade;
import org.apache.nifi.web.dao.AccessPolicyDAO;
import org.apache.nifi.web.dao.ConnectionDAO;
import org.apache.nifi.web.dao.ControllerServiceDAO;
import org.apache.nifi.web.dao.FunnelDAO;
import org.apache.nifi.web.dao.LabelDAO;
import org.apache.nifi.web.dao.PortDAO;
import org.apache.nifi.web.dao.ProcessGroupDAO;
import org.apache.nifi.web.dao.ProcessorDAO;
import org.apache.nifi.web.dao.RemoteProcessGroupDAO;
import org.apache.nifi.web.dao.ReportingTaskDAO;
import org.apache.nifi.web.dao.SnippetDAO;
import org.apache.nifi.web.dao.TemplateDAO;
import org.apache.nifi.web.dao.UserDAO;
import org.apache.nifi.web.dao.UserGroupDAO;
import org.apache.nifi.web.revision.DeleteRevisionTask;
import org.apache.nifi.web.revision.ExpiredRevisionClaimException;
import org.apache.nifi.web.revision.RevisionClaim;
import org.apache.nifi.web.revision.RevisionManager;
import org.apache.nifi.web.revision.RevisionUpdate;
import org.apache.nifi.web.revision.StandardRevisionClaim;
import org.apache.nifi.web.revision.StandardRevisionUpdate;
import org.apache.nifi.web.revision.UpdateRevisionTask;
import org.apache.nifi.web.util.SnippetUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* Implementation of NiFiServiceFacade that performs revision checking.
*/
public class StandardNiFiServiceFacade implements NiFiServiceFacade {
private static final Logger logger = LoggerFactory.getLogger(StandardNiFiServiceFacade.class);
// nifi core components
private ControllerFacade controllerFacade;
private SnippetUtils snippetUtils;
// revision manager
private RevisionManager revisionManager;
private BulletinRepository bulletinRepository;
// data access objects
private ProcessorDAO processorDAO;
private ProcessGroupDAO processGroupDAO;
private RemoteProcessGroupDAO remoteProcessGroupDAO;
private LabelDAO labelDAO;
private FunnelDAO funnelDAO;
private SnippetDAO snippetDAO;
private PortDAO inputPortDAO;
private PortDAO outputPortDAO;
private ConnectionDAO connectionDAO;
private ControllerServiceDAO controllerServiceDAO;
private ReportingTaskDAO reportingTaskDAO;
private TemplateDAO templateDAO;
private UserDAO userDAO;
private UserGroupDAO userGroupDAO;
private AccessPolicyDAO accessPolicyDAO;
private ClusterCoordinator clusterCoordinator;
private HeartbeatMonitor heartbeatMonitor;
private LeaderElectionManager leaderElectionManager;
// administrative services
private AuditService auditService;
// properties
private NiFiProperties properties;
private DtoFactory dtoFactory;
private EntityFactory entityFactory;
private Authorizer authorizer;
private AuthorizableLookup authorizableLookup;
// -----------------------------------------
// Synchronization methods
// -----------------------------------------
@Override
public void authorizeAccess(final AuthorizeAccess authorizeAccess) {
authorizeAccess.authorize(authorizableLookup);
}
@Override
public void verifyRevision(final Revision revision, final NiFiUser user) {
final Revision curRevision = revisionManager.getRevision(revision.getComponentId());
if (revision.equals(curRevision)) {
return;
}
throw new InvalidRevisionException(revision + " is not the most up-to-date revision. This component appears to have been modified");
}
@Override
public void verifyRevisions(final Set<Revision> revisions, final NiFiUser user) {
for (final Revision revision : revisions) {
verifyRevision(revision, user);
}
}
@Override
public Set<Revision> getRevisionsFromGroup(final String groupId, final Function<ProcessGroup, Set<String>> getComponents) {
final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
final Set<String> componentIds = getComponents.apply(group);
return componentIds.stream().map(id -> revisionManager.getRevision(id)).collect(Collectors.toSet());
}
@Override
public Set<Revision> getRevisionsFromSnippet(final String snippetId) {
final Snippet snippet = snippetDAO.getSnippet(snippetId);
final Set<String> componentIds = new HashSet<>();
componentIds.addAll(snippet.getProcessors().keySet());
componentIds.addAll(snippet.getFunnels().keySet());
componentIds.addAll(snippet.getLabels().keySet());
componentIds.addAll(snippet.getConnections().keySet());
componentIds.addAll(snippet.getInputPorts().keySet());
componentIds.addAll(snippet.getOutputPorts().keySet());
componentIds.addAll(snippet.getProcessGroups().keySet());
componentIds.addAll(snippet.getRemoteProcessGroups().keySet());
return componentIds.stream().map(id -> revisionManager.getRevision(id)).collect(Collectors.toSet());
}
// -----------------------------------------
// Verification Operations
// -----------------------------------------
@Override
public void verifyListQueue(final String connectionId) {
connectionDAO.verifyList(connectionId);
}
@Override
public void verifyCreateConnection(final String groupId, final ConnectionDTO connectionDTO) {
connectionDAO.verifyCreate(groupId, connectionDTO);
}
@Override
public void verifyUpdateConnection(final ConnectionDTO connectionDTO) {
// if connection does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (connectionDAO.hasConnection(connectionDTO.getId())) {
connectionDAO.verifyUpdate(connectionDTO);
} else {
connectionDAO.verifyCreate(connectionDTO.getParentGroupId(), connectionDTO);
}
}
@Override
public void verifyDeleteConnection(final String connectionId) {
connectionDAO.verifyDelete(connectionId);
}
@Override
public void verifyDeleteFunnel(final String funnelId) {
funnelDAO.verifyDelete(funnelId);
}
@Override
public void verifyUpdateInputPort(final PortDTO inputPortDTO) {
// if connection does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (inputPortDAO.hasPort(inputPortDTO.getId())) {
inputPortDAO.verifyUpdate(inputPortDTO);
}
}
@Override
public void verifyDeleteInputPort(final String inputPortId) {
inputPortDAO.verifyDelete(inputPortId);
}
@Override
public void verifyUpdateOutputPort(final PortDTO outputPortDTO) {
// if connection does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (outputPortDAO.hasPort(outputPortDTO.getId())) {
outputPortDAO.verifyUpdate(outputPortDTO);
}
}
@Override
public void verifyDeleteOutputPort(final String outputPortId) {
outputPortDAO.verifyDelete(outputPortId);
}
@Override
public void verifyCreateProcessor(ProcessorDTO processorDTO) {
processorDAO.verifyCreate(processorDTO);
}
@Override
public void verifyUpdateProcessor(final ProcessorDTO processorDTO) {
// if group does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (processorDAO.hasProcessor(processorDTO.getId())) {
processorDAO.verifyUpdate(processorDTO);
} else {
verifyCreateProcessor(processorDTO);
}
}
@Override
public void verifyDeleteProcessor(final String processorId) {
processorDAO.verifyDelete(processorId);
}
@Override
public void verifyScheduleComponents(final String groupId, final ScheduledState state, final Set<String> componentIds) {
processGroupDAO.verifyScheduleComponents(groupId, state, componentIds);
}
@Override
public void verifyDeleteProcessGroup(final String groupId) {
processGroupDAO.verifyDelete(groupId);
}
@Override
public void verifyUpdateRemoteProcessGroup(final RemoteProcessGroupDTO remoteProcessGroupDTO) {
// if remote group does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (remoteProcessGroupDAO.hasRemoteProcessGroup(remoteProcessGroupDTO.getId())) {
remoteProcessGroupDAO.verifyUpdate(remoteProcessGroupDTO);
}
}
@Override
public void verifyUpdateRemoteProcessGroupInputPort(final String remoteProcessGroupId, final RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) {
remoteProcessGroupDAO.verifyUpdateInputPort(remoteProcessGroupId, remoteProcessGroupPortDTO);
}
@Override
public void verifyUpdateRemoteProcessGroupOutputPort(final String remoteProcessGroupId, final RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) {
remoteProcessGroupDAO.verifyUpdateOutputPort(remoteProcessGroupId, remoteProcessGroupPortDTO);
}
@Override
public void verifyDeleteRemoteProcessGroup(final String remoteProcessGroupId) {
remoteProcessGroupDAO.verifyDelete(remoteProcessGroupId);
}
@Override
public void verifyCreateControllerService(ControllerServiceDTO controllerServiceDTO) {
controllerServiceDAO.verifyCreate(controllerServiceDTO);
}
@Override
public void verifyUpdateControllerService(final ControllerServiceDTO controllerServiceDTO) {
// if service does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (controllerServiceDAO.hasControllerService(controllerServiceDTO.getId())) {
controllerServiceDAO.verifyUpdate(controllerServiceDTO);
} else {
verifyCreateControllerService(controllerServiceDTO);
}
}
@Override
public void verifyUpdateControllerServiceReferencingComponents(final String controllerServiceId, final ScheduledState scheduledState, final ControllerServiceState controllerServiceState) {
controllerServiceDAO.verifyUpdateReferencingComponents(controllerServiceId, scheduledState, controllerServiceState);
}
@Override
public void verifyDeleteControllerService(final String controllerServiceId) {
controllerServiceDAO.verifyDelete(controllerServiceId);
}
@Override
public void verifyCreateReportingTask(ReportingTaskDTO reportingTaskDTO) {
reportingTaskDAO.verifyCreate(reportingTaskDTO);
}
@Override
public void verifyUpdateReportingTask(final ReportingTaskDTO reportingTaskDTO) {
// if tasks does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (reportingTaskDAO.hasReportingTask(reportingTaskDTO.getId())) {
reportingTaskDAO.verifyUpdate(reportingTaskDTO);
} else {
verifyCreateReportingTask(reportingTaskDTO);
}
}
@Override
public void verifyDeleteReportingTask(final String reportingTaskId) {
reportingTaskDAO.verifyDelete(reportingTaskId);
}
// -----------------------------------------
// Write Operations
// -----------------------------------------
@Override
public AccessPolicyEntity updateAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) {
final Authorizable authorizable = authorizableLookup.getAccessPolicyById(accessPolicyDTO.getId());
final RevisionUpdate<AccessPolicyDTO> snapshot = updateComponent(revision,
authorizable,
() -> accessPolicyDAO.updateAccessPolicy(accessPolicyDTO),
accessPolicy -> {
final Set<TenantEntity> users = accessPolicy.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet());
final Set<TenantEntity> userGroups = accessPolicy.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
final ComponentReferenceEntity componentReference = createComponentReferenceEntity(accessPolicy.getResource());
return dtoFactory.createAccessPolicyDto(accessPolicy, userGroups, users, componentReference);
});
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizable);
return entityFactory.createAccessPolicyEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
@Override
public UserEntity updateUser(final Revision revision, final UserDTO userDTO) {
final Authorizable usersAuthorizable = authorizableLookup.getTenant();
final Set<Group> groups = userGroupDAO.getUserGroupsForUser(userDTO.getId());
final Set<AccessPolicy> policies = userGroupDAO.getAccessPoliciesForUser(userDTO.getId());
final RevisionUpdate<UserDTO> snapshot = updateComponent(revision,
usersAuthorizable,
() -> userDAO.updateUser(userDTO),
user -> {
final Set<TenantEntity> tenantEntities = groups.stream().map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
final Set<AccessPolicySummaryEntity> policyEntities = policies.stream().map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
return dtoFactory.createUserDto(user, tenantEntities, policyEntities);
});
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(usersAuthorizable);
return entityFactory.createUserEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
@Override
public UserGroupEntity updateUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) {
final Authorizable userGroupsAuthorizable = authorizableLookup.getTenant();
final Set<AccessPolicy> policies = userGroupDAO.getAccessPoliciesForUserGroup(userGroupDTO.getId());
final RevisionUpdate<UserGroupDTO> snapshot = updateComponent(revision,
userGroupsAuthorizable,
() -> userGroupDAO.updateUserGroup(userGroupDTO),
userGroup -> {
final Set<TenantEntity> tenantEntities = userGroup.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet());
final Set<AccessPolicySummaryEntity> policyEntities = policies.stream().map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
return dtoFactory.createUserGroupDto(userGroup, tenantEntities, policyEntities);
}
);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(userGroupsAuthorizable);
return entityFactory.createUserGroupEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
@Override
public ConnectionEntity updateConnection(final Revision revision, final ConnectionDTO connectionDTO) {
final Connection connectionNode = connectionDAO.getConnection(connectionDTO.getId());
final RevisionUpdate<ConnectionDTO> snapshot = updateComponent(
revision,
connectionNode,
() -> connectionDAO.updateConnection(connectionDTO),
connection -> dtoFactory.createConnectionDto(connection));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(connectionNode);
final ConnectionStatusDTO status = dtoFactory.createConnectionStatusDto(controllerFacade.getConnectionStatus(connectionNode.getIdentifier()));
return entityFactory.createConnectionEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status);
}
@Override
public ProcessorEntity updateProcessor(final Revision revision, final ProcessorDTO processorDTO) {
// get the component, ensure we have access to it, and perform the update request
final ProcessorNode processorNode = processorDAO.getProcessor(processorDTO.getId());
final RevisionUpdate<ProcessorDTO> snapshot = updateComponent(revision,
processorNode,
() -> processorDAO.updateProcessor(processorDTO),
proc -> dtoFactory.createProcessorDto(proc));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processorNode);
final ProcessorStatusDTO status = dtoFactory.createProcessorStatusDto(controllerFacade.getProcessorStatus(processorNode.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processorNode.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createProcessorEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public LabelEntity updateLabel(final Revision revision, final LabelDTO labelDTO) {
final Label labelNode = labelDAO.getLabel(labelDTO.getId());
final RevisionUpdate<LabelDTO> snapshot = updateComponent(revision,
labelNode,
() -> labelDAO.updateLabel(labelDTO),
label -> dtoFactory.createLabelDto(label));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(labelNode);
return entityFactory.createLabelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
@Override
public FunnelEntity updateFunnel(final Revision revision, final FunnelDTO funnelDTO) {
final Funnel funnelNode = funnelDAO.getFunnel(funnelDTO.getId());
final RevisionUpdate<FunnelDTO> snapshot = updateComponent(revision,
funnelNode,
() -> funnelDAO.updateFunnel(funnelDTO),
funnel -> dtoFactory.createFunnelDto(funnel));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(funnelNode);
return entityFactory.createFunnelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
/**
* Updates a component with the given revision, using the provided supplier to call
* into the appropriate DAO and the provided function to convert the component into a DTO.
*
* @param revision the current revision
* @param daoUpdate a Supplier that will update the component via the appropriate DAO
* @param dtoCreation a Function to convert a component into a dao
* @param <D> the DTO Type of the updated component
* @param <C> the Component Type of the updated component
* @return A RevisionUpdate that represents the new configuration
*/
private <D, C> RevisionUpdate<D> updateComponent(final Revision revision, final Authorizable authorizable, final Supplier<C> daoUpdate, final Function<C, D> dtoCreation) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
try {
final RevisionUpdate<D> updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(revision), user, new UpdateRevisionTask<D>() {
@Override
public RevisionUpdate<D> update() {
// get the updated component
final C component = daoUpdate.get();
// save updated controller
controllerFacade.save();
final D dto = dtoCreation.apply(component);
final Revision updatedRevision = revisionManager.getRevision(revision.getComponentId()).incrementRevision(revision.getClientId());
final FlowModification lastModification = new FlowModification(updatedRevision, user.getIdentity());
return new StandardRevisionUpdate<>(dto, lastModification);
}
});
return updatedComponent;
} catch (final ExpiredRevisionClaimException erce) {
throw new InvalidRevisionException("Failed to update component " + authorizable, erce);
}
}
@Override
public void verifyUpdateSnippet(final SnippetDTO snippetDto, final Set<String> affectedComponentIds) {
// if snippet does not exist, then the update request is likely creating it
// so we don't verify since it will fail
if (snippetDAO.hasSnippet(snippetDto.getId())) {
snippetDAO.verifyUpdateSnippetComponent(snippetDto);
}
}
@Override
public SnippetEntity updateSnippet(final Set<Revision> revisions, final SnippetDTO snippetDto) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final RevisionClaim revisionClaim = new StandardRevisionClaim(revisions);
final RevisionUpdate<SnippetDTO> snapshot;
try {
snapshot = revisionManager.updateRevision(revisionClaim, user, new UpdateRevisionTask<SnippetDTO>() {
@Override
public RevisionUpdate<SnippetDTO> update() {
// get the updated component
final Snippet snippet = snippetDAO.updateSnippetComponents(snippetDto);
// drop the snippet
snippetDAO.dropSnippet(snippet.getId());
// save updated controller
controllerFacade.save();
// increment the revisions
final Set<Revision> updatedRevisions = revisions.stream().map(revision -> {
final Revision currentRevision = revisionManager.getRevision(revision.getComponentId());
return currentRevision.incrementRevision(revision.getClientId());
}).collect(Collectors.toSet());
final SnippetDTO dto = dtoFactory.createSnippetDto(snippet);
return new StandardRevisionUpdate<>(dto, null, updatedRevisions);
}
});
} catch (final ExpiredRevisionClaimException e) {
throw new InvalidRevisionException("Failed to update Snippet", e);
}
return entityFactory.createSnippetEntity(snapshot.getComponent());
}
@Override
public PortEntity updateInputPort(final Revision revision, final PortDTO inputPortDTO) {
final Port inputPortNode = inputPortDAO.getPort(inputPortDTO.getId());
final RevisionUpdate<PortDTO> snapshot = updateComponent(revision,
inputPortNode,
() -> inputPortDAO.updatePort(inputPortDTO),
port -> dtoFactory.createPortDto(port));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(inputPortNode);
final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getInputPortStatus(inputPortNode.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(inputPortNode.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public PortEntity updateOutputPort(final Revision revision, final PortDTO outputPortDTO) {
final Port outputPortNode = outputPortDAO.getPort(outputPortDTO.getId());
final RevisionUpdate<PortDTO> snapshot = updateComponent(revision,
outputPortNode,
() -> outputPortDAO.updatePort(outputPortDTO),
port -> dtoFactory.createPortDto(port));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(outputPortNode);
final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getOutputPortStatus(outputPortNode.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(outputPortNode.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public RemoteProcessGroupEntity updateRemoteProcessGroup(final Revision revision, final RemoteProcessGroupDTO remoteProcessGroupDTO) {
final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId());
final RevisionUpdate<RemoteProcessGroupDTO> snapshot = updateComponent(
revision,
remoteProcessGroupNode,
() -> remoteProcessGroupDAO.updateRemoteProcessGroup(remoteProcessGroupDTO),
remoteProcessGroup -> dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroupNode);
final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification());
final RemoteProcessGroupStatusDTO status = dtoFactory.createRemoteProcessGroupStatusDto(controllerFacade.getRemoteProcessGroupStatus(remoteProcessGroupNode.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(remoteProcessGroupNode.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createRemoteProcessGroupEntity(snapshot.getComponent(), updateRevision, permissions, status, bulletinEntities);
}
@Override
public RemoteProcessGroupPortEntity updateRemoteProcessGroupInputPort(
final Revision revision, final String remoteProcessGroupId, final RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) {
final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupPortDTO.getGroupId());
final RevisionUpdate<RemoteProcessGroupPortDTO> snapshot = updateComponent(
revision,
remoteProcessGroupNode,
() -> remoteProcessGroupDAO.updateRemoteProcessGroupInputPort(remoteProcessGroupId, remoteProcessGroupPortDTO),
remoteGroupPort -> dtoFactory.createRemoteProcessGroupPortDto(remoteGroupPort));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroupNode);
final RevisionDTO updatedRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification());
return entityFactory.createRemoteProcessGroupPortEntity(snapshot.getComponent(), updatedRevision, permissions);
}
@Override
public RemoteProcessGroupPortEntity updateRemoteProcessGroupOutputPort(
final Revision revision, final String remoteProcessGroupId, final RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) {
final RemoteProcessGroup remoteProcessGroupNode = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupPortDTO.getGroupId());
final RevisionUpdate<RemoteProcessGroupPortDTO> snapshot = updateComponent(
revision,
remoteProcessGroupNode,
() -> remoteProcessGroupDAO.updateRemoteProcessGroupOutputPort(remoteProcessGroupId, remoteProcessGroupPortDTO),
remoteGroupPort -> dtoFactory.createRemoteProcessGroupPortDto(remoteGroupPort));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroupNode);
final RevisionDTO updatedRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification());
return entityFactory.createRemoteProcessGroupPortEntity(snapshot.getComponent(), updatedRevision, permissions);
}
@Override
public ProcessGroupEntity updateProcessGroup(final Revision revision, final ProcessGroupDTO processGroupDTO) {
final ProcessGroup processGroupNode = processGroupDAO.getProcessGroup(processGroupDTO.getId());
final RevisionUpdate<ProcessGroupDTO> snapshot = updateComponent(revision,
processGroupNode,
() -> processGroupDAO.updateProcessGroup(processGroupDTO),
processGroup -> dtoFactory.createProcessGroupDto(processGroup));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroupNode);
final RevisionDTO updatedRevision = dtoFactory.createRevisionDTO(snapshot.getLastModification());
final ProcessGroupStatusDTO status = dtoFactory.createConciseProcessGroupStatusDto(controllerFacade.getProcessGroupStatus(processGroupNode.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processGroupNode.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createProcessGroupEntity(snapshot.getComponent(), updatedRevision, permissions, status, bulletinEntities);
}
@Override
public ScheduleComponentsEntity scheduleComponents(final String processGroupId, final ScheduledState state, final Map<String, Revision> componentRevisions) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final RevisionUpdate<ScheduleComponentsEntity> updatedComponent = revisionManager.updateRevision(new StandardRevisionClaim(componentRevisions.values()), user, new
UpdateRevisionTask<ScheduleComponentsEntity>() {
@Override
public RevisionUpdate<ScheduleComponentsEntity> update() {
// schedule the components
processGroupDAO.scheduleComponents(processGroupId, state, componentRevisions.keySet());
// update the revisions
final Map<String, Revision> updatedRevisions = new HashMap<>();
for (final Revision revision : componentRevisions.values()) {
final Revision currentRevision = revisionManager.getRevision(revision.getComponentId());
updatedRevisions.put(revision.getComponentId(), currentRevision.incrementRevision(revision.getClientId()));
}
// save
controllerFacade.save();
// gather details for response
final ScheduleComponentsEntity entity = new ScheduleComponentsEntity();
entity.setId(processGroupId);
entity.setState(state.name());
return new StandardRevisionUpdate<>(entity, null, new HashSet<>(updatedRevisions.values()));
}
});
return updatedComponent.getComponent();
}
@Override
public ControllerConfigurationEntity updateControllerConfiguration(final Revision revision, final ControllerConfigurationDTO controllerConfigurationDTO) {
final RevisionUpdate<ControllerConfigurationDTO> updatedComponent = updateComponent(
revision,
controllerFacade,
() -> {
if (controllerConfigurationDTO.getMaxTimerDrivenThreadCount() != null) {
controllerFacade.setMaxTimerDrivenThreadCount(controllerConfigurationDTO.getMaxTimerDrivenThreadCount());
}
if (controllerConfigurationDTO.getMaxEventDrivenThreadCount() != null) {
controllerFacade.setMaxEventDrivenThreadCount(controllerConfigurationDTO.getMaxEventDrivenThreadCount());
}
return controllerConfigurationDTO;
},
controller -> dtoFactory.createControllerConfigurationDto(controllerFacade));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(controllerFacade);
final RevisionDTO updateRevision = dtoFactory.createRevisionDTO(updatedComponent.getLastModification());
return entityFactory.createControllerConfigurationEntity(updatedComponent.getComponent(), updateRevision, permissions);
}
@Override
public NodeDTO updateNode(final NodeDTO nodeDTO) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
if (user == null) {
throw new WebApplicationException(new Throwable("Unable to access details for current user."));
}
final String userDn = user.getIdentity();
final NodeIdentifier nodeId = clusterCoordinator.getNodeIdentifier(nodeDTO.getNodeId());
if (nodeId == null) {
throw new UnknownNodeException("No node exists with ID " + nodeDTO.getNodeId());
}
if (NodeConnectionState.CONNECTING.name().equalsIgnoreCase(nodeDTO.getStatus())) {
clusterCoordinator.requestNodeConnect(nodeId, userDn);
} else if (NodeConnectionState.DISCONNECTING.name().equalsIgnoreCase(nodeDTO.getStatus())) {
clusterCoordinator.requestNodeDisconnect(nodeId, DisconnectionCode.USER_DISCONNECTED,
"User " + userDn + " requested that node be disconnected from cluster");
}
return getNode(nodeId);
}
@Override
public CounterDTO updateCounter(final String counterId) {
return dtoFactory.createCounterDto(controllerFacade.resetCounter(counterId));
}
@Override
public void verifyCanClearProcessorState(final String processorId) {
processorDAO.verifyClearState(processorId);
}
@Override
public void clearProcessorState(final String processorId) {
processorDAO.clearState(processorId);
}
@Override
public void verifyCanClearControllerServiceState(final String controllerServiceId) {
controllerServiceDAO.verifyClearState(controllerServiceId);
}
@Override
public void clearControllerServiceState(final String controllerServiceId) {
controllerServiceDAO.clearState(controllerServiceId);
}
@Override
public void verifyCanClearReportingTaskState(final String reportingTaskId) {
reportingTaskDAO.verifyClearState(reportingTaskId);
}
@Override
public void clearReportingTaskState(final String reportingTaskId) {
reportingTaskDAO.clearState(reportingTaskId);
}
@Override
public ConnectionEntity deleteConnection(final Revision revision, final String connectionId) {
final Connection connection = connectionDAO.getConnection(connectionId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(connection);
final ConnectionDTO snapshot = deleteComponent(
revision,
connection.getResource(),
() -> connectionDAO.deleteConnection(connectionId),
false, // no policies to remove
dtoFactory.createConnectionDto(connection));
return entityFactory.createConnectionEntity(snapshot, null, permissions, null);
}
@Override
public DropRequestDTO deleteFlowFileDropRequest(final String connectionId, final String dropRequestId) {
return dtoFactory.createDropRequestDTO(connectionDAO.deleteFlowFileDropRequest(connectionId, dropRequestId));
}
@Override
public ListingRequestDTO deleteFlowFileListingRequest(final String connectionId, final String listingRequestId) {
final Connection connection = connectionDAO.getConnection(connectionId);
final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.deleteFlowFileListingRequest(connectionId, listingRequestId));
// include whether the source and destination are running
if (connection.getSource() != null) {
listRequest.setSourceRunning(connection.getSource().isRunning());
}
if (connection.getDestination() != null) {
listRequest.setDestinationRunning(connection.getDestination().isRunning());
}
return listRequest;
}
@Override
public ProcessorEntity deleteProcessor(final Revision revision, final String processorId) {
final ProcessorNode processor = processorDAO.getProcessor(processorId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processor);
final ProcessorDTO snapshot = deleteComponent(
revision,
processor.getResource(),
() -> processorDAO.deleteProcessor(processorId),
true,
dtoFactory.createProcessorDto(processor));
return entityFactory.createProcessorEntity(snapshot, null, permissions, null, null);
}
@Override
public LabelEntity deleteLabel(final Revision revision, final String labelId) {
final Label label = labelDAO.getLabel(labelId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(label);
final LabelDTO snapshot = deleteComponent(
revision,
label.getResource(),
() -> labelDAO.deleteLabel(labelId),
true,
dtoFactory.createLabelDto(label));
return entityFactory.createLabelEntity(snapshot, null, permissions);
}
@Override
public UserEntity deleteUser(final Revision revision, final String userId) {
final User user = userDAO.getUser(userId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getTenant());
final Set<TenantEntity> userGroups = user != null ? userGroupDAO.getUserGroupsForUser(userId).stream()
.map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()) : null;
final Set<AccessPolicySummaryEntity> policyEntities = user != null ? userGroupDAO.getAccessPoliciesForUser(userId).stream()
.map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet()) : null;
final String resourceIdentifier = ResourceFactory.getTenantResource().getIdentifier() + "/" + userId;
final UserDTO snapshot = deleteComponent(
revision,
new Resource() {
@Override
public String getIdentifier() {
return resourceIdentifier;
}
@Override
public String getName() {
return resourceIdentifier;
}
@Override
public String getSafeDescription() {
return "User " + userId;
}
},
() -> userDAO.deleteUser(userId),
false, // no user specific policies to remove
dtoFactory.createUserDto(user, userGroups, policyEntities));
return entityFactory.createUserEntity(snapshot, null, permissions);
}
@Override
public UserGroupEntity deleteUserGroup(final Revision revision, final String userGroupId) {
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getTenant());
final Set<TenantEntity> users = userGroup != null ? userGroup.getUsers().stream()
.map(mapUserIdToTenantEntity()).collect(Collectors.toSet()) : null;
final Set<AccessPolicySummaryEntity> policyEntities = userGroupDAO.getAccessPoliciesForUserGroup(userGroup.getIdentifier()).stream()
.map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
final String resourceIdentifier = ResourceFactory.getTenantResource().getIdentifier() + "/" + userGroupId;
final UserGroupDTO snapshot = deleteComponent(
revision,
new Resource() {
@Override
public String getIdentifier() {
return resourceIdentifier;
}
@Override
public String getName() {
return resourceIdentifier;
}
@Override
public String getSafeDescription() {
return "User Group " + userGroupId;
}
},
() -> userGroupDAO.deleteUserGroup(userGroupId),
false, // no user group specific policies to remove
dtoFactory.createUserGroupDto(userGroup, users, policyEntities));
return entityFactory.createUserGroupEntity(snapshot, null, permissions);
}
@Override
public AccessPolicyEntity deleteAccessPolicy(final Revision revision, final String accessPolicyId) {
final AccessPolicy accessPolicy = accessPolicyDAO.getAccessPolicy(accessPolicyId);
final ComponentReferenceEntity componentReference = createComponentReferenceEntity(accessPolicy.getResource());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getAccessPolicyById(accessPolicyId));
final Set<TenantEntity> userGroups = accessPolicy != null ? accessPolicy.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()) : null;
final Set<TenantEntity> users = accessPolicy != null ? accessPolicy.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet()) : null;
final AccessPolicyDTO snapshot = deleteComponent(
revision,
new Resource() {
@Override
public String getIdentifier() {
return accessPolicy.getResource();
}
@Override
public String getName() {
return accessPolicy.getResource();
}
@Override
public String getSafeDescription() {
return "Policy " + accessPolicyId;
}
},
() -> accessPolicyDAO.deleteAccessPolicy(accessPolicyId),
false, // no need to clean up any policies as it's already been removed above
dtoFactory.createAccessPolicyDto(accessPolicy, userGroups, users, componentReference));
return entityFactory.createAccessPolicyEntity(snapshot, null, permissions);
}
@Override
public FunnelEntity deleteFunnel(final Revision revision, final String funnelId) {
final Funnel funnel = funnelDAO.getFunnel(funnelId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(funnel);
final FunnelDTO snapshot = deleteComponent(
revision,
funnel.getResource(),
() -> funnelDAO.deleteFunnel(funnelId),
true,
dtoFactory.createFunnelDto(funnel));
return entityFactory.createFunnelEntity(snapshot, null, permissions);
}
/**
* Deletes a component using the Optimistic Locking Manager
*
* @param revision the current revision
* @param resource the resource being removed
* @param deleteAction the action that deletes the component via the appropriate DAO object
* @param cleanUpPolicies whether or not the policies for this resource should be removed as well - not necessary when there are
* no component specific policies or if the policies of the component are inherited
* @return a dto that represents the new configuration
*/
private <D, C> D deleteComponent(final Revision revision, final Resource resource, final Runnable deleteAction, final boolean cleanUpPolicies, final D dto) {
final RevisionClaim claim = new StandardRevisionClaim(revision);
final NiFiUser user = NiFiUserUtils.getNiFiUser();
return revisionManager.deleteRevision(claim, user, new DeleteRevisionTask<D>() {
@Override
public D performTask() {
logger.debug("Attempting to delete component {} with claim {}", resource.getIdentifier(), claim);
// run the delete action
deleteAction.run();
// save the flow
controllerFacade.save();
logger.debug("Deletion of component {} was successful", resource.getIdentifier());
if (cleanUpPolicies) {
cleanUpPolicies(resource);
}
return dto;
}
});
}
/**
* Clean up the policies for the specified component resource.
*
* @param componentResource the resource for the component
*/
private void cleanUpPolicies(final Resource componentResource) {
// ensure the authorizer supports configuration
if (accessPolicyDAO.supportsConfigurableAuthorizer()) {
final List<Resource> resources = new ArrayList<>();
resources.add(componentResource);
resources.add(ResourceFactory.getDataResource(componentResource));
resources.add(ResourceFactory.getDataTransferResource(componentResource));
resources.add(ResourceFactory.getPolicyResource(componentResource));
for (final Resource resource : resources) {
for (final RequestAction action : RequestAction.values()) {
try {
// since the component is being deleted, also delete any relevant access policies
final AccessPolicy readPolicy = accessPolicyDAO.getAccessPolicy(action, resource.getIdentifier());
if (readPolicy != null) {
accessPolicyDAO.deleteAccessPolicy(readPolicy.getIdentifier());
}
} catch (final Exception e) {
logger.warn(String.format("Unable to remove access policy for %s %s after component removal.", action, resource.getIdentifier()), e);
}
}
}
}
}
@Override
public void verifyDeleteSnippet(final String snippetId, final Set<String> affectedComponentIds) {
snippetDAO.verifyDeleteSnippetComponents(snippetId);
}
@Override
public SnippetEntity deleteSnippet(final Set<Revision> revisions, final String snippetId) {
final Snippet snippet = snippetDAO.getSnippet(snippetId);
// grab the resources in the snippet so we can delete the policies afterwards
final Set<Resource> snippetResources = new HashSet<>();
snippet.getProcessors().keySet().forEach(id -> snippetResources.add(processorDAO.getProcessor(id).getResource()));
snippet.getInputPorts().keySet().forEach(id -> snippetResources.add(inputPortDAO.getPort(id).getResource()));
snippet.getOutputPorts().keySet().forEach(id -> snippetResources.add(outputPortDAO.getPort(id).getResource()));
snippet.getFunnels().keySet().forEach(id -> snippetResources.add(funnelDAO.getFunnel(id).getResource()));
snippet.getLabels().keySet().forEach(id -> snippetResources.add(labelDAO.getLabel(id).getResource()));
snippet.getRemoteProcessGroups().keySet().forEach(id -> snippetResources.add(remoteProcessGroupDAO.getRemoteProcessGroup(id).getResource()));
snippet.getProcessGroups().keySet().forEach(id -> {
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(id);
// add the process group
snippetResources.add(processGroup.getResource());
// add each encapsulated component
processGroup.findAllProcessors().forEach(processor -> snippetResources.add(processor.getResource()));
processGroup.findAllInputPorts().forEach(inputPort -> snippetResources.add(inputPort.getResource()));
processGroup.findAllOutputPorts().forEach(outputPort -> snippetResources.add(outputPort.getResource()));
processGroup.findAllFunnels().forEach(funnel -> snippetResources.add(funnel.getResource()));
processGroup.findAllLabels().forEach(label -> snippetResources.add(label.getResource()));
processGroup.findAllProcessGroups().forEach(childGroup -> snippetResources.add(childGroup.getResource()));
processGroup.findAllRemoteProcessGroups().forEach(remoteProcessGroup -> snippetResources.add(remoteProcessGroup.getResource()));
processGroup.findAllTemplates().forEach(template -> snippetResources.add(template.getResource()));
processGroup.findAllControllerServices().forEach(controllerService -> snippetResources.add(controllerService.getResource()));
});
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final RevisionClaim claim = new StandardRevisionClaim(revisions);
final SnippetDTO dto = revisionManager.deleteRevision(claim, user, new DeleteRevisionTask<SnippetDTO>() {
@Override
public SnippetDTO performTask() {
// delete the components in the snippet
snippetDAO.deleteSnippetComponents(snippetId);
// drop the snippet
snippetDAO.dropSnippet(snippetId);
// save
controllerFacade.save();
// create the dto for the snippet that was just removed
return dtoFactory.createSnippetDto(snippet);
}
});
// clean up component policies
snippetResources.forEach(resource -> cleanUpPolicies(resource));
return entityFactory.createSnippetEntity(dto);
}
@Override
public PortEntity deleteInputPort(final Revision revision, final String inputPortId) {
final Port port = inputPortDAO.getPort(inputPortId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(port);
final PortDTO snapshot = deleteComponent(
revision,
port.getResource(),
() -> inputPortDAO.deletePort(inputPortId),
true,
dtoFactory.createPortDto(port));
return entityFactory.createPortEntity(snapshot, null, permissions, null, null);
}
@Override
public PortEntity deleteOutputPort(final Revision revision, final String outputPortId) {
final Port port = outputPortDAO.getPort(outputPortId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(port);
final PortDTO snapshot = deleteComponent(
revision,
port.getResource(),
() -> outputPortDAO.deletePort(outputPortId),
true,
dtoFactory.createPortDto(port));
return entityFactory.createPortEntity(snapshot, null, permissions, null, null);
}
@Override
public ProcessGroupEntity deleteProcessGroup(final Revision revision, final String groupId) {
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
// grab the resources in the snippet so we can delete the policies afterwards
final Set<Resource> groupResources = new HashSet<>();
processGroup.findAllProcessors().forEach(processor -> groupResources.add(processor.getResource()));
processGroup.findAllInputPorts().forEach(inputPort -> groupResources.add(inputPort.getResource()));
processGroup.findAllOutputPorts().forEach(outputPort -> groupResources.add(outputPort.getResource()));
processGroup.findAllFunnels().forEach(funnel -> groupResources.add(funnel.getResource()));
processGroup.findAllLabels().forEach(label -> groupResources.add(label.getResource()));
processGroup.findAllProcessGroups().forEach(childGroup -> groupResources.add(childGroup.getResource()));
processGroup.findAllRemoteProcessGroups().forEach(remoteProcessGroup -> groupResources.add(remoteProcessGroup.getResource()));
processGroup.findAllTemplates().forEach(template -> groupResources.add(template.getResource()));
processGroup.findAllControllerServices().forEach(controllerService -> groupResources.add(controllerService.getResource()));
final ProcessGroupDTO snapshot = deleteComponent(
revision,
processGroup.getResource(),
() -> processGroupDAO.deleteProcessGroup(groupId),
true,
dtoFactory.createProcessGroupDto(processGroup));
// delete all applicable component policies
groupResources.forEach(groupResource -> cleanUpPolicies(groupResource));
return entityFactory.createProcessGroupEntity(snapshot, null, permissions, null, null);
}
@Override
public RemoteProcessGroupEntity deleteRemoteProcessGroup(final Revision revision, final String remoteProcessGroupId) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroup);
final RemoteProcessGroupDTO snapshot = deleteComponent(
revision,
remoteProcessGroup.getResource(),
() -> remoteProcessGroupDAO.deleteRemoteProcessGroup(remoteProcessGroupId),
true,
dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup));
return entityFactory.createRemoteProcessGroupEntity(snapshot, null, permissions, null, null);
}
@Override
public void deleteTemplate(final String id) {
// delete the template and save the flow
templateDAO.deleteTemplate(id);
controllerFacade.save();
}
@Override
public ConnectionEntity createConnection(final Revision revision, final String groupId, final ConnectionDTO connectionDTO) {
final RevisionUpdate<ConnectionDTO> snapshot = createComponent(
revision,
connectionDTO,
() -> connectionDAO.createConnection(groupId, connectionDTO),
connection -> dtoFactory.createConnectionDto(connection));
final Connection connection = connectionDAO.getConnection(connectionDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(connection);
final ConnectionStatusDTO status = dtoFactory.createConnectionStatusDto(controllerFacade.getConnectionStatus(connectionDTO.getId()));
return entityFactory.createConnectionEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status);
}
@Override
public DropRequestDTO createFlowFileDropRequest(final String connectionId, final String dropRequestId) {
return dtoFactory.createDropRequestDTO(connectionDAO.createFlowFileDropRequest(connectionId, dropRequestId));
}
@Override
public ListingRequestDTO createFlowFileListingRequest(final String connectionId, final String listingRequestId) {
final Connection connection = connectionDAO.getConnection(connectionId);
final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.createFlowFileListingRequest(connectionId, listingRequestId));
// include whether the source and destination are running
if (connection.getSource() != null) {
listRequest.setSourceRunning(connection.getSource().isRunning());
}
if (connection.getDestination() != null) {
listRequest.setDestinationRunning(connection.getDestination().isRunning());
}
return listRequest;
}
@Override
public ProcessorEntity createProcessor(final Revision revision, final String groupId, final ProcessorDTO processorDTO) {
final RevisionUpdate<ProcessorDTO> snapshot = createComponent(
revision,
processorDTO,
() -> processorDAO.createProcessor(groupId, processorDTO),
processor -> dtoFactory.createProcessorDto(processor));
final ProcessorNode processor = processorDAO.getProcessor(processorDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processor);
final ProcessorStatusDTO status = dtoFactory.createProcessorStatusDto(controllerFacade.getProcessorStatus(processorDTO.getId()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processorDTO.getId()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createProcessorEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public LabelEntity createLabel(final Revision revision, final String groupId, final LabelDTO labelDTO) {
final RevisionUpdate<LabelDTO> snapshot = createComponent(
revision,
labelDTO,
() -> labelDAO.createLabel(groupId, labelDTO),
label -> dtoFactory.createLabelDto(label));
final Label label = labelDAO.getLabel(labelDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(label);
return entityFactory.createLabelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
/**
* Creates a component using the optimistic locking manager.
*
* @param componentDto the DTO that will be used to create the component
* @param daoCreation A Supplier that will create the NiFi Component to use
* @param dtoCreation a Function that will convert the NiFi Component into a corresponding DTO
* @param <D> the DTO Type
* @param <C> the NiFi Component Type
* @return a RevisionUpdate that represents the updated configuration
*/
private <D, C> RevisionUpdate<D> createComponent(final Revision revision, final ComponentDTO componentDto, final Supplier<C> daoCreation, final Function<C, D> dtoCreation) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
// read lock on the containing group
// request claim for component to be created... revision already verified (version == 0)
final RevisionClaim claim = new StandardRevisionClaim(revision);
// update revision through revision manager
return revisionManager.updateRevision(claim, user, () -> {
// add the component
final C component = daoCreation.get();
// save the flow
controllerFacade.save();
final D dto = dtoCreation.apply(component);
final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getIdentity());
return new StandardRevisionUpdate<D>(dto, lastMod);
});
}
@Override
public BulletinEntity createBulletin(final BulletinDTO bulletinDTO, final Boolean canRead){
final Bulletin bulletin = BulletinFactory.createBulletin(bulletinDTO.getCategory(),bulletinDTO.getLevel(),bulletinDTO.getMessage());
bulletinRepository.addBulletin(bulletin);
return entityFactory.createBulletinEntity(dtoFactory.createBulletinDto(bulletin),canRead);
}
@Override
public FunnelEntity createFunnel(final Revision revision, final String groupId, final FunnelDTO funnelDTO) {
final RevisionUpdate<FunnelDTO> snapshot = createComponent(
revision,
funnelDTO,
() -> funnelDAO.createFunnel(groupId, funnelDTO),
funnel -> dtoFactory.createFunnelDto(funnel));
final Funnel funnel = funnelDAO.getFunnel(funnelDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(funnel);
return entityFactory.createFunnelEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions);
}
@Override
public AccessPolicyEntity createAccessPolicy(final Revision revision, final AccessPolicyDTO accessPolicyDTO) {
final Authorizable tenantAuthorizable = authorizableLookup.getTenant();
final String creator = NiFiUserUtils.getNiFiUserIdentity();
final AccessPolicy newAccessPolicy = accessPolicyDAO.createAccessPolicy(accessPolicyDTO);
final ComponentReferenceEntity componentReference = createComponentReferenceEntity(newAccessPolicy.getResource());
final AccessPolicyDTO newAccessPolicyDto = dtoFactory.createAccessPolicyDto(newAccessPolicy,
newAccessPolicy.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()),
newAccessPolicy.getUsers().stream().map(userId -> {
final RevisionDTO userRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userId));
return entityFactory.createTenantEntity(dtoFactory.createTenantDTO(userDAO.getUser(userId)), userRevision,
dtoFactory.createPermissionsDto(tenantAuthorizable));
}).collect(Collectors.toSet()), componentReference);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getAccessPolicyById(accessPolicyDTO.getId()));
return entityFactory.createAccessPolicyEntity(newAccessPolicyDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), permissions);
}
@Override
public UserEntity createUser(final Revision revision, final UserDTO userDTO) {
final String creator = NiFiUserUtils.getNiFiUserIdentity();
final User newUser = userDAO.createUser(userDTO);
final Set<TenantEntity> tenantEntities = userGroupDAO.getUserGroupsForUser(newUser.getIdentifier()).stream()
.map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
final Set<AccessPolicySummaryEntity> policyEntities = userGroupDAO.getAccessPoliciesForUser(newUser.getIdentifier()).stream()
.map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
final UserDTO newUserDto = dtoFactory.createUserDto(newUser, tenantEntities, policyEntities);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getTenant());
return entityFactory.createUserEntity(newUserDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), permissions);
}
private ComponentReferenceEntity createComponentReferenceEntity(final String resource) {
ComponentReferenceEntity componentReferenceEntity = null;
try {
// get the component authorizable
Authorizable componentAuthorizable = authorizableLookup.getAuthorizableFromResource(resource);
// if this represents an authorizable whose policy permissions are enforced through the base resource,
// get the underlying base authorizable for the component reference
if (componentAuthorizable instanceof EnforcePolicyPermissionsThroughBaseResource) {
componentAuthorizable = ((EnforcePolicyPermissionsThroughBaseResource) componentAuthorizable).getBaseAuthorizable();
}
final ComponentReferenceDTO componentReference = dtoFactory.createComponentReferenceDto(componentAuthorizable);
if (componentReference != null) {
final PermissionsDTO componentReferencePermissions = dtoFactory.createPermissionsDto(componentAuthorizable);
final RevisionDTO componentReferenceRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(componentReference.getId()));
componentReferenceEntity = entityFactory.createComponentReferenceEntity(componentReference, componentReferenceRevision, componentReferencePermissions);
}
} catch (final ResourceNotFoundException e) {
// component not found for the specified resource
}
return componentReferenceEntity;
}
private AccessPolicySummaryEntity createAccessPolicySummaryEntity(final AccessPolicy ap) {
final ComponentReferenceEntity componentReference = createComponentReferenceEntity(ap.getResource());
final AccessPolicySummaryDTO apSummary = dtoFactory.createAccessPolicySummaryDto(ap, componentReference);
final PermissionsDTO apPermissions = dtoFactory.createPermissionsDto(authorizableLookup.getAccessPolicyById(ap.getIdentifier()));
final RevisionDTO apRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(ap.getIdentifier()));
return entityFactory.createAccessPolicySummaryEntity(apSummary, apRevision, apPermissions);
}
@Override
public UserGroupEntity createUserGroup(final Revision revision, final UserGroupDTO userGroupDTO) {
final String creator = NiFiUserUtils.getNiFiUserIdentity();
final Group newUserGroup = userGroupDAO.createUserGroup(userGroupDTO);
final Set<TenantEntity> tenantEntities = newUserGroup.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet());
final Set<AccessPolicySummaryEntity> policyEntities = userGroupDAO.getAccessPoliciesForUserGroup(newUserGroup.getIdentifier()).stream()
.map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
final UserGroupDTO newUserGroupDto = dtoFactory.createUserGroupDto(newUserGroup, tenantEntities, policyEntities);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getTenant());
return entityFactory.createUserGroupEntity(newUserGroupDto, dtoFactory.createRevisionDTO(new FlowModification(revision, creator)), permissions);
}
private void validateSnippetContents(final FlowSnippetDTO flow) {
// validate any processors
if (flow.getProcessors() != null) {
for (final ProcessorDTO processorDTO : flow.getProcessors()) {
final ProcessorNode processorNode = processorDAO.getProcessor(processorDTO.getId());
final Collection<ValidationResult> validationErrors = processorNode.getValidationErrors();
if (validationErrors != null && !validationErrors.isEmpty()) {
final List<String> errors = new ArrayList<>();
for (final ValidationResult validationResult : validationErrors) {
errors.add(validationResult.toString());
}
processorDTO.setValidationErrors(errors);
}
}
}
if (flow.getInputPorts() != null) {
for (final PortDTO portDTO : flow.getInputPorts()) {
final Port port = inputPortDAO.getPort(portDTO.getId());
final Collection<ValidationResult> validationErrors = port.getValidationErrors();
if (validationErrors != null && !validationErrors.isEmpty()) {
final List<String> errors = new ArrayList<>();
for (final ValidationResult validationResult : validationErrors) {
errors.add(validationResult.toString());
}
portDTO.setValidationErrors(errors);
}
}
}
if (flow.getOutputPorts() != null) {
for (final PortDTO portDTO : flow.getOutputPorts()) {
final Port port = outputPortDAO.getPort(portDTO.getId());
final Collection<ValidationResult> validationErrors = port.getValidationErrors();
if (validationErrors != null && !validationErrors.isEmpty()) {
final List<String> errors = new ArrayList<>();
for (final ValidationResult validationResult : validationErrors) {
errors.add(validationResult.toString());
}
portDTO.setValidationErrors(errors);
}
}
}
// get any remote process group issues
if (flow.getRemoteProcessGroups() != null) {
for (final RemoteProcessGroupDTO remoteProcessGroupDTO : flow.getRemoteProcessGroups()) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId());
if (remoteProcessGroup.getAuthorizationIssue() != null) {
remoteProcessGroupDTO.setAuthorizationIssues(Arrays.asList(remoteProcessGroup.getAuthorizationIssue()));
}
}
}
}
@Override
public FlowEntity copySnippet(final String groupId, final String snippetId, final Double originX, final Double originY, final String idGenerationSeed) {
// create the new snippet
final FlowSnippetDTO snippet = snippetDAO.copySnippet(groupId, snippetId, originX, originY, idGenerationSeed);
// save the flow
controllerFacade.save();
// drop the snippet
snippetDAO.dropSnippet(snippetId);
// post process new flow snippet
final FlowDTO flowDto = postProcessNewFlowSnippet(groupId, snippet);
final FlowEntity flowEntity = new FlowEntity();
flowEntity.setFlow(flowDto);
return flowEntity;
}
@Override
public SnippetEntity createSnippet(final SnippetDTO snippetDTO) {
// add the component
final Snippet snippet = snippetDAO.createSnippet(snippetDTO);
// save the flow
controllerFacade.save();
final SnippetDTO dto = dtoFactory.createSnippetDto(snippet);
final RevisionUpdate<SnippetDTO> snapshot = new StandardRevisionUpdate<SnippetDTO>(dto, null);
return entityFactory.createSnippetEntity(snapshot.getComponent());
}
@Override
public PortEntity createInputPort(final Revision revision, final String groupId, final PortDTO inputPortDTO) {
final RevisionUpdate<PortDTO> snapshot = createComponent(
revision,
inputPortDTO,
() -> inputPortDAO.createPort(groupId, inputPortDTO),
port -> dtoFactory.createPortDto(port));
final Port port = inputPortDAO.getPort(inputPortDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(port);
final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getInputPortStatus(port.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(port.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public PortEntity createOutputPort(final Revision revision, final String groupId, final PortDTO outputPortDTO) {
final RevisionUpdate<PortDTO> snapshot = createComponent(
revision,
outputPortDTO,
() -> outputPortDAO.createPort(groupId, outputPortDTO),
port -> dtoFactory.createPortDto(port));
final Port port = outputPortDAO.getPort(outputPortDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(port);
final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getOutputPortStatus(port.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(port.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createPortEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public ProcessGroupEntity createProcessGroup(final Revision revision, final String parentGroupId, final ProcessGroupDTO processGroupDTO) {
final RevisionUpdate<ProcessGroupDTO> snapshot = createComponent(
revision,
processGroupDTO,
() -> processGroupDAO.createProcessGroup(parentGroupId, processGroupDTO),
processGroup -> dtoFactory.createProcessGroupDto(processGroup));
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(processGroupDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
final ProcessGroupStatusDTO status = dtoFactory.createConciseProcessGroupStatusDto(controllerFacade.getProcessGroupStatus(processGroup.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processGroup.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createProcessGroupEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public RemoteProcessGroupEntity createRemoteProcessGroup(final Revision revision, final String groupId, final RemoteProcessGroupDTO remoteProcessGroupDTO) {
final RevisionUpdate<RemoteProcessGroupDTO> snapshot = createComponent(
revision,
remoteProcessGroupDTO,
() -> remoteProcessGroupDAO.createRemoteProcessGroup(groupId, remoteProcessGroupDTO),
remoteProcessGroup -> dtoFactory.createRemoteProcessGroupDto(remoteProcessGroup));
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroup);
final RemoteProcessGroupStatusDTO status = dtoFactory.createRemoteProcessGroupStatusDto(controllerFacade.getRemoteProcessGroupStatus(remoteProcessGroup.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(remoteProcessGroup.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createRemoteProcessGroupEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, status, bulletinEntities);
}
@Override
public void verifyCanAddTemplate(String groupId, String name) {
templateDAO.verifyCanAddTemplate(name, groupId);
}
@Override
public void verifyComponentTypes(FlowSnippetDTO snippet) {
templateDAO.verifyComponentTypes(snippet);
}
@Override
public TemplateDTO createTemplate(final String name, final String description, final String snippetId, final String groupId, final Optional<String> idGenerationSeed) {
// get the specified snippet
final Snippet snippet = snippetDAO.getSnippet(snippetId);
// create the template
final TemplateDTO templateDTO = new TemplateDTO();
templateDTO.setName(name);
templateDTO.setDescription(description);
templateDTO.setTimestamp(new Date());
templateDTO.setSnippet(snippetUtils.populateFlowSnippet(snippet, true, true, true));
templateDTO.setEncodingVersion(TemplateDTO.MAX_ENCODING_VERSION);
// set the id based on the specified seed
final String uuid = idGenerationSeed.isPresent() ? (UUID.nameUUIDFromBytes(idGenerationSeed.get().getBytes(StandardCharsets.UTF_8))).toString() : UUID.randomUUID().toString();
templateDTO.setId(uuid);
// create the template
final Template template = templateDAO.createTemplate(templateDTO, groupId);
// drop the snippet
snippetDAO.dropSnippet(snippetId);
// save the flow
controllerFacade.save();
return dtoFactory.createTemplateDTO(template);
}
/**
* Ensures default values are populated for all components in this snippet. This is necessary to handle old templates without default values
* and when existing properties have default values introduced.
*
* @param snippet snippet
*/
private void ensureDefaultPropertyValuesArePopulated(final FlowSnippetDTO snippet) {
if (snippet != null) {
if (snippet.getControllerServices() != null) {
snippet.getControllerServices().forEach(dto -> {
if (dto.getProperties() == null) {
dto.setProperties(new LinkedHashMap<>());
}
try {
final ConfigurableComponent configurableComponent = controllerFacade.getTemporaryComponent(dto.getType(), dto.getBundle());
configurableComponent.getPropertyDescriptors().forEach(descriptor -> {
if (dto.getProperties().get(descriptor.getName()) == null) {
dto.getProperties().put(descriptor.getName(), descriptor.getDefaultValue());
}
});
} catch (final Exception e) {
logger.warn(String.format("Unable to create ControllerService of type %s to populate default values.", dto.getType()));
}
});
}
if (snippet.getProcessors() != null) {
snippet.getProcessors().forEach(dto -> {
if (dto.getConfig() == null) {
dto.setConfig(new ProcessorConfigDTO());
}
final ProcessorConfigDTO config = dto.getConfig();
if (config.getProperties() == null) {
config.setProperties(new LinkedHashMap<>());
}
try {
final ConfigurableComponent configurableComponent = controllerFacade.getTemporaryComponent(dto.getType(), dto.getBundle());
configurableComponent.getPropertyDescriptors().forEach(descriptor -> {
if (config.getProperties().get(descriptor.getName()) == null) {
config.getProperties().put(descriptor.getName(), descriptor.getDefaultValue());
}
});
} catch (final Exception e) {
logger.warn(String.format("Unable to create Processor of type %s to populate default values.", dto.getType()));
}
});
}
if (snippet.getProcessGroups() != null) {
snippet.getProcessGroups().forEach(processGroup -> {
ensureDefaultPropertyValuesArePopulated(processGroup.getContents());
});
}
}
}
@Override
public TemplateDTO importTemplate(final TemplateDTO templateDTO, final String groupId, final Optional<String> idGenerationSeed) {
// ensure id is set
final String uuid = idGenerationSeed.isPresent() ? (UUID.nameUUIDFromBytes(idGenerationSeed.get().getBytes(StandardCharsets.UTF_8))).toString() : UUID.randomUUID().toString();
templateDTO.setId(uuid);
// mark the timestamp
templateDTO.setTimestamp(new Date());
// ensure default values are populated
ensureDefaultPropertyValuesArePopulated(templateDTO.getSnippet());
// import the template
final Template template = templateDAO.importTemplate(templateDTO, groupId);
// save the flow
controllerFacade.save();
// return the template dto
return dtoFactory.createTemplateDTO(template);
}
/**
* Post processes a new flow snippet including validation, removing the snippet, and DTO conversion.
*
* @param groupId group id
* @param snippet snippet
* @return flow dto
*/
private FlowDTO postProcessNewFlowSnippet(final String groupId, final FlowSnippetDTO snippet) {
// validate the new snippet
validateSnippetContents(snippet);
// identify all components added
final Set<String> identifiers = new HashSet<>();
snippet.getProcessors().stream()
.map(proc -> proc.getId())
.forEach(id -> identifiers.add(id));
snippet.getConnections().stream()
.map(conn -> conn.getId())
.forEach(id -> identifiers.add(id));
snippet.getInputPorts().stream()
.map(port -> port.getId())
.forEach(id -> identifiers.add(id));
snippet.getOutputPorts().stream()
.map(port -> port.getId())
.forEach(id -> identifiers.add(id));
snippet.getProcessGroups().stream()
.map(group -> group.getId())
.forEach(id -> identifiers.add(id));
snippet.getRemoteProcessGroups().stream()
.map(remoteGroup -> remoteGroup.getId())
.forEach(id -> identifiers.add(id));
snippet.getRemoteProcessGroups().stream()
.filter(remoteGroup -> remoteGroup.getContents() != null && remoteGroup.getContents().getInputPorts() != null)
.flatMap(remoteGroup -> remoteGroup.getContents().getInputPorts().stream())
.map(remoteInputPort -> remoteInputPort.getId())
.forEach(id -> identifiers.add(id));
snippet.getRemoteProcessGroups().stream()
.filter(remoteGroup -> remoteGroup.getContents() != null && remoteGroup.getContents().getOutputPorts() != null)
.flatMap(remoteGroup -> remoteGroup.getContents().getOutputPorts().stream())
.map(remoteOutputPort -> remoteOutputPort.getId())
.forEach(id -> identifiers.add(id));
snippet.getLabels().stream()
.map(label -> label.getId())
.forEach(id -> identifiers.add(id));
final ProcessGroup group = processGroupDAO.getProcessGroup(groupId);
final ProcessGroupStatus groupStatus = controllerFacade.getProcessGroupStatus(groupId);
return dtoFactory.createFlowDto(group, groupStatus, snippet, revisionManager, this::getProcessGroupBulletins);
}
@Override
public FlowEntity createTemplateInstance(final String groupId, final Double originX, final Double originY, final String templateEncodingVersion,
final FlowSnippetDTO requestSnippet, final String idGenerationSeed) {
// instantiate the template - there is no need to make another copy of the flow snippet since the actual template
// was copied and this dto is only used to instantiate it's components (which as already completed)
final FlowSnippetDTO snippet = templateDAO.instantiateTemplate(groupId, originX, originY, templateEncodingVersion, requestSnippet, idGenerationSeed);
// save the flow
controllerFacade.save();
// post process the new flow snippet
final FlowDTO flowDto = postProcessNewFlowSnippet(groupId, snippet);
final FlowEntity flowEntity = new FlowEntity();
flowEntity.setFlow(flowDto);
return flowEntity;
}
@Override
public ControllerServiceEntity createControllerService(final Revision revision, final String groupId, final ControllerServiceDTO controllerServiceDTO) {
controllerServiceDTO.setParentGroupId(groupId);
final NiFiUser user = NiFiUserUtils.getNiFiUser();
// request claim for component to be created... revision already verified (version == 0)
final RevisionClaim claim = new StandardRevisionClaim(revision);
final RevisionUpdate<ControllerServiceDTO> snapshot;
if (groupId == null) {
// update revision through revision manager
snapshot = revisionManager.updateRevision(claim, user, () -> {
// Unfortunately, we can not use the createComponent() method here because createComponent() wants to obtain the read lock
// on the group. The Controller Service may or may not have a Process Group (it won't if it's controller-scoped).
final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO);
final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(controllerService);
controllerFacade.save();
final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getIdentity());
return new StandardRevisionUpdate<ControllerServiceDTO>(dto, lastMod);
});
} else {
snapshot = revisionManager.updateRevision(claim, user, () -> {
final ControllerServiceNode controllerService = controllerServiceDAO.createControllerService(controllerServiceDTO);
final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(controllerService);
controllerFacade.save();
final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getIdentity());
return new StandardRevisionUpdate<ControllerServiceDTO>(dto, lastMod);
});
}
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(controllerService);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(controllerServiceDTO.getId()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createControllerServiceEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, bulletinEntities);
}
@Override
public ControllerServiceEntity updateControllerService(final Revision revision, final ControllerServiceDTO controllerServiceDTO) {
// get the component, ensure we have access to it, and perform the update request
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceDTO.getId());
final RevisionUpdate<ControllerServiceDTO> snapshot = updateComponent(revision,
controllerService,
() -> controllerServiceDAO.updateControllerService(controllerServiceDTO),
cs -> {
final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(cs);
final ControllerServiceReference ref = controllerService.getReferences();
final ControllerServiceReferencingComponentsEntity referencingComponentsEntity =
createControllerServiceReferencingComponentsEntity(ref, Sets.newHashSet(controllerService.getIdentifier()));
dto.setReferencingComponents(referencingComponentsEntity.getControllerServiceReferencingComponents());
return dto;
});
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(controllerService);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(controllerServiceDTO.getId()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createControllerServiceEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, bulletinEntities);
}
private Set<ConfiguredComponent> findAllReferencingComponents(final ControllerServiceReference reference) {
final Set<ConfiguredComponent> referencingComponents = new HashSet<>(reference.getReferencingComponents());
for (final ConfiguredComponent referencingComponent : reference.getReferencingComponents()) {
if (referencingComponent instanceof ControllerServiceNode) {
referencingComponents.addAll(findAllReferencingComponents(((ControllerServiceNode) referencingComponent).getReferences()));
}
}
return referencingComponents;
}
@Override
public ControllerServiceReferencingComponentsEntity updateControllerServiceReferencingComponents(
final Map<String, Revision> referenceRevisions, final String controllerServiceId, final ScheduledState scheduledState, final ControllerServiceState controllerServiceState) {
final RevisionClaim claim = new StandardRevisionClaim(referenceRevisions.values());
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final RevisionUpdate<ControllerServiceReferencingComponentsEntity> update = revisionManager.updateRevision(claim, user,
new UpdateRevisionTask<ControllerServiceReferencingComponentsEntity>() {
@Override
public RevisionUpdate<ControllerServiceReferencingComponentsEntity> update() {
final Set<ConfiguredComponent> updated = controllerServiceDAO.updateControllerServiceReferencingComponents(controllerServiceId, scheduledState, controllerServiceState);
final ControllerServiceReference updatedReference = controllerServiceDAO.getControllerService(controllerServiceId).getReferences();
// get the revisions of the updated components
final Map<String, Revision> updatedRevisions = new HashMap<>();
for (final ConfiguredComponent component : updated) {
final Revision currentRevision = revisionManager.getRevision(component.getIdentifier());
final Revision requestRevision = referenceRevisions.get(component.getIdentifier());
updatedRevisions.put(component.getIdentifier(), currentRevision.incrementRevision(requestRevision.getClientId()));
}
// ensure the revision for all referencing components is included regardless of whether they were updated in this request
for (final ConfiguredComponent component : findAllReferencingComponents(updatedReference)) {
updatedRevisions.putIfAbsent(component.getIdentifier(), revisionManager.getRevision(component.getIdentifier()));
}
final ControllerServiceReferencingComponentsEntity entity = createControllerServiceReferencingComponentsEntity(updatedReference, updatedRevisions);
return new StandardRevisionUpdate<>(entity, null, new HashSet<>(updatedRevisions.values()));
}
});
return update.getComponent();
}
/**
* Finds the identifiers for all components referencing a ControllerService.
*
* @param reference ControllerServiceReference
* @param visited ControllerServices we've already visited
*/
private void findControllerServiceReferencingComponentIdentifiers(final ControllerServiceReference reference, final Set<ControllerServiceNode> visited) {
for (final ConfiguredComponent component : reference.getReferencingComponents()) {
// if this is a ControllerService consider it's referencing components
if (component instanceof ControllerServiceNode) {
final ControllerServiceNode node = (ControllerServiceNode) component;
if (!visited.contains(node)) {
findControllerServiceReferencingComponentIdentifiers(node.getReferences(), visited);
}
visited.add(node);
}
}
}
/**
* Creates entities for components referencing a ControllerService using their current revision.
*
* @param reference ControllerServiceReference
* @return The entity
*/
private ControllerServiceReferencingComponentsEntity createControllerServiceReferencingComponentsEntity(final ControllerServiceReference reference, final Set<String> lockedIds) {
final Set<ControllerServiceNode> visited = new HashSet<>();
visited.add(reference.getReferencedComponent());
findControllerServiceReferencingComponentIdentifiers(reference, visited);
final Map<String, Revision> referencingRevisions = new HashMap<>();
for (final ConfiguredComponent component : reference.getReferencingComponents()) {
referencingRevisions.put(component.getIdentifier(), revisionManager.getRevision(component.getIdentifier()));
}
return createControllerServiceReferencingComponentsEntity(reference, referencingRevisions);
}
/**
* Creates entities for components referencing a ControllerService using the specified revisions.
*
* @param reference ControllerServiceReference
* @param revisions The revisions
* @return The entity
*/
private ControllerServiceReferencingComponentsEntity createControllerServiceReferencingComponentsEntity(
final ControllerServiceReference reference, final Map<String, Revision> revisions) {
final Set<ControllerServiceNode> visited = new HashSet<>();
visited.add(reference.getReferencedComponent());
return createControllerServiceReferencingComponentsEntity(reference, revisions, visited);
}
/**
* Creates entities for components referencing a ControllerServcie using the specified revisions.
*
* @param reference ControllerServiceReference
* @param revisions The revisions
* @param visited Which services we've already considered (in case of cycle)
* @return The entity
*/
private ControllerServiceReferencingComponentsEntity createControllerServiceReferencingComponentsEntity(
final ControllerServiceReference reference, final Map<String, Revision> revisions, final Set<ControllerServiceNode> visited) {
final String modifier = NiFiUserUtils.getNiFiUserIdentity();
final Set<ConfiguredComponent> referencingComponents = reference.getReferencingComponents();
final Set<ControllerServiceReferencingComponentEntity> componentEntities = new HashSet<>();
for (final ConfiguredComponent refComponent : referencingComponents) {
PermissionsDTO permissions = null;
if (refComponent instanceof Authorizable) {
permissions = dtoFactory.createPermissionsDto(refComponent);
}
final Revision revision = revisions.get(refComponent.getIdentifier());
final FlowModification flowMod = new FlowModification(revision, modifier);
final RevisionDTO revisionDto = dtoFactory.createRevisionDTO(flowMod);
final ControllerServiceReferencingComponentDTO dto = dtoFactory.createControllerServiceReferencingComponentDTO(refComponent);
if (refComponent instanceof ControllerServiceNode) {
final ControllerServiceNode node = (ControllerServiceNode) refComponent;
// indicate if we've hit a cycle
dto.setReferenceCycle(visited.contains(node));
// mark node as visited before building the reference cycle
visited.add(node);
// if we haven't encountered this service before include it's referencing components
if (!dto.getReferenceCycle()) {
final ControllerServiceReference refReferences = node.getReferences();
final Map<String, Revision> referencingRevisions = new HashMap<>(revisions);
for (final ConfiguredComponent component : refReferences.getReferencingComponents()) {
referencingRevisions.putIfAbsent(component.getIdentifier(), revisionManager.getRevision(component.getIdentifier()));
}
final ControllerServiceReferencingComponentsEntity references = createControllerServiceReferencingComponentsEntity(refReferences, referencingRevisions, visited);
dto.setReferencingComponents(references.getControllerServiceReferencingComponents());
}
}
componentEntities.add(entityFactory.createControllerServiceReferencingComponentEntity(dto, revisionDto, permissions));
}
final ControllerServiceReferencingComponentsEntity entity = new ControllerServiceReferencingComponentsEntity();
entity.setControllerServiceReferencingComponents(componentEntities);
return entity;
}
@Override
public ControllerServiceEntity deleteControllerService(final Revision revision, final String controllerServiceId) {
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(controllerService);
final ControllerServiceDTO snapshot = deleteComponent(
revision,
controllerService.getResource(),
() -> controllerServiceDAO.deleteControllerService(controllerServiceId),
true,
dtoFactory.createControllerServiceDto(controllerService));
return entityFactory.createControllerServiceEntity(snapshot, null, permissions, null);
}
@Override
public ReportingTaskEntity createReportingTask(final Revision revision, final ReportingTaskDTO reportingTaskDTO) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
// request claim for component to be created... revision already verified (version == 0)
final RevisionClaim claim = new StandardRevisionClaim(revision);
// update revision through revision manager
final RevisionUpdate<ReportingTaskDTO> snapshot = revisionManager.updateRevision(claim, user, () -> {
// create the reporting task
final ReportingTaskNode reportingTask = reportingTaskDAO.createReportingTask(reportingTaskDTO);
// save the update
controllerFacade.save();
final ReportingTaskDTO dto = dtoFactory.createReportingTaskDto(reportingTask);
final FlowModification lastMod = new FlowModification(revision.incrementRevision(revision.getClientId()), user.getIdentity());
return new StandardRevisionUpdate<ReportingTaskDTO>(dto, lastMod);
});
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskDTO.getId());
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(reportingTask);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(reportingTask.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createReportingTaskEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, bulletinEntities);
}
@Override
public ReportingTaskEntity updateReportingTask(final Revision revision, final ReportingTaskDTO reportingTaskDTO) {
// get the component, ensure we have access to it, and perform the update request
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskDTO.getId());
final RevisionUpdate<ReportingTaskDTO> snapshot = updateComponent(revision,
reportingTask,
() -> reportingTaskDAO.updateReportingTask(reportingTaskDTO),
rt -> dtoFactory.createReportingTaskDto(rt));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(reportingTask);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(reportingTask.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createReportingTaskEntity(snapshot.getComponent(), dtoFactory.createRevisionDTO(snapshot.getLastModification()), permissions, bulletinEntities);
}
@Override
public ReportingTaskEntity deleteReportingTask(final Revision revision, final String reportingTaskId) {
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(reportingTask);
final ReportingTaskDTO snapshot = deleteComponent(
revision,
reportingTask.getResource(),
() -> reportingTaskDAO.deleteReportingTask(reportingTaskId),
true,
dtoFactory.createReportingTaskDto(reportingTask));
return entityFactory.createReportingTaskEntity(snapshot, null, permissions, null);
}
@Override
public void deleteActions(final Date endDate) {
// get the user from the request
final NiFiUser user = NiFiUserUtils.getNiFiUser();
if (user == null) {
throw new WebApplicationException(new Throwable("Unable to access details for current user."));
}
// create the purge details
final FlowChangePurgeDetails details = new FlowChangePurgeDetails();
details.setEndDate(endDate);
// create a purge action to record that records are being removed
final FlowChangeAction purgeAction = new FlowChangeAction();
purgeAction.setUserIdentity(user.getIdentity());
purgeAction.setOperation(Operation.Purge);
purgeAction.setTimestamp(new Date());
purgeAction.setSourceId("Flow Controller");
purgeAction.setSourceName("History");
purgeAction.setSourceType(Component.Controller);
purgeAction.setActionDetails(details);
// purge corresponding actions
auditService.purgeActions(endDate, purgeAction);
}
@Override
public ProvenanceDTO submitProvenance(final ProvenanceDTO query) {
return controllerFacade.submitProvenance(query);
}
@Override
public void deleteProvenance(final String queryId) {
controllerFacade.deleteProvenanceQuery(queryId);
}
@Override
public LineageDTO submitLineage(final LineageDTO lineage) {
return controllerFacade.submitLineage(lineage);
}
@Override
public void deleteLineage(final String lineageId) {
controllerFacade.deleteLineage(lineageId);
}
@Override
public ProvenanceEventDTO submitReplay(final Long eventId) {
return controllerFacade.submitReplay(eventId);
}
// -----------------------------------------
// Read Operations
// -----------------------------------------
@Override
public SearchResultsDTO searchController(final String query) {
return controllerFacade.search(query);
}
@Override
public DownloadableContent getContent(final String connectionId, final String flowFileUuid, final String uri) {
return connectionDAO.getContent(connectionId, flowFileUuid, uri);
}
@Override
public DownloadableContent getContent(final Long eventId, final String uri, final ContentDirection contentDirection) {
return controllerFacade.getContent(eventId, uri, contentDirection);
}
@Override
public ProvenanceDTO getProvenance(final String queryId, final Boolean summarize, final Boolean incrementalResults) {
return controllerFacade.getProvenanceQuery(queryId, summarize, incrementalResults);
}
@Override
public LineageDTO getLineage(final String lineageId) {
return controllerFacade.getLineage(lineageId);
}
@Override
public ProvenanceOptionsDTO getProvenanceSearchOptions() {
return controllerFacade.getProvenanceSearchOptions();
}
@Override
public ProvenanceEventDTO getProvenanceEvent(final Long id) {
return controllerFacade.getProvenanceEvent(id);
}
@Override
public ProcessGroupStatusEntity getProcessGroupStatus(final String groupId, final boolean recursive) {
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
final ProcessGroupStatusDTO dto = dtoFactory.createProcessGroupStatusDto(processGroup, controllerFacade.getProcessGroupStatus(groupId));
// prune the response as necessary
if (!recursive) {
pruneChildGroups(dto.getAggregateSnapshot());
if (dto.getNodeSnapshots() != null) {
for (final NodeProcessGroupStatusSnapshotDTO nodeSnapshot : dto.getNodeSnapshots()) {
pruneChildGroups(nodeSnapshot.getStatusSnapshot());
}
}
}
return entityFactory.createProcessGroupStatusEntity(dto, permissions);
}
private void pruneChildGroups(final ProcessGroupStatusSnapshotDTO snapshot) {
for (final ProcessGroupStatusSnapshotEntity childProcessGroupStatusEntity : snapshot.getProcessGroupStatusSnapshots()) {
final ProcessGroupStatusSnapshotDTO childProcessGroupStatus = childProcessGroupStatusEntity.getProcessGroupStatusSnapshot();
childProcessGroupStatus.setConnectionStatusSnapshots(null);
childProcessGroupStatus.setProcessGroupStatusSnapshots(null);
childProcessGroupStatus.setInputPortStatusSnapshots(null);
childProcessGroupStatus.setOutputPortStatusSnapshots(null);
childProcessGroupStatus.setProcessorStatusSnapshots(null);
childProcessGroupStatus.setRemoteProcessGroupStatusSnapshots(null);
}
}
@Override
public ControllerStatusDTO getControllerStatus() {
return controllerFacade.getControllerStatus();
}
@Override
public ComponentStateDTO getProcessorState(final String processorId) {
final StateMap clusterState = isClustered() ? processorDAO.getState(processorId, Scope.CLUSTER) : null;
final StateMap localState = processorDAO.getState(processorId, Scope.LOCAL);
// processor will be non null as it was already found when getting the state
final ProcessorNode processor = processorDAO.getProcessor(processorId);
return dtoFactory.createComponentStateDTO(processorId, processor.getProcessor().getClass(), localState, clusterState);
}
@Override
public ComponentStateDTO getControllerServiceState(final String controllerServiceId) {
final StateMap clusterState = isClustered() ? controllerServiceDAO.getState(controllerServiceId, Scope.CLUSTER) : null;
final StateMap localState = controllerServiceDAO.getState(controllerServiceId, Scope.LOCAL);
// 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
public ComponentStateDTO getReportingTaskState(final String reportingTaskId) {
final StateMap clusterState = isClustered() ? reportingTaskDAO.getState(reportingTaskId, Scope.CLUSTER) : null;
final StateMap localState = reportingTaskDAO.getState(reportingTaskId, Scope.LOCAL);
// 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
public CountersDTO getCounters() {
final List<Counter> counters = controllerFacade.getCounters();
final Set<CounterDTO> counterDTOs = new LinkedHashSet<>(counters.size());
for (final Counter counter : counters) {
counterDTOs.add(dtoFactory.createCounterDto(counter));
}
final CountersSnapshotDTO snapshotDto = dtoFactory.createCountersDto(counterDTOs);
final CountersDTO countersDto = new CountersDTO();
countersDto.setAggregateSnapshot(snapshotDto);
return countersDto;
}
private ConnectionEntity createConnectionEntity(final Connection connection) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(connection.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(connection);
final ConnectionStatusDTO status = dtoFactory.createConnectionStatusDto(controllerFacade.getConnectionStatus(connection.getIdentifier()));
return entityFactory.createConnectionEntity(dtoFactory.createConnectionDto(connection), revision, permissions, status);
}
@Override
public Set<ConnectionEntity> getConnections(final String groupId) {
final Set<Connection> connections = connectionDAO.getConnections(groupId);
return connections.stream()
.map(connection -> createConnectionEntity(connection))
.collect(Collectors.toSet());
}
@Override
public ConnectionEntity getConnection(final String connectionId) {
final Connection connection = connectionDAO.getConnection(connectionId);
return createConnectionEntity(connection);
}
@Override
public DropRequestDTO getFlowFileDropRequest(final String connectionId, final String dropRequestId) {
return dtoFactory.createDropRequestDTO(connectionDAO.getFlowFileDropRequest(connectionId, dropRequestId));
}
@Override
public ListingRequestDTO getFlowFileListingRequest(final String connectionId, final String listingRequestId) {
final Connection connection = connectionDAO.getConnection(connectionId);
final ListingRequestDTO listRequest = dtoFactory.createListingRequestDTO(connectionDAO.getFlowFileListingRequest(connectionId, listingRequestId));
// include whether the source and destination are running
if (connection.getSource() != null) {
listRequest.setSourceRunning(connection.getSource().isRunning());
}
if (connection.getDestination() != null) {
listRequest.setDestinationRunning(connection.getDestination().isRunning());
}
return listRequest;
}
@Override
public FlowFileDTO getFlowFile(final String connectionId, final String flowFileUuid) {
return dtoFactory.createFlowFileDTO(connectionDAO.getFlowFile(connectionId, flowFileUuid));
}
@Override
public ConnectionStatusEntity getConnectionStatus(final String connectionId) {
final Connection connection = connectionDAO.getConnection(connectionId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(connection);
final ConnectionStatusDTO dto = dtoFactory.createConnectionStatusDto(controllerFacade.getConnectionStatus(connectionId));
return entityFactory.createConnectionStatusEntity(dto, permissions);
}
@Override
public StatusHistoryEntity getConnectionStatusHistory(final String connectionId) {
final Connection connection = connectionDAO.getConnection(connectionId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(connection);
final StatusHistoryDTO dto = controllerFacade.getConnectionStatusHistory(connectionId);
return entityFactory.createStatusHistoryEntity(dto, permissions);
}
private ProcessorEntity createProcessorEntity(final ProcessorNode processor) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(processor.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processor);
final ProcessorStatusDTO status = dtoFactory.createProcessorStatusDto(controllerFacade.getProcessorStatus(processor.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(processor.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createProcessorEntity(dtoFactory.createProcessorDto(processor), revision, permissions, status, bulletinEntities);
}
@Override
public Set<ProcessorEntity> getProcessors(final String groupId) {
final Set<ProcessorNode> processors = processorDAO.getProcessors(groupId);
return processors.stream()
.map(processor -> createProcessorEntity(processor))
.collect(Collectors.toSet());
}
@Override
public TemplateDTO exportTemplate(final String id) {
final Template template = templateDAO.getTemplate(id);
final TemplateDTO templateDetails = template.getDetails();
final TemplateDTO templateDTO = dtoFactory.createTemplateDTO(template);
templateDTO.setSnippet(dtoFactory.copySnippetContents(templateDetails.getSnippet()));
return templateDTO;
}
@Override
public TemplateDTO getTemplate(final String id) {
return dtoFactory.createTemplateDTO(templateDAO.getTemplate(id));
}
@Override
public Set<TemplateEntity> getTemplates() {
return templateDAO.getTemplates().stream()
.map(template -> {
final TemplateDTO dto = dtoFactory.createTemplateDTO(template);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(template);
final TemplateEntity entity = new TemplateEntity();
entity.setId(dto.getId());
entity.setPermissions(permissions);
entity.setTemplate(dto);
return entity;
}).collect(Collectors.toSet());
}
@Override
public Set<DocumentedTypeDTO> getWorkQueuePrioritizerTypes() {
return controllerFacade.getFlowFileComparatorTypes();
}
@Override
public Set<DocumentedTypeDTO> getProcessorTypes(final String bundleGroup, final String bundleArtifact, final String type) {
return controllerFacade.getFlowFileProcessorTypes(bundleGroup, bundleArtifact, type);
}
@Override
public Set<DocumentedTypeDTO> getControllerServiceTypes(final String serviceType, final String serviceBundleGroup, final String serviceBundleArtifact, final String serviceBundleVersion,
final String bundleGroup, final String bundleArtifact, final String type) {
return controllerFacade.getControllerServiceTypes(serviceType, serviceBundleGroup, serviceBundleArtifact, serviceBundleVersion, bundleGroup, bundleArtifact, type);
}
@Override
public Set<DocumentedTypeDTO> getReportingTaskTypes(final String bundleGroup, final String bundleArtifact, final String type) {
return controllerFacade.getReportingTaskTypes(bundleGroup, bundleArtifact, type);
}
@Override
public ProcessorEntity getProcessor(final String id) {
final ProcessorNode processor = processorDAO.getProcessor(id);
return createProcessorEntity(processor);
}
@Override
public PropertyDescriptorDTO getProcessorPropertyDescriptor(final String id, final String property) {
final ProcessorNode processor = processorDAO.getProcessor(id);
PropertyDescriptor descriptor = processor.getPropertyDescriptor(property);
// return an invalid descriptor if the processor doesn't support this property
if (descriptor == null) {
descriptor = new PropertyDescriptor.Builder().name(property).addValidator(Validator.INVALID).dynamic(true).build();
}
return dtoFactory.createPropertyDescriptorDto(descriptor, processor.getProcessGroup().getIdentifier());
}
@Override
public ProcessorStatusEntity getProcessorStatus(final String id) {
final ProcessorNode processor = processorDAO.getProcessor(id);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processor);
final ProcessorStatusDTO dto = dtoFactory.createProcessorStatusDto(controllerFacade.getProcessorStatus(id));
return entityFactory.createProcessorStatusEntity(dto, permissions);
}
@Override
public StatusHistoryEntity getProcessorStatusHistory(final String id) {
final ProcessorNode processor = processorDAO.getProcessor(id);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processor);
final StatusHistoryDTO dto = controllerFacade.getProcessorStatusHistory(id);
return entityFactory.createStatusHistoryEntity(dto, permissions);
}
private boolean authorizeBulletin(final Bulletin bulletin) {
final String sourceId = bulletin.getSourceId();
final ComponentType type = bulletin.getSourceType();
final Authorizable authorizable;
try {
switch (type) {
case PROCESSOR:
authorizable = authorizableLookup.getProcessor(sourceId).getAuthorizable();
break;
case REPORTING_TASK:
authorizable = authorizableLookup.getReportingTask(sourceId).getAuthorizable();
break;
case CONTROLLER_SERVICE:
authorizable = authorizableLookup.getControllerService(sourceId).getAuthorizable();
break;
case FLOW_CONTROLLER:
authorizable = controllerFacade;
break;
case INPUT_PORT:
authorizable = authorizableLookup.getInputPort(sourceId);
break;
case OUTPUT_PORT:
authorizable = authorizableLookup.getOutputPort(sourceId);
break;
case REMOTE_PROCESS_GROUP:
authorizable = authorizableLookup.getRemoteProcessGroup(sourceId);
break;
default:
throw new WebApplicationException(Response.serverError().entity("An unexpected type of component is the source of this bulletin.").build());
}
} catch (final ResourceNotFoundException e) {
// if the underlying component is gone, disallow
return false;
}
// perform the authorization
final AuthorizationResult result = authorizable.checkAuthorization(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
return Result.Approved.equals(result.getResult());
}
@Override
public BulletinBoardDTO getBulletinBoard(final BulletinQueryDTO query) {
// build the query
final BulletinQuery.Builder queryBuilder = new BulletinQuery.Builder()
.groupIdMatches(query.getGroupId())
.sourceIdMatches(query.getSourceId())
.nameMatches(query.getName())
.messageMatches(query.getMessage())
.after(query.getAfter())
.limit(query.getLimit());
// perform the query
final List<Bulletin> results = bulletinRepository.findBulletins(queryBuilder.build());
// perform the query and generate the results - iterating in reverse order since we are
// getting the most recent results by ordering by timestamp desc above. this gets the
// exact results we want but in reverse order
final List<BulletinEntity> bulletinEntities = new ArrayList<>();
for (final ListIterator<Bulletin> bulletinIter = results.listIterator(results.size()); bulletinIter.hasPrevious(); ) {
final Bulletin bulletin = bulletinIter.previous();
bulletinEntities.add(entityFactory.createBulletinEntity(dtoFactory.createBulletinDto(bulletin), authorizeBulletin(bulletin)));
}
// create the bulletin board
final BulletinBoardDTO bulletinBoard = new BulletinBoardDTO();
bulletinBoard.setBulletins(bulletinEntities);
bulletinBoard.setGenerated(new Date());
return bulletinBoard;
}
@Override
public SystemDiagnosticsDTO getSystemDiagnostics() {
final SystemDiagnostics sysDiagnostics = controllerFacade.getSystemDiagnostics();
return dtoFactory.createSystemDiagnosticsDto(sysDiagnostics);
}
@Override
public List<ResourceDTO> getResources() {
final List<Resource> resources = controllerFacade.getResources();
final List<ResourceDTO> resourceDtos = new ArrayList<>(resources.size());
for (final Resource resource : resources) {
resourceDtos.add(dtoFactory.createResourceDto(resource));
}
return resourceDtos;
}
/**
* Ensures the specified user has permission to access the specified port. This method does
* not utilize the DataTransferAuthorizable as that will enforce the entire chain is
* authorized for the transfer. This method is only invoked when obtaining the site to site
* details so the entire chain isn't necessary.
*/
private boolean isUserAuthorized(final NiFiUser user, final RootGroupPort port) {
final boolean isSiteToSiteSecure = Boolean.TRUE.equals(properties.isSiteToSiteSecure());
// if site to site is not secure, allow all users
if (!isSiteToSiteSecure) {
return true;
}
final Map<String, String> userContext;
if (user.getClientAddress() != null && !user.getClientAddress().trim().isEmpty()) {
userContext = new HashMap<>();
userContext.put(UserContextKeys.CLIENT_ADDRESS.name(), user.getClientAddress());
} else {
userContext = null;
}
final AuthorizationRequest request = new AuthorizationRequest.Builder()
.resource(ResourceFactory.getDataTransferResource(port.getResource()))
.identity(user.getIdentity())
.anonymous(user.isAnonymous())
.accessAttempt(false)
.action(RequestAction.WRITE)
.userContext(userContext)
.explanationSupplier(() -> "Unable to retrieve port details.")
.build();
final AuthorizationResult result = authorizer.authorize(request);
return Result.Approved.equals(result.getResult());
}
@Override
public ControllerDTO getSiteToSiteDetails() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
if (user == null) {
throw new WebApplicationException(new Throwable("Unable to access details for current user."));
}
// serialize the input ports this NiFi has access to
final Set<PortDTO> inputPortDtos = new LinkedHashSet<>();
final Set<RootGroupPort> inputPorts = controllerFacade.getInputPorts();
for (final RootGroupPort inputPort : inputPorts) {
if (isUserAuthorized(user, inputPort)) {
final PortDTO dto = new PortDTO();
dto.setId(inputPort.getIdentifier());
dto.setName(inputPort.getName());
dto.setComments(inputPort.getComments());
dto.setState(inputPort.getScheduledState().toString());
inputPortDtos.add(dto);
}
}
// serialize the output ports this NiFi has access to
final Set<PortDTO> outputPortDtos = new LinkedHashSet<>();
for (final RootGroupPort outputPort : controllerFacade.getOutputPorts()) {
if (isUserAuthorized(user, outputPort)) {
final PortDTO dto = new PortDTO();
dto.setId(outputPort.getIdentifier());
dto.setName(outputPort.getName());
dto.setComments(outputPort.getComments());
dto.setState(outputPort.getScheduledState().toString());
outputPortDtos.add(dto);
}
}
// get the root group
final ProcessGroup rootGroup = processGroupDAO.getProcessGroup(controllerFacade.getRootGroupId());
final ProcessGroupCounts counts = rootGroup.getCounts();
// create the controller dto
final ControllerDTO controllerDTO = new ControllerDTO();
controllerDTO.setId(controllerFacade.getRootGroupId());
controllerDTO.setInstanceId(controllerFacade.getInstanceId());
controllerDTO.setInputPorts(inputPortDtos);
controllerDTO.setOutputPorts(outputPortDtos);
controllerDTO.setInputPortCount(inputPortDtos.size());
controllerDTO.setOutputPortCount(outputPortDtos.size());
controllerDTO.setRunningCount(counts.getRunningCount());
controllerDTO.setStoppedCount(counts.getStoppedCount());
controllerDTO.setInvalidCount(counts.getInvalidCount());
controllerDTO.setDisabledCount(counts.getDisabledCount());
// determine the site to site configuration
controllerDTO.setRemoteSiteListeningPort(controllerFacade.getRemoteSiteListeningPort());
controllerDTO.setRemoteSiteHttpListeningPort(controllerFacade.getRemoteSiteListeningHttpPort());
controllerDTO.setSiteToSiteSecure(controllerFacade.isRemoteSiteCommsSecure());
return controllerDTO;
}
@Override
public ControllerConfigurationEntity getControllerConfiguration() {
final Revision rev = revisionManager.getRevision(FlowController.class.getSimpleName());
final ControllerConfigurationDTO dto = dtoFactory.createControllerConfigurationDto(controllerFacade);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(controllerFacade);
final RevisionDTO revision = dtoFactory.createRevisionDTO(rev);
return entityFactory.createControllerConfigurationEntity(dto, revision, permissions);
}
@Override
public ControllerBulletinsEntity getControllerBulletins() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final ControllerBulletinsEntity controllerBulletinsEntity = new ControllerBulletinsEntity();
final List<BulletinEntity> controllerBulletinEntities = new ArrayList<>();
final Authorizable controllerAuthorizable = authorizableLookup.getController();
final boolean authorized = controllerAuthorizable.isAuthorized(authorizer, RequestAction.READ, user);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForController());
controllerBulletinEntities.addAll(bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, authorized)).collect(Collectors.toList()));
// get the controller service bulletins
final BulletinQuery controllerServiceQuery = new BulletinQuery.Builder().sourceType(ComponentType.CONTROLLER_SERVICE).build();
final List<Bulletin> allControllerServiceBulletins = bulletinRepository.findBulletins(controllerServiceQuery);
final List<BulletinEntity> controllerServiceBulletinEntities = new ArrayList<>();
for (final Bulletin bulletin : allControllerServiceBulletins) {
try {
final Authorizable controllerServiceAuthorizable = authorizableLookup.getControllerService(bulletin.getSourceId()).getAuthorizable();
final boolean controllerServiceAuthorized = controllerServiceAuthorizable.isAuthorized(authorizer, RequestAction.READ, user);
final BulletinEntity controllerServiceBulletin = entityFactory.createBulletinEntity(dtoFactory.createBulletinDto(bulletin), controllerServiceAuthorized);
controllerServiceBulletinEntities.add(controllerServiceBulletin);
controllerBulletinEntities.add(controllerServiceBulletin);
} catch (final ResourceNotFoundException e) {
// controller service missing.. skip
}
}
controllerBulletinsEntity.setControllerServiceBulletins(controllerServiceBulletinEntities);
// get the reporting task bulletins
final BulletinQuery reportingTaskQuery = new BulletinQuery.Builder().sourceType(ComponentType.REPORTING_TASK).build();
final List<Bulletin> allReportingTaskBulletins = bulletinRepository.findBulletins(reportingTaskQuery);
final List<BulletinEntity> reportingTaskBulletinEntities = new ArrayList<>();
for (final Bulletin bulletin : allReportingTaskBulletins) {
try {
final Authorizable reportingTaskAuthorizable = authorizableLookup.getReportingTask(bulletin.getSourceId()).getAuthorizable();
final boolean reportingTaskAuthorizableAuthorized = reportingTaskAuthorizable.isAuthorized(authorizer, RequestAction.READ, user);
final BulletinEntity reportingTaskBulletin = entityFactory.createBulletinEntity(dtoFactory.createBulletinDto(bulletin), reportingTaskAuthorizableAuthorized);
reportingTaskBulletinEntities.add(reportingTaskBulletin);
controllerBulletinEntities.add(reportingTaskBulletin);
} catch (final ResourceNotFoundException e) {
// reporting task missing.. skip
}
}
controllerBulletinsEntity.setReportingTaskBulletins(reportingTaskBulletinEntities);
controllerBulletinsEntity.setBulletins(pruneAndSortBulletins(controllerBulletinEntities, BulletinRepository.MAX_BULLETINS_FOR_CONTROLLER));
return controllerBulletinsEntity;
}
@Override
public FlowConfigurationEntity getFlowConfiguration() {
final FlowConfigurationDTO dto = dtoFactory.createFlowConfigurationDto(properties.getAutoRefreshInterval());
final FlowConfigurationEntity entity = new FlowConfigurationEntity();
entity.setFlowConfiguration(dto);
return entity;
}
@Override
public AccessPolicyEntity getAccessPolicy(final String accessPolicyId) {
final AccessPolicy accessPolicy = accessPolicyDAO.getAccessPolicy(accessPolicyId);
return createAccessPolicyEntity(accessPolicy);
}
@Override
public AccessPolicyEntity getAccessPolicy(final RequestAction requestAction, final String resource) {
Authorizable authorizable;
try {
authorizable = authorizableLookup.getAuthorizableFromResource(resource);
} catch (final ResourceNotFoundException e) {
// unable to find the underlying authorizable... user authorized based on top level /policies... create
// an anonymous authorizable to attempt to locate an existing policy for this resource
authorizable = new Authorizable() {
@Override
public Authorizable getParentAuthorizable() {
return null;
}
@Override
public Resource getResource() {
return new Resource() {
@Override
public String getIdentifier() {
return resource;
}
@Override
public String getName() {
return resource;
}
@Override
public String getSafeDescription() {
return "Policy " + resource;
}
};
}
};
}
final AccessPolicy accessPolicy = accessPolicyDAO.getAccessPolicy(requestAction, authorizable);
return createAccessPolicyEntity(accessPolicy);
}
private AccessPolicyEntity createAccessPolicyEntity(final AccessPolicy accessPolicy) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(accessPolicy.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getAccessPolicyById(accessPolicy.getIdentifier()));
final ComponentReferenceEntity componentReference = createComponentReferenceEntity(accessPolicy.getResource());
return entityFactory.createAccessPolicyEntity(
dtoFactory.createAccessPolicyDto(accessPolicy,
accessPolicy.getGroups().stream().map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet()),
accessPolicy.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet()), componentReference),
revision, permissions);
}
@Override
public UserEntity getUser(final String userId) {
final User user = userDAO.getUser(userId);
return createUserEntity(user);
}
@Override
public Set<UserEntity> getUsers() {
final Set<User> users = userDAO.getUsers();
return users.stream()
.map(user -> createUserEntity(user))
.collect(Collectors.toSet());
}
private UserEntity createUserEntity(final User user) {
final RevisionDTO userRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(user.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getTenant());
final Set<TenantEntity> userGroups = userGroupDAO.getUserGroupsForUser(user.getIdentifier()).stream()
.map(g -> g.getIdentifier()).map(mapUserGroupIdToTenantEntity()).collect(Collectors.toSet());
final Set<AccessPolicySummaryEntity> policyEntities = userGroupDAO.getAccessPoliciesForUser(user.getIdentifier()).stream()
.map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
return entityFactory.createUserEntity(dtoFactory.createUserDto(user, userGroups, policyEntities), userRevision, permissions);
}
private UserGroupEntity createUserGroupEntity(final Group userGroup) {
final RevisionDTO userGroupRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userGroup.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(authorizableLookup.getTenant());
final Set<TenantEntity> users = userGroup.getUsers().stream().map(mapUserIdToTenantEntity()).collect(Collectors.toSet());
final Set<AccessPolicySummaryEntity> policyEntities = userGroupDAO.getAccessPoliciesForUserGroup(userGroup.getIdentifier()).stream()
.map(ap -> createAccessPolicySummaryEntity(ap)).collect(Collectors.toSet());
return entityFactory.createUserGroupEntity(dtoFactory.createUserGroupDto(userGroup, users, policyEntities), userGroupRevision, permissions);
}
@Override
public UserGroupEntity getUserGroup(final String userGroupId) {
final Group userGroup = userGroupDAO.getUserGroup(userGroupId);
return createUserGroupEntity(userGroup);
}
@Override
public Set<UserGroupEntity> getUserGroups() {
final Set<Group> userGroups = userGroupDAO.getUserGroups();
return userGroups.stream()
.map(userGroup -> createUserGroupEntity(userGroup))
.collect(Collectors.toSet());
}
private LabelEntity createLabelEntity(final Label label) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(label.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(label);
return entityFactory.createLabelEntity(dtoFactory.createLabelDto(label), revision, permissions);
}
@Override
public Set<LabelEntity> getLabels(final String groupId) {
final Set<Label> labels = labelDAO.getLabels(groupId);
return labels.stream()
.map(label -> createLabelEntity(label))
.collect(Collectors.toSet());
}
@Override
public LabelEntity getLabel(final String labelId) {
final Label label = labelDAO.getLabel(labelId);
return createLabelEntity(label);
}
private FunnelEntity createFunnelEntity(final Funnel funnel) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(funnel.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(funnel);
return entityFactory.createFunnelEntity(dtoFactory.createFunnelDto(funnel), revision, permissions);
}
@Override
public Set<FunnelEntity> getFunnels(final String groupId) {
final Set<Funnel> funnels = funnelDAO.getFunnels(groupId);
return funnels.stream()
.map(funnel -> createFunnelEntity(funnel))
.collect(Collectors.toSet());
}
@Override
public FunnelEntity getFunnel(final String funnelId) {
final Funnel funnel = funnelDAO.getFunnel(funnelId);
return createFunnelEntity(funnel);
}
private PortEntity createInputPortEntity(final Port port) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(port.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(port);
final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getInputPortStatus(port.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(port.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createPortEntity(dtoFactory.createPortDto(port), revision, permissions, status, bulletinEntities);
}
private PortEntity createOutputPortEntity(final Port port) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(port.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(port);
final PortStatusDTO status = dtoFactory.createPortStatusDto(controllerFacade.getOutputPortStatus(port.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(port.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createPortEntity(dtoFactory.createPortDto(port), revision, permissions, status, bulletinEntities);
}
@Override
public Set<PortEntity> getInputPorts(final String groupId) {
final Set<Port> inputPorts = inputPortDAO.getPorts(groupId);
return inputPorts.stream()
.map(port -> createInputPortEntity(port))
.collect(Collectors.toSet());
}
@Override
public Set<PortEntity> getOutputPorts(final String groupId) {
final Set<Port> ports = outputPortDAO.getPorts(groupId);
return ports.stream()
.map(port -> createOutputPortEntity(port))
.collect(Collectors.toSet());
}
private ProcessGroupEntity createProcessGroupEntity(final ProcessGroup group) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(group.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(group);
final ProcessGroupStatusDTO status = dtoFactory.createConciseProcessGroupStatusDto(controllerFacade.getProcessGroupStatus(group.getIdentifier()));
final List<BulletinEntity> bulletins = getProcessGroupBulletins(group);
return entityFactory.createProcessGroupEntity(dtoFactory.createProcessGroupDto(group), revision, permissions, status, bulletins);
}
private List<BulletinEntity> getProcessGroupBulletins(final ProcessGroup group) {
final List<Bulletin> bulletins = new ArrayList<>(bulletinRepository.findBulletinsForGroupBySource(group.getIdentifier()));
for (final ProcessGroup descendantGroup : group.findAllProcessGroups()) {
bulletins.addAll(bulletinRepository.findBulletinsForGroupBySource(descendantGroup.getIdentifier()));
}
List<BulletinEntity> bulletinEntities = new ArrayList<>();
for (final Bulletin bulletin : bulletins) {
bulletinEntities.add(entityFactory.createBulletinEntity(dtoFactory.createBulletinDto(bulletin), authorizeBulletin(bulletin)));
}
return pruneAndSortBulletins(bulletinEntities, BulletinRepository.MAX_BULLETINS_PER_COMPONENT);
}
private List<BulletinEntity> pruneAndSortBulletins(final List<BulletinEntity> bulletinEntities, final int maxBulletins) {
// sort the bulletins
Collections.sort(bulletinEntities, new Comparator<BulletinEntity>() {
@Override
public int compare(BulletinEntity o1, BulletinEntity o2) {
if (o1 == null && o2 == null) {
return 0;
}
if (o1 == null) {
return 1;
}
if (o2 == null) {
return -1;
}
return -Long.compare(o1.getId(), o2.getId());
}
});
// prune the response to only include the max number of bulletins
if (bulletinEntities.size() > maxBulletins) {
return bulletinEntities.subList(0, maxBulletins);
} else {
return bulletinEntities;
}
}
@Override
public Set<ProcessGroupEntity> getProcessGroups(final String parentGroupId) {
final Set<ProcessGroup> groups = processGroupDAO.getProcessGroups(parentGroupId);
return groups.stream()
.map(group -> createProcessGroupEntity(group))
.collect(Collectors.toSet());
}
private RemoteProcessGroupEntity createRemoteGroupEntity(final RemoteProcessGroup rpg) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(rpg.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(rpg);
final RemoteProcessGroupStatusDTO status = dtoFactory.createRemoteProcessGroupStatusDto(controllerFacade.getRemoteProcessGroupStatus(rpg.getIdentifier()));
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(rpg.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createRemoteProcessGroupEntity(dtoFactory.createRemoteProcessGroupDto(rpg), revision, permissions, status, bulletinEntities);
}
@Override
public Set<RemoteProcessGroupEntity> getRemoteProcessGroups(final String groupId) {
final Set<RemoteProcessGroup> rpgs = remoteProcessGroupDAO.getRemoteProcessGroups(groupId);
return rpgs.stream()
.map(rpg -> createRemoteGroupEntity(rpg))
.collect(Collectors.toSet());
}
@Override
public PortEntity getInputPort(final String inputPortId) {
final Port port = inputPortDAO.getPort(inputPortId);
return createInputPortEntity(port);
}
@Override
public PortStatusEntity getInputPortStatus(final String inputPortId) {
final Port inputPort = inputPortDAO.getPort(inputPortId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(inputPort);
final PortStatusDTO dto = dtoFactory.createPortStatusDto(controllerFacade.getInputPortStatus(inputPortId));
return entityFactory.createPortStatusEntity(dto, permissions);
}
@Override
public PortEntity getOutputPort(final String outputPortId) {
final Port port = outputPortDAO.getPort(outputPortId);
return createOutputPortEntity(port);
}
@Override
public PortStatusEntity getOutputPortStatus(final String outputPortId) {
final Port outputPort = outputPortDAO.getPort(outputPortId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(outputPort);
final PortStatusDTO dto = dtoFactory.createPortStatusDto(controllerFacade.getOutputPortStatus(outputPortId));
return entityFactory.createPortStatusEntity(dto, permissions);
}
@Override
public RemoteProcessGroupEntity getRemoteProcessGroup(final String remoteProcessGroupId) {
final RemoteProcessGroup rpg = remoteProcessGroupDAO.getRemoteProcessGroup(remoteProcessGroupId);
return createRemoteGroupEntity(rpg);
}
@Override
public RemoteProcessGroupStatusEntity getRemoteProcessGroupStatus(final String id) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(id);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroup);
final RemoteProcessGroupStatusDTO dto = dtoFactory.createRemoteProcessGroupStatusDto(controllerFacade.getRemoteProcessGroupStatus(id));
return entityFactory.createRemoteProcessGroupStatusEntity(dto, permissions);
}
@Override
public StatusHistoryEntity getRemoteProcessGroupStatusHistory(final String id) {
final RemoteProcessGroup remoteProcessGroup = remoteProcessGroupDAO.getRemoteProcessGroup(id);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(remoteProcessGroup);
final StatusHistoryDTO dto = controllerFacade.getRemoteProcessGroupStatusHistory(id);
return entityFactory.createStatusHistoryEntity(dto, permissions);
}
@Override
public CurrentUserEntity getCurrentUser() {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
final CurrentUserEntity entity = new CurrentUserEntity();
entity.setIdentity(user.getIdentity());
entity.setAnonymous(user.isAnonymous());
entity.setProvenancePermissions(dtoFactory.createPermissionsDto(authorizableLookup.getProvenance()));
entity.setCountersPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getCounters()));
entity.setTenantsPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getTenant()));
entity.setControllerPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getController()));
entity.setPoliciesPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getPolicies()));
entity.setSystemPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getSystem()));
entity.setRestrictedComponentsPermissions(dtoFactory.createPermissionsDto(authorizableLookup.getRestrictedComponents()));
return entity;
}
@Override
public ProcessGroupFlowEntity getProcessGroupFlow(final String groupId) {
// get all identifiers for every child component
final Set<String> identifiers = new HashSet<>();
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
processGroup.getProcessors().stream()
.map(proc -> proc.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getConnections().stream()
.map(conn -> conn.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getInputPorts().stream()
.map(port -> port.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getOutputPorts().stream()
.map(port -> port.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getProcessGroups().stream()
.map(group -> group.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getRemoteProcessGroups().stream()
.map(remoteGroup -> remoteGroup.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getRemoteProcessGroups().stream()
.flatMap(remoteGroup -> remoteGroup.getInputPorts().stream())
.map(remoteInputPort -> remoteInputPort.getIdentifier())
.forEach(id -> identifiers.add(id));
processGroup.getRemoteProcessGroups().stream()
.flatMap(remoteGroup -> remoteGroup.getOutputPorts().stream())
.map(remoteOutputPort -> remoteOutputPort.getIdentifier())
.forEach(id -> identifiers.add(id));
// read lock on every component being accessed in the dto conversion
final ProcessGroupStatus groupStatus = controllerFacade.getProcessGroupStatus(groupId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
return entityFactory.createProcessGroupFlowEntity(dtoFactory.createProcessGroupFlowDto(processGroup, groupStatus, revisionManager, this::getProcessGroupBulletins), permissions);
}
@Override
public ProcessGroupEntity getProcessGroup(final String groupId) {
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
return createProcessGroupEntity(processGroup);
}
private ControllerServiceEntity createControllerServiceEntity(final ControllerServiceNode serviceNode, final Set<String> serviceIds) {
final ControllerServiceDTO dto = dtoFactory.createControllerServiceDto(serviceNode);
final ControllerServiceReference ref = serviceNode.getReferences();
final ControllerServiceReferencingComponentsEntity referencingComponentsEntity = createControllerServiceReferencingComponentsEntity(ref, serviceIds);
dto.setReferencingComponents(referencingComponentsEntity.getControllerServiceReferencingComponents());
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(serviceNode.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(serviceNode);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(serviceNode.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createControllerServiceEntity(dto, revision, permissions, bulletinEntities);
}
@Override
public Set<ControllerServiceEntity> getControllerServices(final String groupId) {
final Set<ControllerServiceNode> serviceNodes = controllerServiceDAO.getControllerServices(groupId);
final Set<String> serviceIds = serviceNodes.stream().map(service -> service.getIdentifier()).collect(Collectors.toSet());
return serviceNodes.stream()
.map(serviceNode -> createControllerServiceEntity(serviceNode, serviceIds))
.collect(Collectors.toSet());
}
@Override
public ControllerServiceEntity getControllerService(final String controllerServiceId) {
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(controllerServiceId);
return createControllerServiceEntity(controllerService, Sets.newHashSet(controllerServiceId));
}
@Override
public PropertyDescriptorDTO getControllerServicePropertyDescriptor(final String id, final String property) {
final ControllerServiceNode controllerService = controllerServiceDAO.getControllerService(id);
PropertyDescriptor descriptor = controllerService.getControllerServiceImplementation().getPropertyDescriptor(property);
// return an invalid descriptor if the controller service doesn't support this property
if (descriptor == null) {
descriptor = new PropertyDescriptor.Builder().name(property).addValidator(Validator.INVALID).dynamic(true).build();
}
final String groupId = controllerService.getProcessGroup() == null ? null : controllerService.getProcessGroup().getIdentifier();
return dtoFactory.createPropertyDescriptorDto(descriptor, groupId);
}
@Override
public ControllerServiceReferencingComponentsEntity getControllerServiceReferencingComponents(final String controllerServiceId) {
final ControllerServiceNode service = controllerServiceDAO.getControllerService(controllerServiceId);
final ControllerServiceReference ref = service.getReferences();
return createControllerServiceReferencingComponentsEntity(ref, Sets.newHashSet(controllerServiceId));
}
private ReportingTaskEntity createReportingTaskEntity(final ReportingTaskNode reportingTask) {
final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(reportingTask.getIdentifier()));
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(reportingTask);
final List<BulletinDTO> bulletins = dtoFactory.createBulletinDtos(bulletinRepository.findBulletinsForSource(reportingTask.getIdentifier()));
final List<BulletinEntity> bulletinEntities = bulletins.stream().map(bulletin -> entityFactory.createBulletinEntity(bulletin, permissions.getCanRead())).collect(Collectors.toList());
return entityFactory.createReportingTaskEntity(dtoFactory.createReportingTaskDto(reportingTask), revision, permissions, bulletinEntities);
}
@Override
public Set<ReportingTaskEntity> getReportingTasks() {
final Set<ReportingTaskNode> reportingTasks = reportingTaskDAO.getReportingTasks();
return reportingTasks.stream()
.map(reportingTask -> createReportingTaskEntity(reportingTask))
.collect(Collectors.toSet());
}
@Override
public ReportingTaskEntity getReportingTask(final String reportingTaskId) {
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(reportingTaskId);
return createReportingTaskEntity(reportingTask);
}
@Override
public PropertyDescriptorDTO getReportingTaskPropertyDescriptor(final String id, final String property) {
final ReportingTaskNode reportingTask = reportingTaskDAO.getReportingTask(id);
PropertyDescriptor descriptor = reportingTask.getReportingTask().getPropertyDescriptor(property);
// return an invalid descriptor if the reporting task doesn't support this property
if (descriptor == null) {
descriptor = new PropertyDescriptor.Builder().name(property).addValidator(Validator.INVALID).dynamic(true).build();
}
return dtoFactory.createPropertyDescriptorDto(descriptor, null);
}
@Override
public StatusHistoryEntity getProcessGroupStatusHistory(final String groupId) {
final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId);
final PermissionsDTO permissions = dtoFactory.createPermissionsDto(processGroup);
final StatusHistoryDTO dto = controllerFacade.getProcessGroupStatusHistory(groupId);
return entityFactory.createStatusHistoryEntity(dto, permissions);
}
private AuthorizationResult authorizeAction(final Action action) {
final String sourceId = action.getSourceId();
final Component type = action.getSourceType();
Authorizable authorizable;
try {
switch (type) {
case Processor:
authorizable = authorizableLookup.getProcessor(sourceId).getAuthorizable();
break;
case ReportingTask:
authorizable = authorizableLookup.getReportingTask(sourceId).getAuthorizable();
break;
case ControllerService:
authorizable = authorizableLookup.getControllerService(sourceId).getAuthorizable();
break;
case Controller:
authorizable = controllerFacade;
break;
case InputPort:
authorizable = authorizableLookup.getInputPort(sourceId);
break;
case OutputPort:
authorizable = authorizableLookup.getOutputPort(sourceId);
break;
case ProcessGroup:
authorizable = authorizableLookup.getProcessGroup(sourceId).getAuthorizable();
break;
case RemoteProcessGroup:
authorizable = authorizableLookup.getRemoteProcessGroup(sourceId);
break;
case Funnel:
authorizable = authorizableLookup.getFunnel(sourceId);
break;
case Connection:
authorizable = authorizableLookup.getConnection(sourceId).getAuthorizable();
break;
case AccessPolicy:
authorizable = authorizableLookup.getAccessPolicyById(sourceId);
break;
case User:
case UserGroup:
authorizable = authorizableLookup.getTenant();
break;
default:
throw new WebApplicationException(Response.serverError().entity("An unexpected type of component is the source of this action.").build());
}
} catch (final ResourceNotFoundException e) {
// if the underlying component is gone, use the controller to see if permissions should be allowed
authorizable = controllerFacade;
}
// perform the authorization
return authorizable.checkAuthorization(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
}
@Override
public HistoryDTO getActions(final HistoryQueryDTO historyQueryDto) {
// extract the query criteria
final HistoryQuery historyQuery = new HistoryQuery();
historyQuery.setStartDate(historyQueryDto.getStartDate());
historyQuery.setEndDate(historyQueryDto.getEndDate());
historyQuery.setSourceId(historyQueryDto.getSourceId());
historyQuery.setUserIdentity(historyQueryDto.getUserIdentity());
historyQuery.setOffset(historyQueryDto.getOffset());
historyQuery.setCount(historyQueryDto.getCount());
historyQuery.setSortColumn(historyQueryDto.getSortColumn());
historyQuery.setSortOrder(historyQueryDto.getSortOrder());
// perform the query
final History history = auditService.getActions(historyQuery);
// only retain authorized actions
final HistoryDTO historyDto = dtoFactory.createHistoryDto(history);
if (history.getActions() != null) {
final List<ActionEntity> actionEntities = new ArrayList<>();
for (final Action action : history.getActions()) {
final AuthorizationResult result = authorizeAction(action);
actionEntities.add(entityFactory.createActionEntity(dtoFactory.createActionDto(action), Result.Approved.equals(result.getResult())));
}
historyDto.setActions(actionEntities);
}
// create the response
return historyDto;
}
@Override
public ActionEntity getAction(final Integer actionId) {
// get the action
final Action action = auditService.getAction(actionId);
// ensure the action was found
if (action == null) {
throw new ResourceNotFoundException(String.format("Unable to find action with id '%s'.", actionId));
}
final AuthorizationResult result = authorizeAction(action);
final boolean authorized = Result.Approved.equals(result.getResult());
if (!authorized) {
throw new AccessDeniedException(result.getExplanation());
}
// return the action
return entityFactory.createActionEntity(dtoFactory.createActionDto(action), authorized);
}
@Override
public ComponentHistoryDTO getComponentHistory(final String componentId) {
final Map<String, PropertyHistoryDTO> propertyHistoryDtos = new LinkedHashMap<>();
final Map<String, List<PreviousValue>> propertyHistory = auditService.getPreviousValues(componentId);
for (final Map.Entry<String, List<PreviousValue>> entry : propertyHistory.entrySet()) {
final List<PreviousValueDTO> previousValueDtos = new ArrayList<>();
for (final PreviousValue previousValue : entry.getValue()) {
final PreviousValueDTO dto = new PreviousValueDTO();
dto.setPreviousValue(previousValue.getPreviousValue());
dto.setTimestamp(previousValue.getTimestamp());
dto.setUserIdentity(previousValue.getUserIdentity());
previousValueDtos.add(dto);
}
if (!previousValueDtos.isEmpty()) {
final PropertyHistoryDTO propertyHistoryDto = new PropertyHistoryDTO();
propertyHistoryDto.setPreviousValues(previousValueDtos);
propertyHistoryDtos.put(entry.getKey(), propertyHistoryDto);
}
}
final ComponentHistoryDTO history = new ComponentHistoryDTO();
history.setComponentId(componentId);
history.setPropertyHistory(propertyHistoryDtos);
return history;
}
@Override
public boolean isClustered() {
return controllerFacade.isClustered();
}
@Override
public String getNodeId() {
final NodeIdentifier nodeId = controllerFacade.getNodeId();
if (nodeId != null) {
return nodeId.getId();
} else {
return null;
}
}
@Override
public ClusterDTO getCluster() {
// create cluster summary dto
final ClusterDTO clusterDto = new ClusterDTO();
// set current time
clusterDto.setGenerated(new Date());
// create node dtos
final List<NodeDTO> nodeDtos = clusterCoordinator.getNodeIdentifiers().stream()
.map(nodeId -> getNode(nodeId))
.collect(Collectors.toList());
clusterDto.setNodes(nodeDtos);
return clusterDto;
}
@Override
public NodeDTO getNode(final String nodeId) {
final NodeIdentifier nodeIdentifier = clusterCoordinator.getNodeIdentifier(nodeId);
return getNode(nodeIdentifier);
}
private NodeDTO getNode(final NodeIdentifier nodeId) {
final NodeConnectionStatus nodeStatus = clusterCoordinator.getConnectionStatus(nodeId);
final List<NodeEvent> events = clusterCoordinator.getNodeEvents(nodeId);
final Set<String> roles = getRoles(nodeId);
final NodeHeartbeat heartbeat = heartbeatMonitor.getLatestHeartbeat(nodeId);
return dtoFactory.createNodeDTO(nodeId, nodeStatus, heartbeat, events, roles);
}
private Set<String> getRoles(final NodeIdentifier nodeId) {
final Set<String> roles = new HashSet<>();
final String nodeAddress = nodeId.getSocketAddress() + ":" + nodeId.getSocketPort();
for (final String roleName : ClusterRoles.getAllRoles()) {
final String leader = leaderElectionManager.getLeader(roleName);
if (leader == null) {
continue;
}
if (leader.equals(nodeAddress)) {
roles.add(roleName);
}
}
return roles;
}
@Override
public void deleteNode(final String nodeId) {
final NiFiUser user = NiFiUserUtils.getNiFiUser();
if (user == null) {
throw new WebApplicationException(new Throwable("Unable to access details for current user."));
}
final String userDn = user.getIdentity();
final NodeIdentifier nodeIdentifier = clusterCoordinator.getNodeIdentifier(nodeId);
if (nodeIdentifier == null) {
throw new UnknownNodeException("Cannot remove Node with ID " + nodeId + " because it is not part of the cluster");
}
final NodeConnectionStatus nodeConnectionStatus = clusterCoordinator.getConnectionStatus(nodeIdentifier);
if (!nodeConnectionStatus.getState().equals(NodeConnectionState.DISCONNECTED)) {
throw new IllegalNodeDeletionException("Cannot remove Node with ID " + nodeId + " because it is not disconnected, current state = " + nodeConnectionStatus.getState());
}
clusterCoordinator.removeNode(nodeIdentifier, userDn);
heartbeatMonitor.removeHeartbeat(nodeIdentifier);
}
/* reusable function declarations for converting ids to tenant entities */
private Function<String, TenantEntity> mapUserGroupIdToTenantEntity() {
return userGroupId -> {
final RevisionDTO userGroupRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userGroupId));
return entityFactory.createTenantEntity(dtoFactory.createTenantDTO(userGroupDAO.getUserGroup(userGroupId)), userGroupRevision,
dtoFactory.createPermissionsDto(authorizableLookup.getTenant()));
};
}
private Function<String, TenantEntity> mapUserIdToTenantEntity() {
return userId -> {
final RevisionDTO userRevision = dtoFactory.createRevisionDTO(revisionManager.getRevision(userId));
return entityFactory.createTenantEntity(dtoFactory.createTenantDTO(userDAO.getUser(userId)), userRevision,
dtoFactory.createPermissionsDto(authorizableLookup.getTenant()));
};
}
/* setters */
public void setProperties(final NiFiProperties properties) {
this.properties = properties;
}
public void setControllerFacade(final ControllerFacade controllerFacade) {
this.controllerFacade = controllerFacade;
}
public void setRemoteProcessGroupDAO(final RemoteProcessGroupDAO remoteProcessGroupDAO) {
this.remoteProcessGroupDAO = remoteProcessGroupDAO;
}
public void setLabelDAO(final LabelDAO labelDAO) {
this.labelDAO = labelDAO;
}
public void setFunnelDAO(final FunnelDAO funnelDAO) {
this.funnelDAO = funnelDAO;
}
public void setSnippetDAO(final SnippetDAO snippetDAO) {
this.snippetDAO = snippetDAO;
}
public void setProcessorDAO(final ProcessorDAO processorDAO) {
this.processorDAO = processorDAO;
}
public void setConnectionDAO(final ConnectionDAO connectionDAO) {
this.connectionDAO = connectionDAO;
}
public void setAuditService(final AuditService auditService) {
this.auditService = auditService;
}
public void setRevisionManager(final RevisionManager revisionManager) {
this.revisionManager = revisionManager;
}
public void setDtoFactory(final DtoFactory dtoFactory) {
this.dtoFactory = dtoFactory;
}
public void setEntityFactory(final EntityFactory entityFactory) {
this.entityFactory = entityFactory;
}
public void setInputPortDAO(final PortDAO inputPortDAO) {
this.inputPortDAO = inputPortDAO;
}
public void setOutputPortDAO(final PortDAO outputPortDAO) {
this.outputPortDAO = outputPortDAO;
}
public void setProcessGroupDAO(final ProcessGroupDAO processGroupDAO) {
this.processGroupDAO = processGroupDAO;
}
public void setControllerServiceDAO(final ControllerServiceDAO controllerServiceDAO) {
this.controllerServiceDAO = controllerServiceDAO;
}
public void setReportingTaskDAO(final ReportingTaskDAO reportingTaskDAO) {
this.reportingTaskDAO = reportingTaskDAO;
}
public void setTemplateDAO(final TemplateDAO templateDAO) {
this.templateDAO = templateDAO;
}
public void setSnippetUtils(final SnippetUtils snippetUtils) {
this.snippetUtils = snippetUtils;
}
public void setAuthorizableLookup(final AuthorizableLookup authorizableLookup) {
this.authorizableLookup = authorizableLookup;
}
public void setAuthorizer(final Authorizer authorizer) {
this.authorizer = authorizer;
}
public void setUserDAO(final UserDAO userDAO) {
this.userDAO = userDAO;
}
public void setUserGroupDAO(final UserGroupDAO userGroupDAO) {
this.userGroupDAO = userGroupDAO;
}
public void setAccessPolicyDAO(final AccessPolicyDAO accessPolicyDAO) {
this.accessPolicyDAO = accessPolicyDAO;
}
public void setClusterCoordinator(final ClusterCoordinator coordinator) {
this.clusterCoordinator = coordinator;
}
public void setHeartbeatMonitor(final HeartbeatMonitor heartbeatMonitor) {
this.heartbeatMonitor = heartbeatMonitor;
}
public void setBulletinRepository(final BulletinRepository bulletinRepository) {
this.bulletinRepository = bulletinRepository;
}
public void setLeaderElectionManager(final LeaderElectionManager leaderElectionManager) {
this.leaderElectionManager = leaderElectionManager;
}
}