/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.nifi.web.dao.impl; import org.apache.nifi.connectable.Port; import org.apache.nifi.connectable.Position; import org.apache.nifi.controller.FlowController; import org.apache.nifi.controller.ScheduledState; import org.apache.nifi.controller.exception.ValidationException; import org.apache.nifi.groups.ProcessGroup; import org.apache.nifi.remote.RootGroupPort; import org.apache.nifi.web.NiFiCoreException; import org.apache.nifi.web.ResourceNotFoundException; import org.apache.nifi.web.api.dto.PortDTO; import org.apache.nifi.web.dao.PortDAO; import java.util.ArrayList; import java.util.List; import java.util.Set; public class StandardOutputPortDAO extends ComponentDAO implements PortDAO { private FlowController flowController; private Port locatePort(final String portId) { final ProcessGroup rootGroup = flowController.getGroup(flowController.getRootGroupId()); final Port port = rootGroup.findOutputPort(portId); if (port == null) { throw new ResourceNotFoundException(String.format("Unable to find port with id '%s'.", portId)); } else { return port; } } @Override public boolean hasPort(String portId) { final ProcessGroup rootGroup = flowController.getGroup(flowController.getRootGroupId()); return rootGroup.findOutputPort(portId) != null; } @Override public Port createPort(String groupId, PortDTO portDTO) { if (isNotNull(portDTO.getParentGroupId()) && !flowController.areGroupsSame(groupId, portDTO.getParentGroupId())) { throw new IllegalArgumentException("Cannot specify a different Parent Group ID than the Group to which the OutputPort is being added."); } // ensure the name has been specified if (portDTO.getName() == null) { throw new IllegalArgumentException("Port name must be specified."); } // get the desired group ProcessGroup group = locateProcessGroup(flowController, groupId); // determine if this is the root group Port port; if (group.getParent() == null) { port = flowController.createRemoteOutputPort(portDTO.getId(), portDTO.getName()); } else { port = flowController.createLocalOutputPort(portDTO.getId(), portDTO.getName()); } // ensure we can perform the update before we add the processor to the flow verifyUpdate(port, portDTO); // configure if (portDTO.getPosition() != null) { port.setPosition(new Position(portDTO.getPosition().getX(), portDTO.getPosition().getY())); } port.setComments(portDTO.getComments()); // add the port group.addOutputPort(port); return port; } @Override public Port getPort(String portId) { return locatePort(portId); } @Override public Set<Port> getPorts(String groupId) { ProcessGroup group = locateProcessGroup(flowController, groupId); return group.getOutputPorts(); } @Override public void verifyUpdate(PortDTO portDTO) { final Port outputPort = locatePort(portDTO.getId()); verifyUpdate(outputPort, portDTO); } private void verifyUpdate(final Port outputPort, final PortDTO portDTO) { if (isNotNull(portDTO.getState())) { final ScheduledState purposedScheduledState = ScheduledState.valueOf(portDTO.getState()); // only attempt an action if it is changing if (!purposedScheduledState.equals(outputPort.getScheduledState())) { // perform the appropriate action switch (purposedScheduledState) { case RUNNING: outputPort.verifyCanStart(); break; case STOPPED: switch (outputPort.getScheduledState()) { case RUNNING: outputPort.verifyCanStop(); break; case DISABLED: outputPort.verifyCanEnable(); break; } break; case DISABLED: outputPort.verifyCanDisable(); break; } } } // see what's be modified if (isAnyNotNull(portDTO.getUserAccessControl(), portDTO.getGroupAccessControl(), portDTO.getConcurrentlySchedulableTaskCount(), portDTO.getName(), portDTO.getComments())) { // validate the request final List<String> requestValidation = validateProposedConfiguration(portDTO); // ensure there was no validation errors if (!requestValidation.isEmpty()) { throw new ValidationException(requestValidation); } // ensure the port can be updated outputPort.verifyCanUpdate(); } } private List<String> validateProposedConfiguration(PortDTO portDTO) { List<String> validationErrors = new ArrayList<>(); if (isNotNull(portDTO.getName()) && portDTO.getName().trim().isEmpty()) { validationErrors.add("Port name cannot be blank."); } if (isNotNull(portDTO.getConcurrentlySchedulableTaskCount()) && portDTO.getConcurrentlySchedulableTaskCount() <= 0) { validationErrors.add("Concurrent tasks must be a positive integer."); } return validationErrors; } @Override public Port updatePort(PortDTO portDTO) { Port outputPort = locatePort(portDTO.getId()); // ensure we can do this update verifyUpdate(outputPort, portDTO); // handle state transition if (portDTO.getState() != null) { final ScheduledState purposedScheduledState = ScheduledState.valueOf(portDTO.getState()); // only attempt an action if it is changing if (!purposedScheduledState.equals(outputPort.getScheduledState())) { try { // perform the appropriate action switch (purposedScheduledState) { case RUNNING: outputPort.getProcessGroup().startOutputPort(outputPort); break; case STOPPED: switch (outputPort.getScheduledState()) { case RUNNING: outputPort.getProcessGroup().stopOutputPort(outputPort); break; case DISABLED: outputPort.getProcessGroup().enableOutputPort(outputPort); break; } break; case DISABLED: outputPort.getProcessGroup().disableOutputPort(outputPort); break; } } catch (IllegalStateException ise) { throw new NiFiCoreException(ise.getMessage(), ise); } } } if (outputPort instanceof RootGroupPort) { final RootGroupPort rootPort = (RootGroupPort) outputPort; if (isNotNull(portDTO.getGroupAccessControl())) { rootPort.setGroupAccessControl(portDTO.getGroupAccessControl()); } if (isNotNull(portDTO.getUserAccessControl())) { rootPort.setUserAccessControl(portDTO.getUserAccessControl()); } } // perform the configuration final String name = portDTO.getName(); final String comments = portDTO.getComments(); final Integer concurrentTasks = portDTO.getConcurrentlySchedulableTaskCount(); if (isNotNull(portDTO.getPosition())) { outputPort.setPosition(new Position(portDTO.getPosition().getX(), portDTO.getPosition().getY())); } if (isNotNull(name)) { outputPort.setName(name); } if (isNotNull(comments)) { outputPort.setComments(comments); } if (isNotNull(concurrentTasks)) { outputPort.setMaxConcurrentTasks(concurrentTasks); } return outputPort; } @Override public void verifyDelete(final String portId) { final Port outputPort = locatePort(portId); outputPort.verifyCanDelete(); } @Override public void deletePort(String portId) { Port outputPort = locatePort(portId); outputPort.getProcessGroup().removeOutputPort(outputPort); } /* setters */ public void setFlowController(FlowController flowController) { this.flowController = flowController; } }