http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java deleted file mode 100644 index a332e05..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateManager.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.nifi.controller; - -import static java.util.Objects.requireNonNull; - -import java.io.BufferedInputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileFilter; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import org.apache.commons.lang3.StringUtils; -import org.apache.nifi.persistence.TemplateDeserializer; -import org.apache.nifi.persistence.TemplateSerializer; -import org.apache.nifi.stream.io.ByteArrayInputStream; -import org.apache.nifi.stream.io.ByteArrayOutputStream; -import org.apache.nifi.stream.io.DataOutputStream; -import org.apache.nifi.stream.io.StreamUtils; -import org.apache.nifi.web.api.dto.ConnectableDTO; -import org.apache.nifi.web.api.dto.ConnectionDTO; -import org.apache.nifi.web.api.dto.ControllerServiceDTO; -import org.apache.nifi.web.api.dto.FlowSnippetDTO; -import org.apache.nifi.web.api.dto.ProcessGroupDTO; -import org.apache.nifi.web.api.dto.ProcessorConfigDTO; -import org.apache.nifi.web.api.dto.ProcessorDTO; -import org.apache.nifi.web.api.dto.PropertyDescriptorDTO; -import org.apache.nifi.web.api.dto.RemoteProcessGroupContentsDTO; -import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO; -import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO; -import org.apache.nifi.web.api.dto.TemplateDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class TemplateManager { - - private static final Logger logger = LoggerFactory.getLogger(TemplateManager.class); - - private final Path directory; - private final Map<String, Template> templateMap = new HashMap<>(); - - private final ReadWriteLock rwLock = new ReentrantReadWriteLock(); - private final Lock readLock = rwLock.readLock(); - private final Lock writeLock = rwLock.writeLock(); - - private final FileFilter templateFileFilter = new FileFilter() { - @Override - public boolean accept(File pathname) { - return pathname.getName().toLowerCase().endsWith(".template"); - } - }; - - public TemplateManager(final Path storageLocation) throws IOException { - directory = storageLocation; - if (!Files.exists(directory)) { - Files.createDirectories(directory); - } else { - if (!Files.isDirectory(directory)) { - throw new IllegalArgumentException(directory.toString() + " is not a directory"); - } - // use toFile().canXXX, rather than Files.is... because on Windows 7, we sometimes get the wrong result for Files.is... (running Java 7 update 9) - if (!directory.toFile().canExecute() || !directory.toFile().canWrite()) { - throw new IOException("Invalid permissions for directory " + directory.toString()); - } - } - } - - /** - * Adds a template to this manager. The contents of this template must be part of the current flow. This is going create a template based on a snippet of this flow. Any sensitive properties in the - * TemplateDTO will be removed. - * - * @param dto dto - * @return a copy of the given DTO - * @throws IOException if an I/O error occurs when persisting the Template - * @throws NullPointerException if the DTO is null - * @throws IllegalArgumentException if does not contain all required information, such as the template name or a processor's configuration element - */ - public Template addTemplate(final TemplateDTO dto) throws IOException { - scrubTemplate(dto.getSnippet()); - return importTemplate(dto); - } - - private void verifyCanImport(final TemplateDTO dto) { - // ensure the template is specified - if (dto == null || dto.getSnippet() == null) { - throw new IllegalArgumentException("Template details not specified."); - } - - // ensure the name is specified - if (StringUtils.isBlank(dto.getName())) { - throw new IllegalArgumentException("Template name cannot be blank."); - } - - readLock.lock(); - try { - for (final Template template : templateMap.values()) { - final TemplateDTO existingDto = template.getDetails(); - - // ensure a template with this name doesnt already exist - if (dto.getName().equals(existingDto.getName())) { - throw new IllegalStateException(String.format("A template named '%s' already exists.", dto.getName())); - } - } - } finally { - readLock.unlock(); - } - } - - /** - * Clears all Templates from the TemplateManager - * - * @throws java.io.IOException ioe - */ - public void clear() throws IOException { - writeLock.lock(); - try { - templateMap.clear(); - - final File[] files = directory.toFile().listFiles(templateFileFilter); - if (files == null) { - return; - } - - for (final File file : files) { - boolean successful = false; - - for (int i = 0; i < 10; i++) { - if (file.delete()) { - successful = true; - break; - } - } - - if (!successful && file.exists()) { - throw new IOException("Failed to delete template file " + file.getAbsolutePath()); - } - } - } finally { - writeLock.unlock(); - } - } - - /** - * @param id template id - * @return the template with the given id, if it exists; else, returns null - */ - public Template getTemplate(final String id) { - readLock.lock(); - try { - return templateMap.get(id); - } finally { - readLock.unlock(); - } - } - - /** - * Loads the templates from disk - * - * @throws IOException ioe - */ - public void loadTemplates() throws IOException { - writeLock.lock(); - try { - final File[] files = directory.toFile().listFiles(templateFileFilter); - if (files == null) { - return; - } - - for (final File file : files) { - try (final FileInputStream fis = new FileInputStream(file); - final BufferedInputStream bis = new BufferedInputStream(fis)) { - final TemplateDTO templateDto = TemplateDeserializer.deserialize(bis); - templateMap.put(templateDto.getId(), new Template(templateDto)); - } - } - } finally { - writeLock.unlock(); - } - } - - public Template importTemplate(final TemplateDTO dto) throws IOException { - // ensure we can add this template - verifyCanImport(dto); - - writeLock.lock(); - try { - if (requireNonNull(dto).getId() == null) { - dto.setId(UUID.randomUUID().toString()); - } - - final Template template = new Template(dto); - persistTemplate(template); - - templateMap.put(dto.getId(), template); - return template; - } finally { - writeLock.unlock(); - } - } - - /** - * Persists the given template to disk - * - * @param template template - * @throws IOException ioe - */ - private void persistTemplate(final Template template) throws IOException { - final Path path = directory.resolve(template.getDetails().getId() + ".template"); - Files.write(path, TemplateSerializer.serialize(template.getDetails()), StandardOpenOption.WRITE, StandardOpenOption.CREATE); - } - - /** - * Scrubs the template prior to persisting in order to remove fields that shouldn't be included or are unnecessary. - * - * @param snippet snippet - */ - private void scrubTemplate(final FlowSnippetDTO snippet) { - // ensure that contents have been specified - if (snippet != null) { - // go through each processor if specified - if (snippet.getProcessors() != null) { - scrubProcessors(snippet.getProcessors()); - } - - // go through each connection if specified - if (snippet.getConnections() != null) { - scrubConnections(snippet.getConnections()); - } - - // go through each remote process group if specified - if (snippet.getRemoteProcessGroups() != null) { - scrubRemoteProcessGroups(snippet.getRemoteProcessGroups()); - } - - // go through each process group if specified - if (snippet.getProcessGroups() != null) { - scrubProcessGroups(snippet.getProcessGroups()); - } - - // go through each controller service if specified - if (snippet.getControllerServices() != null) { - scrubControllerServices(snippet.getControllerServices()); - } - } - } - - /** - * Scrubs process groups prior to saving. - * - * @param processGroups groups - */ - private void scrubProcessGroups(final Set<ProcessGroupDTO> processGroups) { - // go through each process group - for (final ProcessGroupDTO processGroupDTO : processGroups) { - scrubTemplate(processGroupDTO.getContents()); - } - } - - /** - * Scrubs processors prior to saving. This includes removing sensitive properties, validation errors, property descriptors, etc. - * - * @param processors procs - */ - private void scrubProcessors(final Set<ProcessorDTO> processors) { - // go through each processor - for (final ProcessorDTO processorDTO : processors) { - final ProcessorConfigDTO processorConfig = processorDTO.getConfig(); - - // ensure that some property configuration have been specified - if (processorConfig != null) { - // if properties have been specified, remove sensitive ones - if (processorConfig.getProperties() != null) { - Map<String, String> processorProperties = processorConfig.getProperties(); - - // look for sensitive properties and remove them - if (processorConfig.getDescriptors() != null) { - final Collection<PropertyDescriptorDTO> descriptors = processorConfig.getDescriptors().values(); - for (PropertyDescriptorDTO descriptor : descriptors) { - if (descriptor.isSensitive()) { - processorProperties.put(descriptor.getName(), null); - } - } - } - } - - processorConfig.setCustomUiUrl(null); - } - - // remove validation errors - processorDTO.setValidationErrors(null); - processorDTO.setInputRequirement(null); - } - } - - private void scrubControllerServices(final Set<ControllerServiceDTO> controllerServices) { - for (final ControllerServiceDTO serviceDTO : controllerServices) { - final Map<String, String> properties = serviceDTO.getProperties(); - final Map<String, PropertyDescriptorDTO> descriptors = serviceDTO.getDescriptors(); - - if (properties != null && descriptors != null) { - for (final PropertyDescriptorDTO descriptor : descriptors.values()) { - if (descriptor.isSensitive()) { - properties.put(descriptor.getName(), null); - } - } - } - - serviceDTO.setCustomUiUrl(null); - serviceDTO.setValidationErrors(null); - } - } - - /** - * Scrubs connections prior to saving. This includes removing available relationships. - * - * @param connections conns - */ - private void scrubConnections(final Set<ConnectionDTO> connections) { - // go through each connection - for (final ConnectionDTO connectionDTO : connections) { - connectionDTO.setAvailableRelationships(null); - - scrubConnectable(connectionDTO.getSource()); - scrubConnectable(connectionDTO.getDestination()); - } - } - - /** - * Remove unnecessary fields in connectables prior to saving. - * - * @param connectable connectable - */ - private void scrubConnectable(final ConnectableDTO connectable) { - if (connectable != null) { - connectable.setComments(null); - connectable.setExists(null); - connectable.setRunning(null); - connectable.setTransmitting(null); - connectable.setName(null); - } - } - - /** - * Remove unnecessary fields in remote groups prior to saving. - * - * @param remoteGroups groups - */ - private void scrubRemoteProcessGroups(final Set<RemoteProcessGroupDTO> remoteGroups) { - // go through each remote process group - for (final RemoteProcessGroupDTO remoteProcessGroupDTO : remoteGroups) { - remoteProcessGroupDTO.setFlowRefreshed(null); - remoteProcessGroupDTO.setInputPortCount(null); - remoteProcessGroupDTO.setOutputPortCount(null); - remoteProcessGroupDTO.setTransmitting(null); - - // if this remote process group has contents - if (remoteProcessGroupDTO.getContents() != null) { - RemoteProcessGroupContentsDTO contents = remoteProcessGroupDTO.getContents(); - - // scrub any remote input ports - if (contents.getInputPorts() != null) { - scrubRemotePorts(contents.getInputPorts()); - } - - // scrub and remote output ports - if (contents.getOutputPorts() != null) { - scrubRemotePorts(contents.getOutputPorts()); - } - } - } - } - - /** - * Remove unnecessary fields in remote ports prior to saving. - * - * @param remotePorts ports - */ - private void scrubRemotePorts(final Set<RemoteProcessGroupPortDTO> remotePorts) { - for (final Iterator<RemoteProcessGroupPortDTO> remotePortIter = remotePorts.iterator(); remotePortIter.hasNext();) { - final RemoteProcessGroupPortDTO remotePortDTO = remotePortIter.next(); - - // if the flow is not connected to this remote port, remove it - if (remotePortDTO.isConnected() == null || !remotePortDTO.isConnected().booleanValue()) { - remotePortIter.remove(); - continue; - } - - remotePortDTO.setExists(null); - remotePortDTO.setTargetRunning(null); - } - } - - /** - * Removes the template with the given ID. - * - * @param id the ID of the template to remove - * @throws NullPointerException if the argument is null - * @throws IllegalStateException if no template exists with the given ID - * @throws IOException if template could not be removed - */ - public void removeTemplate(final String id) throws IOException, IllegalStateException { - writeLock.lock(); - try { - final Template removed = templateMap.remove(requireNonNull(id)); - - // ensure the template exists - if (removed == null) { - throw new IllegalStateException("No template with ID " + id + " exists"); - } else { - - try { - // remove the template from the archive directory - final Path path = directory.resolve(removed.getDetails().getId() + ".template"); - Files.delete(path); - } catch (final NoSuchFileException e) { - logger.warn(String.format("Template file for template %s not found when attempting to remove. Continuing...", id)); - } catch (final IOException e) { - logger.error(String.format("Unable to remove template file for template %s.", id)); - - // since the template file existed and we were unable to remove it, rollback - // by returning it to the template map - templateMap.put(id, removed); - - // rethrow - throw e; - } - } - } finally { - writeLock.unlock(); - } - } - - public Set<Template> getTemplates() { - readLock.lock(); - try { - return new HashSet<>(templateMap.values()); - } finally { - readLock.unlock(); - } - } - - public static List<Template> parseBytes(final byte[] bytes) { - final List<Template> templates = new ArrayList<>(); - - try (final InputStream rawIn = new ByteArrayInputStream(bytes); - final DataInputStream in = new DataInputStream(rawIn)) { - - while (isMoreData(in)) { - final int length = in.readInt(); - final byte[] buffer = new byte[length]; - StreamUtils.fillBuffer(in, buffer, true); - final TemplateDTO dto = TemplateDeserializer.deserialize(new ByteArrayInputStream(buffer)); - templates.add(new Template(dto)); - } - } catch (final IOException e) { - throw new RuntimeException("Could not parse bytes", e); // won't happen because of the types of streams being used - } - - return templates; - } - - private static boolean isMoreData(final InputStream in) throws IOException { - in.mark(1); - final int nextByte = in.read(); - if (nextByte == -1) { - return false; - } - - in.reset(); - return true; - } - - public byte[] export() { - readLock.lock(); - try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final DataOutputStream dos = new DataOutputStream(baos)) { - for (final Template template : templateMap.values()) { - final TemplateDTO dto = template.getDetails(); - final byte[] bytes = TemplateSerializer.serialize(dto); - dos.writeInt(bytes.length); - dos.write(bytes); - } - - return baos.toByteArray(); - } catch (final IOException e) { - // won't happen - return null; - } finally { - readLock.unlock(); - } - } -}
http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateUtils.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateUtils.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateUtils.java new file mode 100644 index 0000000..bcf692d --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/TemplateUtils.java @@ -0,0 +1,287 @@ +/* + * 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.controller; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.dom.DOMSource; + +import org.apache.nifi.persistence.TemplateDeserializer; +import org.apache.nifi.stream.io.ByteArrayInputStream; +import org.apache.nifi.stream.io.StreamUtils; +import org.apache.nifi.web.api.dto.ConnectableDTO; +import org.apache.nifi.web.api.dto.ConnectionDTO; +import org.apache.nifi.web.api.dto.ControllerServiceDTO; +import org.apache.nifi.web.api.dto.FlowSnippetDTO; +import org.apache.nifi.web.api.dto.ProcessGroupDTO; +import org.apache.nifi.web.api.dto.ProcessorConfigDTO; +import org.apache.nifi.web.api.dto.ProcessorDTO; +import org.apache.nifi.web.api.dto.PropertyDescriptorDTO; +import org.apache.nifi.web.api.dto.RemoteProcessGroupContentsDTO; +import org.apache.nifi.web.api.dto.RemoteProcessGroupDTO; +import org.apache.nifi.web.api.dto.RemoteProcessGroupPortDTO; +import org.apache.nifi.web.api.dto.TemplateDTO; +import org.w3c.dom.Element; + +public class TemplateUtils { + + public static TemplateDTO parseDto(final Element templateElement) { + try { + JAXBContext context = JAXBContext.newInstance(TemplateDTO.class); + Unmarshaller unmarshaller = context.createUnmarshaller(); + return unmarshaller.unmarshal(new DOMSource(templateElement), TemplateDTO.class).getValue(); + } catch (final Exception e) { + throw new RuntimeException("Could not parse XML as a valid template", e); + } + } + + public static TemplateDTO parseDto(final byte[] bytes) { + try (final InputStream in = new ByteArrayInputStream(bytes)) { + return TemplateDeserializer.deserialize(in); + } catch (final IOException ioe) { + throw new RuntimeException("Could not parse bytes as template", ioe); // won't happen because of the types of streams being used + } + } + + public static List<Template> parseTemplateStream(final byte[] bytes) { + final List<Template> templates = new ArrayList<>(); + + try (final InputStream rawIn = new ByteArrayInputStream(bytes); + final DataInputStream in = new DataInputStream(rawIn)) { + + while (isMoreData(in)) { + final int length = in.readInt(); + final byte[] buffer = new byte[length]; + StreamUtils.fillBuffer(in, buffer, true); + final TemplateDTO dto = TemplateDeserializer.deserialize(new ByteArrayInputStream(buffer)); + templates.add(new Template(dto)); + } + } catch (final IOException e) { + throw new RuntimeException("Could not parse bytes", e); // won't happen because of the types of streams being used + } + + return templates; + } + + + private static boolean isMoreData(final InputStream in) throws IOException { + in.mark(1); + final int nextByte = in.read(); + if (nextByte == -1) { + return false; + } + + in.reset(); + return true; + } + + /** + * Scrubs the template prior to persisting in order to remove fields that shouldn't be included or are unnecessary. + * + * @param templateDto template + */ + public static void scrubTemplate(final TemplateDTO templateDto) { + scrubSnippet(templateDto.getSnippet()); + } + + private static void scrubSnippet(final FlowSnippetDTO snippet) { + // ensure that contents have been specified + if (snippet != null) { + // go through each processor if specified + if (snippet.getProcessors() != null) { + scrubProcessors(snippet.getProcessors()); + } + + // go through each connection if specified + if (snippet.getConnections() != null) { + scrubConnections(snippet.getConnections()); + } + + // go through each remote process group if specified + if (snippet.getRemoteProcessGroups() != null) { + scrubRemoteProcessGroups(snippet.getRemoteProcessGroups()); + } + + // go through each process group if specified + if (snippet.getProcessGroups() != null) { + scrubProcessGroups(snippet.getProcessGroups()); + } + + // go through each controller service if specified + if (snippet.getControllerServices() != null) { + scrubControllerServices(snippet.getControllerServices()); + } + } + } + + /** + * Scrubs process groups prior to saving. + * + * @param processGroups groups + */ + private static void scrubProcessGroups(final Set<ProcessGroupDTO> processGroups) { + // go through each process group + for (final ProcessGroupDTO processGroupDTO : processGroups) { + scrubSnippet(processGroupDTO.getContents()); + } + } + + /** + * Scrubs processors prior to saving. This includes removing sensitive properties, validation errors, property descriptors, etc. + * + * @param processors procs + */ + private static void scrubProcessors(final Set<ProcessorDTO> processors) { + // go through each processor + for (final ProcessorDTO processorDTO : processors) { + final ProcessorConfigDTO processorConfig = processorDTO.getConfig(); + + // ensure that some property configuration have been specified + if (processorConfig != null) { + // if properties have been specified, remove sensitive ones + if (processorConfig.getProperties() != null) { + Map<String, String> processorProperties = processorConfig.getProperties(); + + // look for sensitive properties and remove them + if (processorConfig.getDescriptors() != null) { + final Collection<PropertyDescriptorDTO> descriptors = processorConfig.getDescriptors().values(); + for (PropertyDescriptorDTO descriptor : descriptors) { + if (descriptor.isSensitive()) { + processorProperties.put(descriptor.getName(), null); + } + } + } + } + + processorConfig.setCustomUiUrl(null); + } + + // remove validation errors + processorDTO.setValidationErrors(null); + processorDTO.setInputRequirement(null); + } + } + + private static void scrubControllerServices(final Set<ControllerServiceDTO> controllerServices) { + for (final ControllerServiceDTO serviceDTO : controllerServices) { + final Map<String, String> properties = serviceDTO.getProperties(); + final Map<String, PropertyDescriptorDTO> descriptors = serviceDTO.getDescriptors(); + + if (properties != null && descriptors != null) { + for (final PropertyDescriptorDTO descriptor : descriptors.values()) { + if (descriptor.isSensitive()) { + properties.put(descriptor.getName(), null); + } + } + } + + serviceDTO.setCustomUiUrl(null); + serviceDTO.setValidationErrors(null); + } + } + + /** + * Scrubs connections prior to saving. This includes removing available relationships. + * + * @param connections conns + */ + private static void scrubConnections(final Set<ConnectionDTO> connections) { + // go through each connection + for (final ConnectionDTO connectionDTO : connections) { + connectionDTO.setAvailableRelationships(null); + + scrubConnectable(connectionDTO.getSource()); + scrubConnectable(connectionDTO.getDestination()); + } + } + + /** + * Remove unnecessary fields in connectables prior to saving. + * + * @param connectable connectable + */ + private static void scrubConnectable(final ConnectableDTO connectable) { + if (connectable != null) { + connectable.setComments(null); + connectable.setExists(null); + connectable.setRunning(null); + connectable.setTransmitting(null); + connectable.setName(null); + } + } + + /** + * Remove unnecessary fields in remote groups prior to saving. + * + * @param remoteGroups groups + */ + private static void scrubRemoteProcessGroups(final Set<RemoteProcessGroupDTO> remoteGroups) { + // go through each remote process group + for (final RemoteProcessGroupDTO remoteProcessGroupDTO : remoteGroups) { + remoteProcessGroupDTO.setFlowRefreshed(null); + remoteProcessGroupDTO.setInputPortCount(null); + remoteProcessGroupDTO.setOutputPortCount(null); + remoteProcessGroupDTO.setTransmitting(null); + + // if this remote process group has contents + if (remoteProcessGroupDTO.getContents() != null) { + RemoteProcessGroupContentsDTO contents = remoteProcessGroupDTO.getContents(); + + // scrub any remote input ports + if (contents.getInputPorts() != null) { + scrubRemotePorts(contents.getInputPorts()); + } + + // scrub and remote output ports + if (contents.getOutputPorts() != null) { + scrubRemotePorts(contents.getOutputPorts()); + } + } + } + } + + /** + * Remove unnecessary fields in remote ports prior to saving. + * + * @param remotePorts ports + */ + private static void scrubRemotePorts(final Set<RemoteProcessGroupPortDTO> remotePorts) { + for (final Iterator<RemoteProcessGroupPortDTO> remotePortIter = remotePorts.iterator(); remotePortIter.hasNext();) { + final RemoteProcessGroupPortDTO remotePortDTO = remotePortIter.next(); + + // if the flow is not connected to this remote port, remove it + if (remotePortDTO.isConnected() == null || !remotePortDTO.isConnected().booleanValue()) { + remotePortIter.remove(); + continue; + } + + remotePortDTO.setExists(null); + remotePortDTO.setTargetRunning(null); + } + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java index e2ce751..4d0cd9d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java @@ -17,6 +17,8 @@ package org.apache.nifi.controller.serialization; import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.InputStream; import java.io.OutputStream; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -42,6 +44,7 @@ import org.apache.nifi.connectable.Size; import org.apache.nifi.controller.FlowController; import org.apache.nifi.controller.ProcessorNode; import org.apache.nifi.controller.ReportingTaskNode; +import org.apache.nifi.controller.Template; import org.apache.nifi.controller.label.Label; import org.apache.nifi.controller.service.ControllerServiceNode; import org.apache.nifi.controller.service.ControllerServiceState; @@ -49,12 +52,14 @@ import org.apache.nifi.encrypt.StringEncryptor; import org.apache.nifi.flowfile.FlowFilePrioritizer; import org.apache.nifi.groups.ProcessGroup; import org.apache.nifi.groups.RemoteProcessGroup; +import org.apache.nifi.persistence.TemplateSerializer; import org.apache.nifi.processor.Relationship; import org.apache.nifi.remote.RemoteGroupPort; import org.apache.nifi.remote.RootGroupPort; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; /** * Serializes a Flow Controller as XML to an output stream. @@ -186,6 +191,10 @@ public class StandardFlowSerializer implements FlowSerializer { for (final ControllerServiceNode service : group.getControllerServices(false)) { addControllerService(element, service); } + + for (final Template template : group.getTemplates()) { + addTemplate(element, template); + } } private void addStyle(final Element parentElement, final Map<String, String> style) { @@ -456,4 +465,21 @@ public class StandardFlowSerializer implements FlowSerializer { element.appendChild(toAdd); } + public static void addTemplate(final Element element, final Template template) { + try { + final byte[] serialized = TemplateSerializer.serialize(template.getDetails()); + + final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + final DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); + final Document document; + try (final InputStream in = new ByteArrayInputStream(serialized)) { + document = docBuilder.parse(in); + } + + final Node templateNode = element.getOwnerDocument().importNode(document.getDocumentElement(), true); + element.appendChild(templateNode); + } catch (final Exception e) { + throw new FlowSerializationException(e); + } + } } http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java index 5ede175..be58d22 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java @@ -39,6 +39,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; +import org.apache.commons.lang3.StringUtils; import org.apache.nifi.components.PropertyDescriptor; import org.apache.nifi.controller.FlowController; import org.apache.nifi.controller.Template; @@ -47,12 +48,12 @@ import org.apache.nifi.controller.serialization.FlowFromDOMFactory; import org.apache.nifi.encrypt.StringEncryptor; import org.apache.nifi.processor.Processor; import org.apache.nifi.util.DomUtils; +import org.apache.nifi.web.api.dto.ComponentDTO; import org.apache.nifi.web.api.dto.ConnectionDTO; import org.apache.nifi.web.api.dto.ControllerServiceDTO; 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.ComponentDTO; import org.apache.nifi.web.api.dto.PortDTO; import org.apache.nifi.web.api.dto.ProcessGroupDTO; import org.apache.nifi.web.api.dto.ProcessorConfigDTO; @@ -62,7 +63,6 @@ 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.TemplateDTO; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -311,6 +311,7 @@ public final class FingerprintFactory { private StringBuilder addTemplateFingerprint(final StringBuilder builder, final TemplateDTO dto) { builder.append(dto.getId()); + builder.append(dto.getGroupId()); builder.append(dto.getName()); builder.append(dto.getDescription()); final FlowSnippetDTO snippet = dto.getSnippet(); http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java index 8567c85..1a3ab52 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/groups/StandardProcessGroup.java @@ -41,6 +41,7 @@ import org.apache.nifi.controller.FlowController; import org.apache.nifi.controller.ProcessorNode; import org.apache.nifi.controller.ScheduledState; import org.apache.nifi.controller.Snippet; +import org.apache.nifi.controller.Template; import org.apache.nifi.controller.exception.ComponentLifeCycleException; import org.apache.nifi.controller.label.Label; import org.apache.nifi.controller.scheduling.StandardProcessScheduler; @@ -95,6 +96,7 @@ public final class StandardProcessGroup implements ProcessGroup { private final Map<String, ProcessorNode> processors = new HashMap<>(); private final Map<String, Funnel> funnels = new HashMap<>(); private final Map<String, ControllerServiceNode> controllerServices = new HashMap<>(); + private final Map<String, Template> templates = new HashMap<>(); private final StringEncryptor encryptor; private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock(); @@ -1883,6 +1885,99 @@ public final class StandardProcessGroup implements ProcessGroup { @Override + public void addTemplate(final Template template) { + requireNonNull(template); + + writeLock.lock(); + try { + final String id = template.getDetails().getId(); + if (id == null) { + throw new IllegalStateException("Cannot add template that has no ID"); + } + + if (templates.containsKey(id)) { + throw new IllegalStateException("Process Group already contains a Template with ID " + id); + } + + templates.put(id, template); + template.setProcessGroup(this); + LOG.info("{} added to {}", template, this); + } finally { + writeLock.unlock(); + } + } + + @Override + public Template getTemplate(final String id) { + readLock.lock(); + try { + return templates.get(id); + } finally { + readLock.unlock(); + } + } + + @Override + public Template findTemplate(final String id) { + return findTemplate(id, this); + } + + private Template findTemplate(final String id, final ProcessGroup start) { + final Template template = start.getTemplate(id); + if (template != null) { + return template; + } + + for (final ProcessGroup child : start.getProcessGroups()) { + final Template childTemplate = findTemplate(id, child); + if (childTemplate != null) { + return childTemplate; + } + } + + return null; + } + + @Override + public Set<Template> getTemplates() { + readLock.lock(); + try { + return new HashSet<>(templates.values()); + } finally { + readLock.unlock(); + } + } + + @Override + public Set<Template> findAllTemplates() { + return findAllTemplates(this); + } + + private Set<Template> findAllTemplates(final ProcessGroup group) { + final Set<Template> templates = new HashSet<>(group.getTemplates()); + for (final ProcessGroup childGroup : group.getProcessGroups()) { + templates.addAll(findAllTemplates(childGroup)); + } + return templates; + } + + @Override + public void removeTemplate(final Template template) { + writeLock.lock(); + try { + final Template existing = templates.get(requireNonNull(template).getIdentifier()); + if (existing == null) { + throw new IllegalStateException(template + " is not a member of this ProcessGroup"); + } + + templates.remove(template.getIdentifier()); + LOG.info("{} removed from flow", template); + } finally { + writeLock.unlock(); + } + } + + @Override public void remove(final Snippet snippet) { writeLock.lock(); try { http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateSerializer.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateSerializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateSerializer.java index 72d7f56..7c9d9e6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateSerializer.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateSerializer.java @@ -44,4 +44,5 @@ public final class TemplateSerializer { throw new FlowSerializationException(e); } } + } http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java index 15efd86..771bda6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/StandardFlowServiceTest.java @@ -80,7 +80,7 @@ public class StandardFlowServiceTest { @Test public void testLoadWithFlow() throws IOException { byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml")); - flowService.load(new StandardDataFlow(flowBytes, null, null)); + flowService.load(new StandardDataFlow(flowBytes, null)); FlowSerializer serializer = new StandardFlowSerializer(mockEncryptor); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -95,16 +95,16 @@ public class StandardFlowServiceTest { @Test(expected = FlowSerializationException.class) public void testLoadWithCorruptFlow() throws IOException { byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-corrupt.xml")); - flowService.load(new StandardDataFlow(flowBytes, null, null)); + flowService.load(new StandardDataFlow(flowBytes, null)); } @Test public void testLoadExistingFlow() throws IOException { byte[] flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml")); - flowService.load(new StandardDataFlow(flowBytes, null, null)); + flowService.load(new StandardDataFlow(flowBytes, null)); flowBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-inheritable.xml")); - flowService.load(new StandardDataFlow(flowBytes, null, null)); + flowService.load(new StandardDataFlow(flowBytes, null)); FlowSerializer serializer = new StandardFlowSerializer(mockEncryptor); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -118,11 +118,11 @@ public class StandardFlowServiceTest { @Test public void testLoadExistingFlowWithUninheritableFlow() throws IOException { byte[] originalBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml")); - flowService.load(new StandardDataFlow(originalBytes, null, null)); + flowService.load(new StandardDataFlow(originalBytes, null)); try { byte[] updatedBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-uninheritable.xml")); - flowService.load(new StandardDataFlow(updatedBytes, null, null)); + flowService.load(new StandardDataFlow(updatedBytes, null)); fail("should have thrown " + UninheritableFlowException.class); } catch (UninheritableFlowException ufe) { @@ -140,11 +140,11 @@ public class StandardFlowServiceTest { @Test public void testLoadExistingFlowWithCorruptFlow() throws IOException { byte[] originalBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow.xml")); - flowService.load(new StandardDataFlow(originalBytes, null, null)); + flowService.load(new StandardDataFlow(originalBytes, null)); try { byte[] updatedBytes = IOUtils.toByteArray(StandardFlowServiceTest.class.getResourceAsStream("/conf/all-flow-corrupt.xml")); - flowService.load(new StandardDataFlow(updatedBytes, null, null)); + flowService.load(new StandardDataFlow(updatedBytes, null)); fail("should have thrown " + FlowSerializationException.class); } catch (FlowSerializationException ufe) { http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/mock/MockProcessGroup.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/mock/MockProcessGroup.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/mock/MockProcessGroup.java index 98e2571..11724f4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/mock/MockProcessGroup.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/service/mock/MockProcessGroup.java @@ -32,6 +32,7 @@ import org.apache.nifi.connectable.Port; import org.apache.nifi.connectable.Position; import org.apache.nifi.controller.ProcessorNode; import org.apache.nifi.controller.Snippet; +import org.apache.nifi.controller.Template; import org.apache.nifi.controller.label.Label; import org.apache.nifi.controller.service.ControllerServiceNode; import org.apache.nifi.groups.ProcessGroup; @@ -527,4 +528,33 @@ public class MockProcessGroup implements ProcessGroup { } + @Override + public void addTemplate(Template template) { + throw new UnsupportedOperationException(); + } + + @Override + public void removeTemplate(Template template) { + } + + @Override + public Template getTemplate(String id) { + return null; + } + + @Override + public Template findTemplate(String id) { + return null; + } + + @Override + public Set<Template> getTemplates() { + return null; + } + + @Override + public Set<Template> findAllTemplates() { + return null; + } + } http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java index 47d0594..ecd6195 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java @@ -304,17 +304,20 @@ public interface NiFiServiceFacade { * @param name name * @param description description * @param snippetId id + * @param groupId id of the process group * @return template */ - TemplateDTO createTemplate(String name, String description, String snippetId); + TemplateDTO createTemplate(String name, String description, String snippetId, String groupId); /** * Imports the specified Template. * * @param templateDTO The template dto + * @param groupId id of the process group + * * @return The new template dto */ - TemplateDTO importTemplate(TemplateDTO templateDTO); + TemplateDTO importTemplate(TemplateDTO templateDTO, String groupId); /** * Instantiate the corresponding template. http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index 4ba8b33..ace31a3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -16,8 +16,31 @@ */ package org.apache.nifi.web; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +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.Set; +import java.util.TimeZone; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import javax.ws.rs.WebApplicationException; + import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; import org.apache.nifi.action.Action; import org.apache.nifi.action.Component; import org.apache.nifi.action.FlowChangeAction; @@ -166,35 +189,14 @@ 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 javax.ws.rs.WebApplicationException; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -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.Set; -import java.util.TimeZone; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Implementation of NiFiServiceFacade that performs revision checking. */ public class StandardNiFiServiceFacade implements NiFiServiceFacade { - private static final Logger logger = Logger.getLogger(StandardNiFiServiceFacade.class); + private static final Logger logger = LoggerFactory.getLogger(StandardNiFiServiceFacade.class); // nifi core components private ControllerFacade controllerFacade; @@ -258,136 +260,236 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public void verifyUpdateConnection(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(connectionDTO.getId()); + throw e; } } @Override public void verifyDeleteConnection(String connectionId) { - connectionDAO.verifyDelete(connectionId); + try { + connectionDAO.verifyDelete(connectionId); + } catch (final Exception e) { + revisionManager.cancelClaim(connectionId); + throw e; + } } @Override public void verifyDeleteFunnel(String funnelId) { - funnelDAO.verifyDelete(funnelId); + try { + funnelDAO.verifyDelete(funnelId); + } catch (final Exception e) { + revisionManager.cancelClaim(funnelId); + throw e; + } } @Override public void verifyUpdateInputPort(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(inputPortDTO.getId()); + throw e; } } @Override public void verifyDeleteInputPort(String inputPortId) { - inputPortDAO.verifyDelete(inputPortId); + try { + inputPortDAO.verifyDelete(inputPortId); + } catch (final Exception e) { + revisionManager.cancelClaim(inputPortId); + throw e; + } } @Override public void verifyUpdateOutputPort(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(outputPortDTO.getId()); + throw e; } } @Override public void verifyDeleteOutputPort(String outputPortId) { - outputPortDAO.verifyDelete(outputPortId); + try { + outputPortDAO.verifyDelete(outputPortId); + } catch (final Exception e) { + revisionManager.cancelClaim(outputPortId); + throw e; + } } @Override public void verifyUpdateProcessor(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(processorDTO.getId()); + throw e; } } @Override public void verifyDeleteProcessor(String processorId) { - processorDAO.verifyDelete(processorId); + try { + processorDAO.verifyDelete(processorId); + } catch (final Exception e) { + revisionManager.cancelClaim(processorId); + throw e; + } } @Override public void verifyUpdateProcessGroup(ProcessGroupDTO processGroupDTO) { - // if group does not exist, then the update request is likely creating it - // so we don't verify since it will fail - if (processGroupDAO.hasProcessGroup(processGroupDTO.getId())) { - processGroupDAO.verifyUpdate(processGroupDTO); + try { + // if group does not exist, then the update request is likely creating it + // so we don't verify since it will fail + if (processGroupDAO.hasProcessGroup(processGroupDTO.getId())) { + processGroupDAO.verifyUpdate(processGroupDTO); + } + } catch (final Exception e) { + revisionManager.cancelClaim(processGroupDTO.getId()); + throw e; } } @Override public void verifyDeleteProcessGroup(String groupId) { - processGroupDAO.verifyDelete(groupId); + try { + processGroupDAO.verifyDelete(groupId); + } catch (final Exception e) { + revisionManager.cancelClaim(groupId); + throw e; + } } @Override public void verifyUpdateRemoteProcessGroup(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(remoteProcessGroupDTO.getId()); + throw e; } } @Override public void verifyUpdateRemoteProcessGroupInputPort(String remoteProcessGroupId, RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) { - remoteProcessGroupDAO.verifyUpdateInputPort(remoteProcessGroupId, remoteProcessGroupPortDTO); + try { + remoteProcessGroupDAO.verifyUpdateInputPort(remoteProcessGroupId, remoteProcessGroupPortDTO); + } catch (final Exception e) { + revisionManager.cancelClaim(remoteProcessGroupId); + throw e; + } } @Override public void verifyUpdateRemoteProcessGroupOutputPort(String remoteProcessGroupId, RemoteProcessGroupPortDTO remoteProcessGroupPortDTO) { - remoteProcessGroupDAO.verifyUpdateOutputPort(remoteProcessGroupId, remoteProcessGroupPortDTO); + try { + remoteProcessGroupDAO.verifyUpdateOutputPort(remoteProcessGroupId, remoteProcessGroupPortDTO); + } catch (final Exception e) { + revisionManager.cancelClaim(remoteProcessGroupId); + throw e; + } } @Override public void verifyDeleteRemoteProcessGroup(String remoteProcessGroupId) { - remoteProcessGroupDAO.verifyDelete(remoteProcessGroupId); + try { + remoteProcessGroupDAO.verifyDelete(remoteProcessGroupId); + } catch (final Exception e) { + revisionManager.cancelClaim(remoteProcessGroupId); + throw e; + } } @Override public void verifyUpdateControllerService(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(controllerServiceDTO.getId()); + throw e; } } @Override public void verifyUpdateControllerServiceReferencingComponents(String controllerServiceId, ScheduledState scheduledState, ControllerServiceState controllerServiceState) { - controllerServiceDAO.verifyUpdateReferencingComponents(controllerServiceId, scheduledState, controllerServiceState); + try { + controllerServiceDAO.verifyUpdateReferencingComponents(controllerServiceId, scheduledState, controllerServiceState); + } catch (final Exception e) { + revisionManager.cancelClaim(controllerServiceId); + throw e; + } } @Override public void verifyDeleteControllerService(String controllerServiceId) { - controllerServiceDAO.verifyDelete(controllerServiceId); + try { + controllerServiceDAO.verifyDelete(controllerServiceId); + } catch (final Exception e) { + revisionManager.cancelClaim(controllerServiceId); + throw e; + } } @Override public void verifyUpdateReportingTask(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); + try { + // 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); + } + } catch (final Exception e) { + revisionManager.cancelClaim(reportingTaskDTO.getId()); + throw e; } } @Override public void verifyDeleteReportingTask(String reportingTaskId) { - reportingTaskDAO.verifyDelete(reportingTaskId); + try { + reportingTaskDAO.verifyDelete(reportingTaskId); + } catch (final Exception e) { + revisionManager.cancelClaim(reportingTaskId); + throw e; + } } // ----------------------------------------- @@ -515,10 +617,15 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public void verifyUpdateSnippet(SnippetDTO snippetDto) { - // 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.verifyUpdate(snippetDto); + try { + // 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.verifyUpdate(snippetDto); + } + } catch (final Exception e) { + revisionManager.cancelClaim(snippetDto.getId()); + throw e; } } @@ -843,7 +950,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public void verifyCanClearProcessorState(final String processorId) { - processorDAO.verifyClearState(processorId); + try { + processorDAO.verifyClearState(processorId); + } catch (final Exception e) { + revisionManager.cancelClaim(processorId); + throw e; + } } @Override @@ -874,7 +986,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public void verifyCanClearControllerServiceState(final String controllerServiceId) { - controllerServiceDAO.verifyClearState(controllerServiceId); + try { + controllerServiceDAO.verifyClearState(controllerServiceId); + } catch (final Exception e) { + revisionManager.cancelClaim(controllerServiceId); + throw e; + } } @Override @@ -884,7 +1001,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public void verifyCanClearReportingTaskState(final String reportingTaskId) { - reportingTaskDAO.verifyClearState(reportingTaskId); + try { + reportingTaskDAO.verifyClearState(reportingTaskId); + } catch (final Exception e) { + revisionManager.cancelClaim(reportingTaskId); + throw e; + } } @Override @@ -978,6 +1100,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { return revisionManager.deleteRevision(claim, new DeleteRevisionTask<D>() { @Override public D performTask() { + logger.debug("Attempting to delete component {} with claim {}", authorizable, claim); + // ensure access to the component authorizable.authorize(authorizer, RequestAction.WRITE); @@ -985,6 +1109,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { // save the flow controllerFacade.save(); + logger.debug("Deletion of component {} was successful", authorizable); return dto; } @@ -993,7 +1118,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { @Override public void verifyDeleteSnippet(String id) { - snippetDAO.verifyDelete(id); + try { + snippetDAO.verifyDelete(id); + } catch (final Exception e) { + revisionManager.cancelClaim(id); + throw e; + } } @Override @@ -1394,7 +1524,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public TemplateDTO createTemplate(String name, String description, String snippetId) { + public TemplateDTO createTemplate(String name, String description, String snippetId, String groupId) { // get the specified snippet Snippet snippet = snippetDAO.getSnippet(snippetId); @@ -1409,27 +1539,31 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { final ClusterContext clusterContext = ClusterContextThreadLocal.getContext(); if (clusterContext != null) { templateDTO.setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString()); + } else { + templateDTO.setId(UUID.randomUUID().toString()); } // create the template - Template template = templateDAO.createTemplate(templateDTO); + Template template = templateDAO.createTemplate(templateDTO, groupId); return dtoFactory.createTemplateDTO(template); } @Override - public TemplateDTO importTemplate(TemplateDTO templateDTO) { + public TemplateDTO importTemplate(TemplateDTO templateDTO, String groupId) { // ensure id is set final ClusterContext clusterContext = ClusterContextThreadLocal.getContext(); if (clusterContext != null) { templateDTO.setId(UUID.nameUUIDFromBytes(clusterContext.getIdGenerationSeed().getBytes(StandardCharsets.UTF_8)).toString()); + } else { + templateDTO.setId(UUID.randomUUID().toString()); } // mark the timestamp templateDTO.setTimestamp(new Date()); // import the template - final Template template = templateDAO.importTemplate(templateDTO); + final Template template = templateDAO.importTemplate(templateDTO, groupId); // return the template dto return dtoFactory.createTemplateDTO(template); http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java index c835254..955d0bb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java @@ -96,6 +96,7 @@ import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -2187,7 +2188,8 @@ public class ProcessGroupResource extends ApplicationResource { // create the template and generate the json final RevisionDTO revisionDTO = createTemplateRequestEntity.getRevision(); - final TemplateDTO template = serviceFacade.createTemplate(createTemplateRequestEntity.getName(), createTemplateRequestEntity.getDescription(), createTemplateRequestEntity.getSnippetId()); + final TemplateDTO template = serviceFacade.createTemplate(createTemplateRequestEntity.getName(), createTemplateRequestEntity.getDescription(), + createTemplateRequestEntity.getSnippetId(), groupId); templateResource.populateRemainingTemplateContent(template); // create the revision @@ -2320,7 +2322,7 @@ public class ProcessGroupResource extends ApplicationResource { } // import the template - final TemplateDTO template = serviceFacade.importTemplate(templateEntity.getTemplate()); + final TemplateDTO template = serviceFacade.importTemplate(templateEntity.getTemplate(), groupId); templateResource.populateRemainingTemplateContent(template); // create the revision @@ -2502,6 +2504,11 @@ public class ProcessGroupResource extends ApplicationResource { // replicate if cluster manager if (properties.isClusterManager() && Availability.NODE.equals(avail)) { return clusterManager.applyRequest(HttpMethod.GET, getAbsolutePath(), getRequestParameters(true), getHeaders()).getResponse(); + } else if (properties.isClusterManager()) { + // create the response entity + final ControllerServicesEntity entity = new ControllerServicesEntity(); + entity.setControllerServices(Collections.emptySet()); + return clusterContext(generateOkResponse(entity)).build(); } // get all the controller services http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java index e0cc08b..6356a18 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java @@ -46,6 +46,8 @@ import org.apache.nifi.web.api.entity.ProcessorEntity; import org.apache.nifi.web.api.entity.PropertyDescriptorEntity; import org.apache.nifi.web.api.request.ClientIdParameter; import org.apache.nifi.web.api.request.LongParameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; @@ -77,6 +79,7 @@ import java.util.Set; description = "Endpoint for managing a Processor." ) public class ProcessorResource extends ApplicationResource { + private static final Logger logger = LoggerFactory.getLogger(ProcessorResource.class); private static final List<Long> POSSIBLE_RUN_DURATIONS = Arrays.asList(0L, 25L, 50L, 100L, 250L, 500L, 1000L, 2000L); @@ -481,16 +484,32 @@ public class ProcessorResource extends ApplicationResource { // handle expects request (usually from the cluster manager) final Revision revision = getRevision(processorEntity, id); final boolean validationPhase = isValidationPhase(httpServletRequest); - if (validationPhase || !isTwoPhaseRequest(httpServletRequest)) { + final boolean twoPhaseRequest = isTwoPhaseRequest(httpServletRequest); + final String requestId = getHeaders().get("X-RequestTransactionId"); + + logger.debug("For Update Processor, Validation Phase = {}, Two-phase request = {}, Request ID = {}", validationPhase, twoPhaseRequest, requestId); + if (validationPhase || !twoPhaseRequest) { serviceFacade.claimRevision(revision); + logger.debug("Claimed Revision {}", revision); } if (validationPhase) { serviceFacade.verifyUpdateProcessor(requestProcessorDTO); + logger.debug("Verified Update of Processor"); return generateContinueResponse().build(); } // update the processor - final UpdateResult<ProcessorEntity> result = serviceFacade.updateProcessor(revision, requestProcessorDTO); + final UpdateResult<ProcessorEntity> result; + try { + logger.debug("Updating Processor with Revision {}", revision); + result = serviceFacade.updateProcessor(revision, requestProcessorDTO); + logger.debug("Updated Processor with Revision {}", revision); + } catch (final Exception e) { + final boolean tpr = isTwoPhaseRequest(httpServletRequest); + logger.error("Got Exception trying to update processor. two-phase request = {}, validation phase = {}, revision = {}", tpr, validationPhase, revision); + logger.error("", e); + throw e; + } final ProcessorEntity entity = result.getResult(); populateRemainingProcessorEntityContent(entity); http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/IllegalArgumentExceptionMapper.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/IllegalArgumentExceptionMapper.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/IllegalArgumentExceptionMapper.java index a152775..e9edd8f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/IllegalArgumentExceptionMapper.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/config/IllegalArgumentExceptionMapper.java @@ -35,10 +35,7 @@ public class IllegalArgumentExceptionMapper implements ExceptionMapper<IllegalAr public Response toResponse(IllegalArgumentException exception) { // log the error logger.info(String.format("%s. Returning %s response.", exception, Response.Status.BAD_REQUEST)); - - if (logger.isDebugEnabled()) { - logger.debug(StringUtils.EMPTY, exception); - } + logger.debug(StringUtils.EMPTY, exception); return Response.status(Response.Status.BAD_REQUEST).entity(exception.getMessage()).type("text/plain").build(); } http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java index 29858b9..82a79b9 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/controller/ControllerFacade.java @@ -780,7 +780,7 @@ public class ControllerFacade implements Authorizable { } // add each template - for (final Template template : flowController.getTemplates()) { + for (final Template template : root.findAllTemplates()) { final TemplateDTO details = template.getDetails(); resources.add(ResourceFactory.getComponentResource(ResourceType.Template, details.getId(), details.getName())); } http://git-wip-us.apache.org/repos/asf/nifi/blob/270944ec/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java index 13fe66d..02e8f0a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/dao/TemplateDAO.java @@ -28,17 +28,19 @@ public interface TemplateDAO { * Creates a template. * * @param templateDTO The template DTO + * @param groupId the ID of the group to add the template to * @return The template */ - Template createTemplate(TemplateDTO templateDTO); + Template createTemplate(TemplateDTO templateDTO, String groupId); /** * Import the specified template. * * @param templateDTO dto + * @param groupId the ID of the group to add the template to * @return template */ - Template importTemplate(TemplateDTO templateDTO); + Template importTemplate(TemplateDTO templateDTO, String groupId); /** * Instantiate the corresponding template.
