http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateAuthorizable.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateAuthorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateAuthorizable.java deleted file mode 100644 index 17a8896..0000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateAuthorizable.java +++ /dev/null @@ -1,48 +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.authorization; - -import org.apache.nifi.authorization.resource.Authorizable; - -import java.util.Set; - -/** - * Authorizable for a Template. - */ -public interface TemplateAuthorizable { - /** - * Returns the authorizable for this template. Non null - * - * @return authorizable - */ - Authorizable getAuthorizable(); - - /** - * Returns temporary instances of all encapsulated processors. Non null - * - * @return temporary instances of all encapsulated processors - */ - Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors(); - - /** - * Returns temporary instances of all encapsulated controller services. Non null - * - * @return temporary instances of all encapsulated controller services - */ - Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices(); - -}
http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateContentsAuthorizable.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateContentsAuthorizable.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateContentsAuthorizable.java new file mode 100644 index 0000000..7222765 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/TemplateContentsAuthorizable.java @@ -0,0 +1,39 @@ +/* + * 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.authorization; + +import java.util.Set; + +/** + * Authorizable for a Template. + */ +public interface TemplateContentsAuthorizable { + /** + * Returns temporary instances of all encapsulated processors. Non null + * + * @return temporary instances of all encapsulated processors + */ + Set<ConfigurableComponentAuthorizable> getEncapsulatedProcessors(); + + /** + * Returns temporary instances of all encapsulated controller services. Non null + * + * @return temporary instances of all encapsulated controller services + */ + Set<ConfigurableComponentAuthorizable> getEncapsulatedControllerServices(); + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/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 1a72127..039cbf8 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 @@ -153,6 +153,8 @@ public interface NiFiServiceFacade { */ Set<Revision> getRevisionsFromSnippet(String snippetId); + + // ---------------------------------------- // Controller methods // ---------------------------------------- @@ -328,24 +330,37 @@ public interface NiFiServiceFacade { /** * Returns the list of processor types. * - * @return The list of available processor types + * @param bundleGroupFilter if specified, must be member of bundle group + * @param bundleArtifactFilter if specified, must be member of bundle artifact + * @param typeFilter if specified, type must match + * @return The list of available processor types matching specified criteria */ - Set<DocumentedTypeDTO> getProcessorTypes(); + Set<DocumentedTypeDTO> getProcessorTypes(final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter); /** * Returns the list of controller service types. * * @param serviceType Filters only service types that implement this type - * @return The list of available controller types + * @param serviceBundleGroup if serviceType specified, the bundle group of the serviceType + * @param serviceBundleArtifact if serviceType specified, the bundle artifact of the serviceType + * @param serviceBundleVersion if serviceType specified, the bundle version of the serviceType + * @param bundleGroupFilter if specified, must be member of bundle group + * @param bundleArtifactFilter if specified, must be member of bundle artifact + * @param typeFilter if specified, type must match + * @return The list of available controller types matching specified criteria */ - Set<DocumentedTypeDTO> getControllerServiceTypes(String serviceType); + Set<DocumentedTypeDTO> getControllerServiceTypes(final String serviceType, final String serviceBundleGroup, final String serviceBundleArtifact, final String serviceBundleVersion, + final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter); /** * Returns the list of reporting task types. * - * @return The list of available reporting task types + * @param bundleGroupFilter if specified, must be member of bundle group + * @param bundleArtifactFilter if specified, must be member of bundle artifact + * @param typeFilter if specified, type must match + * @return The list of available reporting task types matching specified criteria */ - Set<DocumentedTypeDTO> getReportingTaskTypes(); + Set<DocumentedTypeDTO> getReportingTaskTypes(final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter); /** * Returns the list of prioritizer types. @@ -400,13 +415,14 @@ public interface NiFiServiceFacade { * Instantiate the corresponding template. * * @param groupId group id - * @param templateId template id * @param originX x * @param originY y + * @param templateEncodingVersion template encoding version + * @param snippet template snippet * @param idGenerationSeed the ID to use for generating UUID's. May be null. * @return snapshot */ - FlowEntity createTemplateInstance(String groupId, Double originX, Double originY, String templateId, String idGenerationSeed); + FlowEntity createTemplateInstance(String groupId, Double originX, Double originY, String templateEncodingVersion, FlowSnippetDTO snippet, String idGenerationSeed); /** * Gets the template with the specified id. @@ -441,6 +457,14 @@ public interface NiFiServiceFacade { // ---------------------------------------- // Processor methods // ---------------------------------------- + + /** + * Verifies the specified processor can be created. + * + * @param processorDTO processor + */ + void verifyCreateProcessor(ProcessorDTO processorDTO); + /** * Creates a new Processor. * @@ -1321,6 +1345,14 @@ public interface NiFiServiceFacade { // ---------------------------------------- // Controller Services methods // ---------------------------------------- + + /** + * Verifies the specified controller service can be created. + * + * @param controllerServiceDTO service + */ + void verifyCreateControllerService(ControllerServiceDTO controllerServiceDTO); + /** * Creates a controller service. * @@ -1420,6 +1452,14 @@ public interface NiFiServiceFacade { // ---------------------------------------- // Reporting Task methods // ---------------------------------------- + + /** + * Verifies the specified reporting task can be created. + * + * @param reportingTaskDTO task + */ + void verifyCreateReportingTask(ReportingTaskDTO reportingTaskDTO); + /** * Creates a reporting task. * http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/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 cc472b8..1f8fd92 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 @@ -396,11 +396,18 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @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); } } @@ -444,11 +451,18 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @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); } } @@ -463,11 +477,18 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @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); } } @@ -1657,7 +1678,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } try { - final ControllerService controllerService = controllerFacade.createTemporaryControllerService(dto.getType()).getControllerServiceImplementation(); + final ControllerService controllerService = controllerFacade.createTemporaryControllerService(dto.getType(), dto.getBundle()).getControllerServiceImplementation(); controllerService.getPropertyDescriptors().forEach(descriptor -> { if (dto.getProperties().get(descriptor.getName()) == null) { dto.getProperties().put(descriptor.getName(), descriptor.getDefaultValue()); @@ -1681,7 +1702,7 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } try { - final ProcessorNode processorNode = controllerFacade.createTemporaryProcessor(dto.getType()); + final ProcessorNode processorNode = controllerFacade.createTemporaryProcessor(dto.getType(), dto.getBundle()); processorNode.getPropertyDescriptors().forEach(descriptor -> { if (config.getProperties().get(descriptor.getName()) == null) { config.getProperties().put(descriptor.getName(), descriptor.getDefaultValue()); @@ -1774,10 +1795,12 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public FlowEntity createTemplateInstance(final String groupId, final Double originX, final Double originY, final String templateId, final String idGenerationSeed) { + 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, templateId, idGenerationSeed); + final FlowSnippetDTO snippet = templateDAO.instantiateTemplate(groupId, originX, originY, templateEncodingVersion, requestSnippet, idGenerationSeed); // save the flow controllerFacade.save(); @@ -2365,18 +2388,19 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade { } @Override - public Set<DocumentedTypeDTO> getProcessorTypes() { - return controllerFacade.getFlowFileProcessorTypes(); + 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) { - return controllerFacade.getControllerServiceTypes(serviceType); + 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() { - return controllerFacade.getReportingTaskTypes(); + public Set<DocumentedTypeDTO> getReportingTaskTypes(final String bundleGroup, final String bundleArtifact, final String type) { + return controllerFacade.getReportingTaskTypes(bundleGroup, bundleArtifact, type); } @Override http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.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/ApplicationResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java index 79ddc81..c159273 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ApplicationResource.java @@ -662,6 +662,11 @@ public abstract class ApplicationResource { // authorize access serviceFacade.authorizeAccess(authorizer); + // verify if necessary + if (verifier != null) { + verifier.run(); + } + // run the action return action.apply(entity); } http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.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/ControllerResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java index 1e56dbb..63f7c18 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java @@ -295,16 +295,24 @@ public class ControllerResource extends ApplicationResource { lookup -> { authorizeController(RequestAction.WRITE); - final ConfigurableComponentAuthorizable authorizable = lookup.getReportingTaskByType(requestReportingTask.getType()); - if (authorizable.isRestricted()) { - lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); - } - - if (requestReportingTask.getProperties() != null) { - AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestReportingTask.getProperties(), authorizable, authorizer, lookup); + ConfigurableComponentAuthorizable authorizable = null; + try { + authorizable = lookup.getReportingTaskByType(requestReportingTask.getType(), requestReportingTask.getBundle()); + + if (authorizable.isRestricted()) { + lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); + } + + if (requestReportingTask.getProperties() != null) { + AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestReportingTask.getProperties(), authorizable, authorizer, lookup); + } + } finally { + if (authorizable != null) { + authorizable.cleanUpResources(); + } } }, - null, + () -> serviceFacade.verifyCreateReportingTask(requestReportingTask), (reportingTaskEntity) -> { final ReportingTaskDTO reportingTask = reportingTaskEntity.getComponent(); @@ -393,16 +401,24 @@ public class ControllerResource extends ApplicationResource { lookup -> { authorizeController(RequestAction.WRITE); - final ConfigurableComponentAuthorizable authorizable = lookup.getControllerServiceByType(requestControllerService.getType()); - if (authorizable.isRestricted()) { - lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); - } - - if (requestControllerService.getProperties() != null) { - AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup); + ConfigurableComponentAuthorizable authorizable = null; + try { + authorizable = lookup.getControllerServiceByType(requestControllerService.getType(), requestControllerService.getBundle()); + + if (authorizable.isRestricted()) { + lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); + } + + if (requestControllerService.getProperties() != null) { + AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup); + } + } finally { + if (authorizable != null) { + authorizable.cleanUpResources(); + } } }, - null, + () -> serviceFacade.verifyCreateControllerService(requestControllerService), (controllerServiceEntity) -> { final ControllerServiceDTO controllerService = controllerServiceEntity.getComponent(); @@ -561,7 +577,7 @@ public class ControllerResource extends ApplicationResource { ) @PathParam("id") String id, @ApiParam( - value = "The node configuration. The only configuration that will be honored at this endpoint is the status or primary flag.", + value = "The node configuration. The only configuration that will be honored at this endpoint is the status.", required = true ) NodeEntity nodeEntity) { http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.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/ControllerServiceResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java index 26ebd2b..46e95f1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java @@ -36,6 +36,7 @@ import org.apache.nifi.ui.extension.UiExtensionMapping; import org.apache.nifi.web.NiFiServiceFacade; import org.apache.nifi.web.Revision; import org.apache.nifi.web.UiExtensionType; +import org.apache.nifi.web.api.dto.BundleDTO; import org.apache.nifi.web.api.dto.ComponentStateDTO; import org.apache.nifi.web.api.dto.ControllerServiceDTO; import org.apache.nifi.web.api.dto.PropertyDescriptorDTO; @@ -124,10 +125,12 @@ public class ControllerServiceResource extends ApplicationResource { * Populates the uri for the specified controller service. */ public ControllerServiceDTO populateRemainingControllerServiceContent(final ControllerServiceDTO controllerService) { + final BundleDTO bundle = controllerService.getBundle(); + // see if this processor has any ui extensions final UiExtensionMapping uiExtensionMapping = (UiExtensionMapping) servletContext.getAttribute("nifi-ui-extensions"); - if (uiExtensionMapping.hasUiExtension(controllerService.getType())) { - final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(controllerService.getType()); + if (uiExtensionMapping.hasUiExtension(controllerService.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion())) { + final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(controllerService.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion()); for (final UiExtension uiExtension : uiExtensions) { if (UiExtensionType.ControllerServiceConfiguration.equals(uiExtension.getExtensionType())) { controllerService.setCustomUiUrl(uiExtension.getContextPath() + "/configure"); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.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/FlowResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java index a031725..bc45118 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/FlowResource.java @@ -35,12 +35,15 @@ import org.apache.nifi.authorization.resource.Authorizable; 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.bundle.Bundle; +import org.apache.nifi.bundle.BundleDetails; import org.apache.nifi.cluster.coordination.ClusterCoordinator; import org.apache.nifi.cluster.coordination.node.NodeConnectionState; import org.apache.nifi.cluster.manager.NodeResponse; import org.apache.nifi.cluster.protocol.NodeIdentifier; import org.apache.nifi.controller.ScheduledState; import org.apache.nifi.groups.ProcessGroup; +import org.apache.nifi.nar.NarClassLoaders; import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.web.IllegalClusterResourceRequestException; import org.apache.nifi.web.NiFiServiceFacade; @@ -925,12 +928,32 @@ public class FlowResource extends ApplicationResource { @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") } ) - public Response getProcessorTypes() throws InterruptedException { + public Response getProcessorTypes( + @ApiParam( + value = "If specified, will only return types that are a member of this bundle group.", + required = false + ) + @QueryParam("bundleGroupFilter") String bundleGroupFilter, + @ApiParam( + value = "If specified, will only return types that are a member of this bundle artifact.", + required = false + ) + @QueryParam("bundleArtifactFilter") String bundleArtifactFilter, + @ApiParam( + value = "If specified, will only return types whose fully qualified classname matches.", + required = false + ) + @QueryParam("type") String typeFilter) throws InterruptedException { + authorizeFlow(); + if (isReplicateRequest()) { + return replicate(HttpMethod.GET); + } + // create response entity final ProcessorTypesEntity entity = new ProcessorTypesEntity(); - entity.setProcessorTypes(serviceFacade.getProcessorTypes()); + entity.setProcessorTypes(serviceFacade.getProcessorTypes(bundleGroupFilter, bundleArtifactFilter, typeFilter)); // generate the response return clusterContext(generateOkResponse(entity)).build(); @@ -965,16 +988,57 @@ public class FlowResource extends ApplicationResource { ) public Response getControllerServiceTypes( @ApiParam( - value = "If specified, will only return controller services of this type.", + value = "If specified, will only return controller services that are compatible with this type of service.", + required = false + ) + @QueryParam("serviceType") String serviceType, + @ApiParam( + value = "If serviceType specified, is the bundle group of the serviceType.", + required = false + ) + @QueryParam("serviceBundleGroup") String serviceBundleGroup, + @ApiParam( + value = "If serviceType specified, is the bundle artifact of the serviceType.", required = false ) - @QueryParam("serviceType") String serviceType) throws InterruptedException { + @QueryParam("serviceBundleArtifact") String serviceBundleArtifact, + @ApiParam( + value = "If serviceType specified, is the bundle version of the serviceType.", + required = false + ) + @QueryParam("serviceBundleVersion") String serviceBundleVersion, + @ApiParam( + value = "If specified, will only return types that are a member of this bundle group.", + required = false + ) + @QueryParam("bundleGroupFilter") String bundleGroupFilter, + @ApiParam( + value = "If specified, will only return types that are a member of this bundle artifact.", + required = false + ) + @QueryParam("bundleArtifactFilter") String bundleArtifactFilter, + @ApiParam( + value = "If specified, will only return types whose fully qualified classname matches.", + required = false + ) + @QueryParam("typeFilter") String typeFilter) throws InterruptedException { authorizeFlow(); + if (serviceType != null) { + if (serviceBundleGroup == null || serviceBundleArtifact == null || serviceBundleVersion == null) { + throw new IllegalArgumentException("When specifying the serviceType the serviceBundleGroup, serviceBundleArtifact, and serviceBundleVersion must be specified."); + } + } + + if (isReplicateRequest()) { + return replicate(HttpMethod.GET); + } + // create response entity final ControllerServiceTypesEntity entity = new ControllerServiceTypesEntity(); - entity.setControllerServiceTypes(serviceFacade.getControllerServiceTypes(serviceType)); + entity.setControllerServiceTypes(serviceFacade.getControllerServiceTypes(serviceType, serviceBundleGroup, serviceBundleArtifact, serviceBundleVersion, + bundleGroupFilter, bundleArtifactFilter, typeFilter)); // generate the response return clusterContext(generateOkResponse(entity)).build(); @@ -1006,12 +1070,32 @@ public class FlowResource extends ApplicationResource { @ApiResponse(code = 409, message = "The request was valid but NiFi was not in the appropriate state to process it. Retrying the same request later may be successful.") } ) - public Response getReportingTaskTypes() throws InterruptedException { + public Response getReportingTaskTypes( + @ApiParam( + value = "If specified, will only return types that are a member of this bundle group.", + required = false + ) + @QueryParam("bundleGroupFilter") String bundleGroupFilter, + @ApiParam( + value = "If specified, will only return types that are a member of this bundle artifact.", + required = false + ) + @QueryParam("bundleArtifactFilter") String bundleArtifactFilter, + @ApiParam( + value = "If specified, will only return types whose fully qualified classname matches.", + required = false + ) + @QueryParam("type") String typeFilter) throws InterruptedException { + authorizeFlow(); + if (isReplicateRequest()) { + return replicate(HttpMethod.GET); + } + // create response entity final ReportingTaskTypesEntity entity = new ReportingTaskTypesEntity(); - entity.setReportingTaskTypes(serviceFacade.getReportingTaskTypes()); + entity.setReportingTaskTypes(serviceFacade.getReportingTaskTypes(bundleGroupFilter, bundleArtifactFilter, typeFilter)); // generate the response return clusterContext(generateOkResponse(entity)).build(); @@ -1046,6 +1130,10 @@ public class FlowResource extends ApplicationResource { public Response getPrioritizers() throws InterruptedException { authorizeFlow(); + if (isReplicateRequest()) { + return replicate(HttpMethod.GET); + } + // create response entity final PrioritizerTypesEntity entity = new PrioritizerTypesEntity(); entity.setPrioritizerTypes(serviceFacade.getWorkQueuePrioritizerTypes()); @@ -1084,7 +1172,6 @@ public class FlowResource extends ApplicationResource { // create the about dto final AboutDTO aboutDTO = new AboutDTO(); aboutDTO.setTitle("NiFi"); - aboutDTO.setVersion(getProperties().getUiTitle()); aboutDTO.setUri(generateResourceUri()); aboutDTO.setTimezone(new Date()); @@ -1092,11 +1179,19 @@ public class FlowResource extends ApplicationResource { final NiFiProperties properties = getProperties(); aboutDTO.setContentViewerUrl(properties.getProperty(NiFiProperties.CONTENT_VIEWER_URL)); - // Get build info - aboutDTO.setBuildTag(properties.getProperty(NiFiProperties.BUILD_TAG)); - aboutDTO.setBuildRevision(properties.getProperty(NiFiProperties.BUILD_REVISION)); - aboutDTO.setBuildBranch(properties.getProperty(NiFiProperties.BUILD_BRANCH)); - aboutDTO.setBuildTimestamp(properties.getBuildTimestamp()); + final Bundle frameworkBundle = NarClassLoaders.getInstance().getFrameworkBundle(); + if (frameworkBundle != null) { + final BundleDetails frameworkDetails = frameworkBundle.getBundleDetails(); + + // set the version + aboutDTO.setVersion(frameworkDetails.getCoordinate().getVersion()); + + // Get build info + aboutDTO.setBuildTag(frameworkDetails.getBuildTag()); + aboutDTO.setBuildRevision(frameworkDetails.getBuildRevision()); + aboutDTO.setBuildBranch(frameworkDetails.getBuildBranch()); + aboutDTO.setBuildTimestamp(frameworkDetails.getBuildTimestampDate()); + } // create the response entity final AboutEntity entity = new AboutEntity(); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/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 58c9e30..ffcc084 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 @@ -32,17 +32,22 @@ import org.apache.nifi.authorization.ConfigurableComponentAuthorizable; import org.apache.nifi.authorization.ProcessGroupAuthorizable; import org.apache.nifi.authorization.RequestAction; import org.apache.nifi.authorization.SnippetAuthorizable; -import org.apache.nifi.authorization.TemplateAuthorizable; +import org.apache.nifi.authorization.TemplateContentsAuthorizable; import org.apache.nifi.authorization.resource.Authorizable; import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.authorization.user.NiFiUserUtils; +import org.apache.nifi.bundle.BundleCoordinate; import org.apache.nifi.connectable.ConnectableType; +import org.apache.nifi.controller.serialization.FlowEncodingVersion; import org.apache.nifi.remote.util.SiteToSiteRestApiClient; +import org.apache.nifi.util.BundleUtils; import org.apache.nifi.web.NiFiServiceFacade; import org.apache.nifi.web.ResourceNotFoundException; import org.apache.nifi.web.Revision; +import org.apache.nifi.web.api.dto.BundleDTO; 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.PositionDTO; import org.apache.nifi.web.api.dto.ProcessGroupDTO; import org.apache.nifi.web.api.dto.ProcessorConfigDTO; @@ -652,17 +657,25 @@ public class ProcessGroupResource extends ApplicationResource { final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable(); processGroup.authorize(authorizer, RequestAction.WRITE, user); - final ConfigurableComponentAuthorizable authorizable = lookup.getProcessorByType(requestProcessor.getType()); - if (authorizable.isRestricted()) { - lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user); - } + ConfigurableComponentAuthorizable authorizable = null; + try { + authorizable = lookup.getProcessorByType(requestProcessor.getType(), requestProcessor.getBundle()); + + if (authorizable.isRestricted()) { + lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user); + } - final ProcessorConfigDTO config = requestProcessor.getConfig(); - if (config != null && config.getProperties() != null) { - AuthorizeControllerServiceReference.authorizeControllerServiceReferences(config.getProperties(), authorizable, authorizer, lookup); + final ProcessorConfigDTO config = requestProcessor.getConfig(); + if (config != null && config.getProperties() != null) { + AuthorizeControllerServiceReference.authorizeControllerServiceReferences(config.getProperties(), authorizable, authorizer, lookup); + } + } finally { + if (authorizable != null) { + authorizable.cleanUpResources(); + } } }, - null, + () -> serviceFacade.verifyCreateProcessor(requestProcessor), processorEntity -> { final ProcessorDTO processor = processorEntity.getComponent(); @@ -1835,6 +1848,33 @@ public class ProcessGroupResource extends ApplicationResource { // ----------------- /** + * Discovers the compatible bundle details for the components in the specified snippet. + * + * @param snippet the snippet + */ + private void discoverCompatibleBundles(final FlowSnippetDTO snippet) { + if (snippet.getProcessors() != null) { + snippet.getProcessors().forEach(processor -> { + final BundleCoordinate coordinate = BundleUtils.getCompatibleBundle(processor.getType(), processor.getBundle()); + processor.setBundle(new BundleDTO(coordinate.getGroup(), coordinate.getId(), coordinate.getVersion())); + }); + } + + if (snippet.getControllerServices() != null) { + snippet.getControllerServices().forEach(controllerService -> { + final BundleCoordinate coordinate = BundleUtils.getCompatibleBundle(controllerService.getType(), controllerService.getBundle()); + controllerService.setBundle(new BundleDTO(coordinate.getGroup(), coordinate.getId(), coordinate.getVersion())); + }); + } + + if (snippet.getProcessGroups() != null) { + snippet.getProcessGroups().forEach(processGroup -> { + discoverCompatibleBundles(processGroup.getContents()); + }); + } + } + + /** * Instantiates the specified template within this ProcessGroup. The template instance that is instantiated cannot be referenced at a later time, therefore there is no * corresponding URI. Instead the request URI is returned. * <p> @@ -1881,7 +1921,43 @@ public class ProcessGroupResource extends ApplicationResource { // ensure the position has been specified if (requestInstantiateTemplateRequestEntity == null || requestInstantiateTemplateRequestEntity.getOriginX() == null || requestInstantiateTemplateRequestEntity.getOriginY() == null) { - throw new IllegalArgumentException("The origin position (x, y) must be specified"); + throw new IllegalArgumentException("The origin position (x, y) must be specified."); + } + + // ensure the template id was provided + if (requestInstantiateTemplateRequestEntity.getTemplateId() == null) { + throw new IllegalArgumentException("The template id must be specified."); + } + + // ensure the template encoding version is valid + if (requestInstantiateTemplateRequestEntity.getEncodingVersion() != null) { + try { + FlowEncodingVersion.parse(requestInstantiateTemplateRequestEntity.getEncodingVersion()); + } catch (final IllegalArgumentException e) { + throw new IllegalArgumentException("The template encoding version is not valid. The expected format is <number>.<number>"); + } + } + + // populate the encoding version if necessary + if (requestInstantiateTemplateRequestEntity.getEncodingVersion() == null) { + // if the encoding version is not specified, use the latest encoding version as these options were + // not available pre 1.x, will be overridden if populating from the underlying template below + requestInstantiateTemplateRequestEntity.setEncodingVersion(TemplateDTO.MAX_ENCODING_VERSION); + } + + // populate the component bundles if necessary + if (requestInstantiateTemplateRequestEntity.getSnippet() == null) { + // get the desired template in order to determine the supported bundles + final TemplateDTO requestedTemplate = serviceFacade.exportTemplate(requestInstantiateTemplateRequestEntity.getTemplateId()); + final FlowSnippetDTO requestTemplateContents = requestedTemplate.getSnippet(); + + // determine the compatible bundles to use for each component in this template, this ensures the nodes in the cluster + // instantiate the components from the same bundles + discoverCompatibleBundles(requestTemplateContents); + + // update the requested template as necessary - use the encoding version from the underlying template + requestInstantiateTemplateRequestEntity.setEncodingVersion(requestedTemplate.getEncodingVersion()); + requestInstantiateTemplateRequestEntity.setSnippet(requestTemplateContents); } if (isReplicateRequest()) { @@ -1898,9 +1974,11 @@ public class ProcessGroupResource extends ApplicationResource { final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable(); processGroup.authorize(authorizer, RequestAction.WRITE, user); + final Authorizable template = lookup.getTemplate(requestInstantiateTemplateRequestEntity.getTemplateId()); + template.authorize(authorizer, RequestAction.READ, user); + // ensure read on the template - final TemplateAuthorizable template = lookup.getTemplate(requestInstantiateTemplateRequestEntity.getTemplateId()); - template.getAuthorizable().authorize(authorizer, RequestAction.READ, user); + final TemplateContentsAuthorizable templateContents = lookup.getTemplateContents(requestInstantiateTemplateRequestEntity.getSnippet()); // flag to only perform the restricted check once, atomic reference so we can mark final and use in lambda final AtomicBoolean restrictedCheckPerformed = new AtomicBoolean(false); @@ -1911,14 +1989,14 @@ public class ProcessGroupResource extends ApplicationResource { }; // ensure restricted access if necessary - template.getEncapsulatedProcessors().forEach(authorizeRestricted); - template.getEncapsulatedControllerServices().forEach(authorizeRestricted); + templateContents.getEncapsulatedProcessors().forEach(authorizeRestricted); + templateContents.getEncapsulatedControllerServices().forEach(authorizeRestricted); }, - null, + () -> serviceFacade.verifyComponentTypes(requestInstantiateTemplateRequestEntity.getSnippet()), instantiateTemplateRequestEntity -> { // create the template and generate the json - final FlowEntity entity = serviceFacade.createTemplateInstance(groupId, instantiateTemplateRequestEntity.getOriginX(), - instantiateTemplateRequestEntity.getOriginY(), instantiateTemplateRequestEntity.getTemplateId(), getIdGenerationSeed().orElse(null)); + final FlowEntity entity = serviceFacade.createTemplateInstance(groupId, instantiateTemplateRequestEntity.getOriginX(), instantiateTemplateRequestEntity.getOriginY(), + instantiateTemplateRequestEntity.getEncodingVersion(), instantiateTemplateRequestEntity.getSnippet(), getIdGenerationSeed().orElse(null)); final FlowDTO flowSnippet = entity.getFlow(); @@ -2161,10 +2239,7 @@ public class ProcessGroupResource extends ApplicationResource { final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable(); processGroup.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); }, - () -> { - serviceFacade.verifyCanAddTemplate(groupId, requestTemplateEntity.getTemplate().getName()); - serviceFacade.verifyComponentTypes(requestTemplateEntity.getTemplate().getSnippet()); - }, + () -> serviceFacade.verifyCanAddTemplate(groupId, requestTemplateEntity.getTemplate().getName()), templateEntity -> { try { // import the template @@ -2272,16 +2347,24 @@ public class ProcessGroupResource extends ApplicationResource { final Authorizable processGroup = lookup.getProcessGroup(groupId).getAuthorizable(); processGroup.authorize(authorizer, RequestAction.WRITE, user); - final ConfigurableComponentAuthorizable authorizable = lookup.getControllerServiceByType(requestControllerService.getType()); - if (authorizable.isRestricted()) { - lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user); - } + ConfigurableComponentAuthorizable authorizable = null; + try { + authorizable = lookup.getControllerServiceByType(requestControllerService.getType(), requestControllerService.getBundle()); + + if (authorizable.isRestricted()) { + lookup.getRestrictedComponents().authorize(authorizer, RequestAction.WRITE, user); + } - if (requestControllerService.getProperties() != null) { - AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup); + if (requestControllerService.getProperties() != null) { + AuthorizeControllerServiceReference.authorizeControllerServiceReferences(requestControllerService.getProperties(), authorizable, authorizer, lookup); + } + } finally { + if (authorizable != null) { + authorizable.cleanUpResources(); + } } }, - null, + () -> serviceFacade.verifyCreateControllerService(requestControllerService), controllerServiceEntity -> { final ControllerServiceDTO controllerService = controllerServiceEntity.getComponent(); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/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 1238e64..204d57b 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 @@ -35,6 +35,7 @@ import org.apache.nifi.ui.extension.UiExtensionMapping; import org.apache.nifi.web.NiFiServiceFacade; import org.apache.nifi.web.Revision; import org.apache.nifi.web.UiExtensionType; +import org.apache.nifi.web.api.dto.BundleDTO; import org.apache.nifi.web.api.dto.ComponentStateDTO; import org.apache.nifi.web.api.dto.PositionDTO; import org.apache.nifi.web.api.dto.ProcessorConfigDTO; @@ -121,10 +122,12 @@ public class ProcessorResource extends ApplicationResource { if (StringUtils.isNotBlank(customUiUrl)) { config.setCustomUiUrl(customUiUrl); } else { + final BundleDTO bundle = processor.getBundle(); + // see if this processor has any ui extensions final UiExtensionMapping uiExtensionMapping = (UiExtensionMapping) servletContext.getAttribute("nifi-ui-extensions"); - if (uiExtensionMapping.hasUiExtension(processor.getType())) { - final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(processor.getType()); + if (uiExtensionMapping.hasUiExtension(processor.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion())) { + final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(processor.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion()); for (final UiExtension uiExtension : uiExtensions) { if (UiExtensionType.ProcessorConfiguration.equals(uiExtension.getExtensionType())) { config.setCustomUiUrl(uiExtension.getContextPath() + "/configure"); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.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/ReportingTaskResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java index 39c75f9..c62d24d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java @@ -34,6 +34,7 @@ import org.apache.nifi.ui.extension.UiExtensionMapping; import org.apache.nifi.web.NiFiServiceFacade; import org.apache.nifi.web.Revision; import org.apache.nifi.web.UiExtensionType; +import org.apache.nifi.web.api.dto.BundleDTO; import org.apache.nifi.web.api.dto.ComponentStateDTO; import org.apache.nifi.web.api.dto.PropertyDescriptorDTO; import org.apache.nifi.web.api.dto.ReportingTaskDTO; @@ -111,10 +112,12 @@ public class ReportingTaskResource extends ApplicationResource { * Populates the uri for the specified reporting task. */ public ReportingTaskDTO populateRemainingReportingTaskContent(final ReportingTaskDTO reportingTask) { + final BundleDTO bundle = reportingTask.getBundle(); + // see if this processor has any ui extensions final UiExtensionMapping uiExtensionMapping = (UiExtensionMapping) servletContext.getAttribute("nifi-ui-extensions"); - if (uiExtensionMapping.hasUiExtension(reportingTask.getType())) { - final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(reportingTask.getType()); + if (uiExtensionMapping.hasUiExtension(reportingTask.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion())) { + final List<UiExtension> uiExtensions = uiExtensionMapping.getUiExtension(reportingTask.getType(), bundle.getGroup(), bundle.getArtifact(), bundle.getVersion()); for (final UiExtension uiExtension : uiExtensions) { if (UiExtensionType.ReportingTaskConfiguration.equals(uiExtension.getExtensionType())) { reportingTask.setCustomUiUrl(uiExtension.getContextPath() + "/configure"); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.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/TemplateResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java index 515ade6..52b31a5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/TemplateResource.java @@ -122,7 +122,7 @@ public class TemplateResource extends ApplicationResource { // authorize access serviceFacade.authorizeAccess(lookup -> { - final Authorizable template = lookup.getTemplate(id).getAuthorizable(); + final Authorizable template = lookup.getTemplate(id); template.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser()); }); @@ -197,7 +197,7 @@ public class TemplateResource extends ApplicationResource { serviceFacade, requestTemplateEntity, lookup -> { - final Authorizable template = lookup.getTemplate(id).getAuthorizable(); + final Authorizable template = lookup.getTemplate(id); // ensure write permission to the template template.authorize(authorizer, RequestAction.WRITE, NiFiUserUtils.getNiFiUser()); http://git-wip-us.apache.org/repos/asf/nifi/blob/d90cf846/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.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/dto/DtoFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java index 4e238d2..aaa33d0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/dto/DtoFactory.java @@ -16,33 +16,8 @@ */ package org.apache.nifi.web.api.dto; -import java.text.Collator; -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.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TimeZone; -import java.util.TreeMap; -import java.util.TreeSet; -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.ClassUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.nifi.action.Action; import org.apache.nifi.action.component.details.ComponentDetails; import org.apache.nifi.action.component.details.ExtensionDetails; @@ -72,6 +47,9 @@ import org.apache.nifi.authorization.User; import org.apache.nifi.authorization.resource.Authorizable; import org.apache.nifi.authorization.resource.ComponentAuthorizable; import org.apache.nifi.authorization.user.NiFiUserUtils; +import org.apache.nifi.bundle.Bundle; +import org.apache.nifi.bundle.BundleCoordinate; +import org.apache.nifi.bundle.BundleDetails; import org.apache.nifi.cluster.coordination.heartbeat.NodeHeartbeat; import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus; import org.apache.nifi.cluster.event.NodeEvent; @@ -122,6 +100,8 @@ 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.nar.ExtensionManager; +import org.apache.nifi.nar.NarClassLoaders; import org.apache.nifi.processor.Processor; import org.apache.nifi.processor.Relationship; import org.apache.nifi.provenance.lineage.ComputeLineageResult; @@ -137,7 +117,6 @@ import org.apache.nifi.reporting.ReportingTask; import org.apache.nifi.scheduling.SchedulingStrategy; import org.apache.nifi.util.FormatUtils; import org.apache.nifi.util.NiFiProperties; -import org.apache.nifi.util.StringUtils; import org.apache.nifi.web.FlowModification; import org.apache.nifi.web.Revision; import org.apache.nifi.web.api.dto.action.ActionDTO; @@ -184,6 +163,32 @@ import org.apache.nifi.web.api.entity.TenantEntity; import org.apache.nifi.web.controller.ControllerFacade; import org.apache.nifi.web.revision.RevisionManager; +import javax.ws.rs.WebApplicationException; +import java.text.Collator; +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.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.TreeSet; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; + public final class DtoFactory { @SuppressWarnings("rawtypes") @@ -1230,10 +1235,17 @@ public final class DtoFactory { } public ReportingTaskDTO createReportingTaskDto(final ReportingTaskNode reportingTaskNode) { + final BundleCoordinate bundleCoordinate = reportingTaskNode.getBundleCoordinate(); + final List<Bundle> compatibleBundles = ExtensionManager.getBundles(reportingTaskNode.getCanonicalClassName()).stream().filter(bundle -> { + final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate(); + return bundleCoordinate.getGroup().equals(coordinate.getGroup()) && bundleCoordinate.getId().equals(coordinate.getId()); + }).collect(Collectors.toList()); + final ReportingTaskDTO dto = new ReportingTaskDTO(); dto.setId(reportingTaskNode.getIdentifier()); dto.setName(reportingTaskNode.getName()); dto.setType(reportingTaskNode.getCanonicalClassName()); + dto.setBundle(createBundleDto(bundleCoordinate)); dto.setSchedulingStrategy(reportingTaskNode.getSchedulingStrategy().name()); dto.setSchedulingPeriod(reportingTaskNode.getSchedulingPeriod()); dto.setState(reportingTaskNode.getScheduledState().name()); @@ -1242,6 +1254,8 @@ public final class DtoFactory { dto.setComments(reportingTaskNode.getComments()); dto.setPersistsState(reportingTaskNode.getReportingTask().getClass().isAnnotationPresent(Stateful.class)); dto.setRestricted(reportingTaskNode.isRestricted()); + dto.setExtensionMissing(reportingTaskNode.isExtensionMissing()); + dto.setMultipleVersionsAvailable(compatibleBundles.size() > 1); final Map<String, String> defaultSchedulingPeriod = new HashMap<>(); defaultSchedulingPeriod.put(SchedulingStrategy.TIMER_DRIVEN.name(), SchedulingStrategy.TIMER_DRIVEN.getDefaultSchedulingPeriod()); @@ -1302,16 +1316,26 @@ public final class DtoFactory { } public ControllerServiceDTO createControllerServiceDto(final ControllerServiceNode controllerServiceNode) { + final BundleCoordinate bundleCoordinate = controllerServiceNode.getBundleCoordinate(); + final List<Bundle> compatibleBundles = ExtensionManager.getBundles(controllerServiceNode.getCanonicalClassName()).stream().filter(bundle -> { + final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate(); + return bundleCoordinate.getGroup().equals(coordinate.getGroup()) && bundleCoordinate.getId().equals(coordinate.getId()); + }).collect(Collectors.toList()); + final ControllerServiceDTO dto = new ControllerServiceDTO(); dto.setId(controllerServiceNode.getIdentifier()); dto.setParentGroupId(controllerServiceNode.getProcessGroup() == null ? null : controllerServiceNode.getProcessGroup().getIdentifier()); dto.setName(controllerServiceNode.getName()); dto.setType(controllerServiceNode.getCanonicalClassName()); + dto.setBundle(createBundleDto(bundleCoordinate)); + dto.setControllerServiceApis(createControllerServiceApiDto(controllerServiceNode.getControllerServiceImplementation().getClass())); dto.setState(controllerServiceNode.getState().name()); dto.setAnnotationData(controllerServiceNode.getAnnotationData()); dto.setComments(controllerServiceNode.getComments()); dto.setPersistsState(controllerServiceNode.getControllerServiceImplementation().getClass().isAnnotationPresent(Stateful.class)); dto.setRestricted(controllerServiceNode.isRestricted()); + dto.setExtensionMissing(controllerServiceNode.isExtensionMissing()); + dto.setMultipleVersionsAvailable(compatibleBundles.size() > 1); // sort a copy of the properties final Map<PropertyDescriptor, String> sortedProperties = new TreeMap<>(new Comparator<PropertyDescriptor>() { @@ -2056,30 +2080,109 @@ public final class DtoFactory { } /** + * Creates a bundle DTO from the specified class. + * + * @param coordinate bundle coordinates + * @return dto + */ + public BundleDTO createBundleDto(final BundleCoordinate coordinate) { + final BundleDTO dto = new BundleDTO(); + dto.setGroup(coordinate.getGroup()); + dto.setArtifact(coordinate.getId()); + dto.setVersion(coordinate.getVersion()); + return dto; + } + + private List<ControllerServiceApiDTO> createControllerServiceApiDto(final Class cls) { + final Set<Class> serviceApis = new HashSet<>(); + + // if this is a controller service + if (ControllerService.class.isAssignableFrom(cls)) { + // get all of it's interfaces to determine the controller service api's it implements + final List<Class<?>> interfaces = ClassUtils.getAllInterfaces(cls); + for (final Class i : interfaces) { + // add all controller services that's not ControllerService itself + if (ControllerService.class.isAssignableFrom(i) && !ControllerService.class.equals(i)) { + serviceApis.add(i); + } + } + + final List<ControllerServiceApiDTO> dtos = new ArrayList<>(); + for (final Class serviceApi : serviceApis) { + final Bundle bundle = ExtensionManager.getBundle(serviceApi.getClassLoader()); + final BundleCoordinate bundleCoordinate = bundle.getBundleDetails().getCoordinate(); + + final ControllerServiceApiDTO dto = new ControllerServiceApiDTO(); + dto.setType(serviceApi.getName()); + dto.setBundle(createBundleDto(bundleCoordinate)); + dtos.add(dto); + } + return dtos; + } else { + return null; + } + } + + /** * Gets the DocumentedTypeDTOs from the specified classes. * * @param classes classes + * @param bundleGroupFilter if specified, must be member of bundle group + * @param bundleArtifactFilter if specified, must be member of bundle artifact + * @param typeFilter if specified, type must match * @return dtos */ - @SuppressWarnings("rawtypes") - public Set<DocumentedTypeDTO> fromDocumentedTypes(final Set<Class> classes) { + public Set<DocumentedTypeDTO> fromDocumentedTypes(final Map<Class, Bundle> classes, final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter) { final Set<DocumentedTypeDTO> types = new LinkedHashSet<>(); - final Set<Class> sortedClasses = new TreeSet<>(CLASS_NAME_COMPARATOR); - sortedClasses.addAll(classes); + final List<Class> sortedClasses = new ArrayList<>(classes.keySet()); + Collections.sort(sortedClasses, CLASS_NAME_COMPARATOR); - for (final Class<?> cls : sortedClasses) { - final DocumentedTypeDTO type = new DocumentedTypeDTO(); - type.setType(cls.getName()); - type.setDescription(getCapabilityDescription(cls)); - type.setUsageRestriction(getUsageRestriction(cls)); - type.setTags(getTags(cls)); - types.add(type); + for (final Class cls : sortedClasses) { + final Bundle bundle = classes.get(cls); + final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate(); + + // only include classes that meet the criteria if specified + if (bundleGroupFilter != null && !bundleGroupFilter.equals(coordinate.getGroup())) { + continue; + } + if (bundleArtifactFilter != null && !bundleArtifactFilter.equals(coordinate.getId())) { + continue; + } + if (typeFilter != null && !typeFilter.equals(cls.getName())) { + continue; + } + + final DocumentedTypeDTO dto = new DocumentedTypeDTO(); + dto.setType(cls.getName()); + dto.setBundle(createBundleDto(coordinate)); + dto.setControllerServiceApis(createControllerServiceApiDto(cls)); + dto.setDescription(getCapabilityDescription(cls)); + dto.setUsageRestriction(getUsageRestriction(cls)); + dto.setTags(getTags(cls)); + types.add(dto); } return types; } /** + * Gets the DocumentedTypeDTOs from the specified classes. + * + * @param classes classes + * @param bundleGroupFilter if specified, must be member of bundle group + * @param bundleArtifactFilter if specified, must be member of bundle artifact + * @param typeFilter if specified, type must match + * @return dtos + */ + public Set<DocumentedTypeDTO> fromDocumentedTypes(final Set<Class> classes, final String bundleGroupFilter, final String bundleArtifactFilter, final String typeFilter) { + final Map<Class, Bundle> classBundles = new HashMap<>(); + for (final Class cls : classes) { + classBundles.put(cls, ExtensionManager.getBundle(cls.getClassLoader())); + } + return fromDocumentedTypes(classBundles, bundleGroupFilter, bundleArtifactFilter, typeFilter); + } + + /** * Creates a ProcessorDTO from the specified ProcessorNode. * * @param node node @@ -2090,6 +2193,12 @@ public final class DtoFactory { return null; } + final BundleCoordinate bundleCoordinate = node.getBundleCoordinate(); + final List<Bundle> compatibleBundles = ExtensionManager.getBundles(node.getCanonicalClassName()).stream().filter(bundle -> { + final BundleCoordinate coordinate = bundle.getBundleDetails().getCoordinate(); + return bundleCoordinate.getGroup().equals(coordinate.getGroup()) && bundleCoordinate.getId().equals(coordinate.getId()); + }).collect(Collectors.toList()); + final ProcessorDTO dto = new ProcessorDTO(); dto.setId(node.getIdentifier()); dto.setPosition(createPositionDto(node.getPosition())); @@ -2098,8 +2207,11 @@ public final class DtoFactory { dto.setInputRequirement(node.getInputRequirement().name()); dto.setPersistsState(node.getProcessor().getClass().isAnnotationPresent(Stateful.class)); dto.setRestricted(node.isRestricted()); + dto.setExtensionMissing(node.isExtensionMissing()); + dto.setMultipleVersionsAvailable(compatibleBundles.size() > 1); dto.setType(node.getCanonicalClassName()); + dto.setBundle(createBundleDto(bundleCoordinate)); dto.setName(node.getName()); dto.setState(node.getScheduledState().toString()); @@ -2466,16 +2578,25 @@ public final class DtoFactory { public SystemDiagnosticsSnapshotDTO.VersionInfoDTO createVersionInfoDTO() { final SystemDiagnosticsSnapshotDTO.VersionInfoDTO dto = new SystemDiagnosticsSnapshotDTO.VersionInfoDTO(); - dto.setNiFiVersion(properties.getUiTitle()); dto.setJavaVendor(System.getProperty("java.vendor")); dto.setJavaVersion(System.getProperty("java.version")); dto.setOsName(System.getProperty("os.name")); dto.setOsVersion(System.getProperty("os.version")); dto.setOsArchitecture(System.getProperty("os.arch")); - dto.setBuildTag(properties.getProperty(NiFiProperties.BUILD_TAG)); - dto.setBuildRevision(properties.getProperty(NiFiProperties.BUILD_REVISION)); - dto.setBuildBranch(properties.getProperty(NiFiProperties.BUILD_BRANCH)); - dto.setBuildTimestamp(properties.getBuildTimestamp()); + + final Bundle frameworkBundle = NarClassLoaders.getInstance().getFrameworkBundle(); + if (frameworkBundle != null) { + final BundleDetails frameworkDetails = frameworkBundle.getBundleDetails(); + + dto.setNiFiVersion(frameworkDetails.getCoordinate().getVersion()); + + // Get build info + dto.setBuildTag(frameworkDetails.getBuildTag()); + dto.setBuildRevision(frameworkDetails.getBuildRevision()); + dto.setBuildBranch(frameworkDetails.getBuildBranch()); + dto.setBuildTimestamp(frameworkDetails.getBuildTimestampDate()); + } + return dto; } @@ -2598,7 +2719,11 @@ public final class DtoFactory { // set the identifies controller service is applicable if (propertyDescriptor.getControllerServiceDefinition() != null) { - dto.setIdentifiesControllerService(propertyDescriptor.getControllerServiceDefinition().getName()); + final Class serviceClass = propertyDescriptor.getControllerServiceDefinition(); + final Bundle serviceBundle = ExtensionManager.getBundle(serviceClass.getClassLoader()); + + dto.setIdentifiesControllerService(serviceClass.getName()); + dto.setIdentifiesControllerServiceBundle(createBundleDto(serviceBundle.getBundleDetails().getCoordinate())); } final Class<? extends ControllerService> serviceDefinition = propertyDescriptor.getControllerServiceDefinition(); @@ -2654,6 +2779,7 @@ public final class DtoFactory { public ControllerServiceDTO copy(final ControllerServiceDTO original) { final ControllerServiceDTO copy = new ControllerServiceDTO(); copy.setAnnotationData(original.getAnnotationData()); + copy.setControllerServiceApis(original.getControllerServiceApis()); copy.setComments(original.getComments()); copy.setCustomUiUrl(original.getCustomUiUrl()); copy.setDescriptors(copy(original.getDescriptors())); @@ -2664,6 +2790,10 @@ public final class DtoFactory { copy.setReferencingComponents(copy(original.getReferencingComponents())); copy.setState(original.getState()); copy.setType(original.getType()); + copy.setBundle(copy(original.getBundle())); + copy.setExtensionMissing(original.getExtensionMissing()); + copy.setMultipleVersionsAvailable(original.getMultipleVersionsAvailable()); + copy.setPersistsState(original.getPersistsState()); copy.setValidationErrors(copy(original.getValidationErrors())); return copy; } @@ -2709,6 +2839,18 @@ public final class DtoFactory { } } + public BundleDTO copy(final BundleDTO original) { + if (original == null) { + return null; + } + + final BundleDTO copy = new BundleDTO(); + copy.setGroup(original.getGroup()); + copy.setArtifact(original.getArtifact()); + copy.setVersion(original.getVersion()); + return copy; + } + public ProcessorDTO copy(final ProcessorDTO original) { final ProcessorDTO copy = new ProcessorDTO(); copy.setConfig(copy(original.getConfig())); @@ -2721,8 +2863,13 @@ public final class DtoFactory { copy.setState(original.getState()); copy.setStyle(copy(original.getStyle())); copy.setType(original.getType()); + copy.setBundle(copy(original.getBundle())); copy.setSupportsParallelProcessing(original.getSupportsParallelProcessing()); copy.setSupportsEventDriven(original.getSupportsEventDriven()); + copy.setSupportsBatching(original.getSupportsBatching()); + copy.setPersistsState(original.getPersistsState()); + copy.setExtensionMissing(original.getExtensionMissing()); + copy.setMultipleVersionsAvailable(original.getMultipleVersionsAvailable()); copy.setValidationErrors(copy(original.getValidationErrors())); return copy;
