exceptionfactory commented on code in PR #7124:
URL: https://github.com/apache/nifi/pull/7124#discussion_r1165799800


##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";
+    private NiFiServiceFacade serviceFacade;
+    private Authorizer authorizer;
+
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.WILDCARD)

Review Comment:
   This should be changed from `WILDCARD` to `APPLICATION_JSON`.
   ```suggestion
       @Produces(MediaType.APPLICATION_JSON)
   ```



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsWriter.java:
##########
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+
+public class JmxMetricsWriter {
+    private final static ObjectMapper MAPPER = JsonMapper.builder()
+            .disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)
+            .build();
+    private final JmxMetricsFilter metricsFilter;
+
+    public JmxMetricsWriter(final JmxMetricsFilter metricsFilter) {
+        this.metricsFilter = metricsFilter;
+    }
+
+    public void write(final OutputStream outputStream, final 
Collection<JmxMetricsResult> results) {
+        final Collection<JmxMetricsResult> filteredResults = 
metricsFilter.filter(results);
+
+        try {
+            MAPPER.writerWithDefaultPrettyPrinter().writeValue(outputStream, 
filteredResults);
+        } catch (IOException e) {
+            throw new RuntimeException(e);

Review Comment:
   An `UncheckedIOException` should be used, with a message.
   ```suggestion
               throw new UncheckedIOException("JSON serialization failed", e);
   ```



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverter.java:
##########
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class JmxMetricsResultConverter {

Review Comment:
   With this being a separate class, having a dedicated unit test would be 
helpful to illustrate expected behavior.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";
+    private NiFiServiceFacade serviceFacade;
+    private Authorizer authorizer;
+
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.WILDCARD)
+    @ApiOperation(
+            value = "Gets all allowed JMX metrics",
+            response = StreamingOutput.class,

Review Comment:
   The `response` class should indicate the actual object definition, not the 
wrapper class. It looks like the implementation should be adjusted to return a 
wrapping entity class.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsCollector.java:
##########
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+public class JmxMetricsCollector {
+    private final static String PATTERN_FOR_ALL_OBJECT_NAMES = "*:*";
+    private final JmxMetricsResultConverter resultConverter;
+
+    public JmxMetricsCollector(final JmxMetricsResultConverter 
metricsResultConverter) {
+        this.resultConverter = metricsResultConverter;
+    }
+
+    public Collection<JmxMetricsResult> getBeanMetrics() {
+        final javax.management.MBeanServer mBeanServer = 
java.lang.management.ManagementFactory.getPlatformMBeanServer();

Review Comment:
   The full class names should be replaced with import statements.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsCollector.java:
##########
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+public class JmxMetricsCollector {
+    private final static String PATTERN_FOR_ALL_OBJECT_NAMES = "*:*";
+    private final JmxMetricsResultConverter resultConverter;
+
+    public JmxMetricsCollector(final JmxMetricsResultConverter 
metricsResultConverter) {
+        this.resultConverter = metricsResultConverter;
+    }
+
+    public Collection<JmxMetricsResult> getBeanMetrics() {
+        final javax.management.MBeanServer mBeanServer = 
java.lang.management.ManagementFactory.getPlatformMBeanServer();
+        final Set<ObjectInstance> instances;
+        try {
+            instances = mBeanServer.queryMBeans(new 
ObjectName(PATTERN_FOR_ALL_OBJECT_NAMES), null);
+        } catch (MalformedObjectNameException e) {
+            throw new RuntimeException(e);

Review Comment:
   All exceptions should include a message providing a summary reason.
   



##########
nifi-docs/src/main/asciidoc/administration-guide.adoc:
##########
@@ -4824,3 +4824,32 @@ nifi.diagnostics.on.shutdown.max.directory.size=10 MB
 ```
 
 In the case of a lengthy diagnostic, NiFi may terminate before the command 
execution ends. In this case, the `graceful.shutdown.seconds` property should 
be set to a higher value in the `bootstrap.conf` configuration file.
+
+[[jmx_bean_metrics]]
+== JMX Bean metrics
+
+It is possible to get JMX metrics data calling  
`<your_nifi_url>/nifi-api/jmx-metrics` with 'Flow' 'Read' and 
'SystemDiagnostics' 'Read' permissions.
+
+The information available depends on the registered MBeans and usually related 
to performance indicators such as request/response rate, latency, request size, 
request counts or tool specific ones like commit rate or sync/join time for 
Kafka.
+
+Listing of certain MBeans can be prohibited by a list of regex expressions, 
separated by a `;` and can be configured by a NiFi application property. 
Leaving the property empty means all the MBeans may appear in the result list. 
Default value is to display all MBeans.

Review Comment:
   Instead of supporting multiple expressions, it should be sufficient to 
define one regular expression.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";
+    private NiFiServiceFacade serviceFacade;
+    private Authorizer authorizer;
+
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.WILDCARD)
+    @ApiOperation(
+            value = "Gets all allowed JMX metrics",
+            response = StreamingOutput.class,
+            authorizations = {
+                    @Authorization(value = "Read - /flow"),
+                    @Authorization(value = "Read - /system-diagnostics")
+            }
+    )
+    @ApiResponses(
+            value = {
+                    @ApiResponse(code = 400, message = "NiFi was unable to 
complete the request because it was invalid. The request should not be retried 
without modification."),
+                    @ApiResponse(code = 401, message = "Client could not be 
authenticated."),
+                    @ApiResponse(code = 403, message = "Client is not 
authorized to make this request."),
+                    @ApiResponse(code = 404, message = "The specified resource 
could not be found."),
+                    @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 getJmxMetrics(
+            @ApiParam(
+                    value = "Regular Expression Pattern to be applied against 
the ObjectName")
+            @QueryParam("beanNameFilter") final String beanNameFilter
+
+    ) {
+        authorizeJmxMetrics();
+
+        final String blackListingFilter = 
getProperties().getProperty(JMX_METRICS_NIFI_PROPERTY);

Review Comment:
   The variable should be renamed, but access to the NiFi Properties should be 
pushed down to the service level, not in the REST Resource method.
   ```suggestion
           final String blockedFilterPattern = 
getProperties().getProperty(JMX_METRICS_NIFI_PROPERTY);
   ```



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";
+    private NiFiServiceFacade serviceFacade;
+    private Authorizer authorizer;
+
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.WILDCARD)
+    @ApiOperation(
+            value = "Gets all allowed JMX metrics",

Review Comment:
   Recommend adjusting the wording:
   ```suggestion
               value = "Get all available JMX metrics",
   ```



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverter.java:
##########
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class JmxMetricsResultConverter {
+    private static final String COMPOSITE_DATA_KEY = "CompositeData%s";
+
+    public Object convert(final Object attributeValue) {
+            if (attributeValue instanceof CompositeData[]) {
+                final Map<String, Object> values = new HashMap<>();
+                for (int i = 0; i < ((CompositeData[]) attributeValue).length; 
i++) {
+                    final Map<String, Object> subValues = new HashMap<>();
+                    convertCompositeData(((CompositeData[]) 
attributeValue)[i], subValues);
+                    values.put(String.format(COMPOSITE_DATA_KEY, i), 
subValues);
+                }
+                return values;
+            } else if (attributeValue instanceof CompositeData) {
+                final Map<String, Object> values = new HashMap<>();
+                convertCompositeData(((CompositeData) attributeValue), values);
+                return values;
+            } else if (attributeValue instanceof TabularData) {

Review Comment:
   What should happen in the value of other attribute value types? The current 
implementation does not have an `else` condition.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverter.java:
##########
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import java.util.HashMap;

Review Comment:
   Recommend using `LinkedHashMap` instead of `HashMap` to ensure deterministic 
ordering.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";
+    private NiFiServiceFacade serviceFacade;
+    private Authorizer authorizer;
+
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.WILDCARD)
+    @ApiOperation(
+            value = "Gets all allowed JMX metrics",
+            response = StreamingOutput.class,
+            authorizations = {
+                    @Authorization(value = "Read - /flow"),
+                    @Authorization(value = "Read - /system-diagnostics")

Review Comment:
   The value should be `/system` instead of `/system-diagnostics`.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsWriter.java:
##########
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.json.JsonMapper;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+
+public class JmxMetricsWriter {

Review Comment:
   It seems like this class is specific to the output format, so it could be 
moved into a method in the REST Resource.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResult.java:
##########
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+public class JmxMetricsResult {
+    private String beanName;
+    private String attributeName;
+    private Object attributeValue;
+
+    public JmxMetricsResult() {
+    }

Review Comment:
   Is this no-arg constructor necessary? As it stands, the object properties 
cannot be set outside of the constructor. This might be necessary for reading 
JSON, but it should not be necessary for writing.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverter.java:
##########
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.TabularData;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class JmxMetricsResultConverter {
+    private static final String COMPOSITE_DATA_KEY = "CompositeData%s";
+
+    public Object convert(final Object attributeValue) {
+            if (attributeValue instanceof CompositeData[]) {
+                final Map<String, Object> values = new HashMap<>();
+                for (int i = 0; i < ((CompositeData[]) attributeValue).length; 
i++) {

Review Comment:
   Recommend casting and declaring `CompositeData[]` on a separate line to make 
this easier to read.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsFilter.java:
##########
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.stream.Collectors;
+
+public class JmxMetricsFilter {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(JmxMetricsFilter.class);
+    private final static String MATCH_NOTHING = "~^";
+    private final static String MATCH_ALL = "";
+    private final static String SEPARATOR = ";\\s?";
+    private final static String REPLACEMENT = "|";
+    private final Pattern blackListingFilter;

Review Comment:
   Recommend renaming this variable to `blockedNameFilter`.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";
+    private NiFiServiceFacade serviceFacade;
+    private Authorizer authorizer;
+
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @GET
+    @Consumes(MediaType.WILDCARD)
+    @Produces(MediaType.WILDCARD)
+    @ApiOperation(
+            value = "Gets all allowed JMX metrics",
+            response = StreamingOutput.class,
+            authorizations = {
+                    @Authorization(value = "Read - /flow"),
+                    @Authorization(value = "Read - /system-diagnostics")
+            }
+    )
+    @ApiResponses(
+            value = {
+                    @ApiResponse(code = 400, message = "NiFi was unable to 
complete the request because it was invalid. The request should not be retried 
without modification."),
+                    @ApiResponse(code = 401, message = "Client could not be 
authenticated."),
+                    @ApiResponse(code = 403, message = "Client is not 
authorized to make this request."),
+                    @ApiResponse(code = 404, message = "The specified resource 
could not be found."),
+                    @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 getJmxMetrics(
+            @ApiParam(
+                    value = "Regular Expression Pattern to be applied against 
the ObjectName")
+            @QueryParam("beanNameFilter") final String beanNameFilter
+
+    ) {
+        authorizeJmxMetrics();
+
+        final String blackListingFilter = 
getProperties().getProperty(JMX_METRICS_NIFI_PROPERTY);
+        final JmxMetricsResultConverter metricsResultConverter = new 
JmxMetricsResultConverter();
+        final JmxMetricsCollector jmxMetricsCollector = new 
JmxMetricsCollector(metricsResultConverter);
+
+        final Collection<JmxMetricsResult> results = 
jmxMetricsCollector.getBeanMetrics();

Review Comment:
   Although the implementation is fairly straightforward, in general there 
should be some decoupling between REST Resource methods and implementations. 
Recommend introducing a `JmxMetricsService` interface to encapsulate the 
collection and filtering, and provide the implementation through property 
wiring.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsCollector.java:
##########
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api.metrics.jmx;
+
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.IntrospectionException;
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+public class JmxMetricsCollector {
+    private final static String PATTERN_FOR_ALL_OBJECT_NAMES = "*:*";
+    private final JmxMetricsResultConverter resultConverter;
+
+    public JmxMetricsCollector(final JmxMetricsResultConverter 
metricsResultConverter) {
+        this.resultConverter = metricsResultConverter;
+    }
+
+    public Collection<JmxMetricsResult> getBeanMetrics() {
+        final javax.management.MBeanServer mBeanServer = 
java.lang.management.ManagementFactory.getPlatformMBeanServer();
+        final Set<ObjectInstance> instances;
+        try {
+            instances = mBeanServer.queryMBeans(new 
ObjectName(PATTERN_FOR_ALL_OBJECT_NAMES), null);
+        } catch (MalformedObjectNameException e) {
+            throw new RuntimeException(e);
+        }
+
+        final Collection<JmxMetricsResult> results = new ArrayList<>();
+        for (final ObjectInstance instance : instances) {
+            final MBeanInfo info;
+            try {
+                info = mBeanServer.getMBeanInfo(instance.getObjectName());
+            } catch (InstanceNotFoundException | ReflectionException | 
IntrospectionException e) {
+                continue;
+            }
+
+            for (MBeanAttributeInfo attribute : info.getAttributes()) {
+                    try {
+                        final String beanName = 
instance.getObjectName().getCanonicalName();
+                        final String attributeName = attribute.getName();
+                        final Object attributeValue = 
resultConverter.convert(mBeanServer.getAttribute(instance.getObjectName(), 
attribute.getName()));
+
+                        results.add(new JmxMetricsResult(beanName, 
attributeName, attributeValue));
+                    } catch (MBeanException | RuntimeMBeanException | 
ReflectionException | InstanceNotFoundException | AttributeNotFoundException e) 
{
+                        //Empty or invalid attributes should not stop the loop.

Review Comment:
   Recommend introducing a trace log at this point for potential 
troubleshooting, instead of hiding the exception.



##########
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/JmxMetricsResource.java:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.web.api;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsFilter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResult;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsWriter;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.util.Collection;
+
+/**
+ * RESTful endpoint for JMX metrics.
+ */
+@Path("/jmx-metrics")
+@Api(
+        value = "/jmx-metrics",
+        description = "Endpoint for accessing the JMX metrics."
+)
+public class JmxMetricsResource extends ApplicationResource {
+    private static final String JMX_METRICS_NIFI_PROPERTY = 
"nifi.jmx.metrics.blacklisting.filter";

Review Comment:
   As mentioned elsewhere, this property should be injected at the Service 
level, not at the Resource level.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscr...@nifi.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


Reply via email to