This is an automated email from the ASF dual-hosted git repository.

exceptionfactory pushed a commit to branch support/nifi-1.x
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/support/nifi-1.x by this push:
     new e1ddc44b07 NIFI-11385 Added JMX Metrics REST Resource for Diagnostics
e1ddc44b07 is described below

commit e1ddc44b078b17780465c6075e4bdd51ac522c89
Author: Timea Barna <[email protected]>
AuthorDate: Wed Apr 5 14:42:47 2023 +0200

    NIFI-11385 Added JMX Metrics REST Resource for Diagnostics
    
    This closes #7124
    
    Co-authored-by: David Handermann <[email protected]>
    Signed-off-by: David Handermann <[email protected]>
    (cherry picked from commit 5811a9c579a11aa8fc8358851df33d0456a5e10c)
---
 .../java/org/apache/nifi/util/NiFiProperties.java  |   1 +
 .../src/main/asciidoc/administration-guide.adoc    |  36 +++++
 .../nifi/web/api/dto/JmxMetricsResultDTO.java      |  49 +++++++
 .../web/api/entity/JmxMetricsResultsEntity.java    |  43 ++++++
 .../nifi-framework/nifi-resources/pom.xml          |   1 +
 .../src/main/resources/conf/nifi.properties        |   5 +-
 .../nifi/web/api/SystemDiagnosticsResource.java    |  60 +++++++-
 .../web/api/metrics/jmx/JmxMetricsCollector.java   |  82 +++++++++++
 .../nifi/web/api/metrics/jmx/JmxMetricsFilter.java |  59 ++++++++
 .../api/metrics/jmx/JmxMetricsResultConverter.java |  66 +++++++++
 .../web/api/metrics/jmx/JmxMetricsService.java     |  30 ++++
 .../api/metrics/jmx/StandardJmxMetricsService.java |  42 ++++++
 .../src/main/resources/nifi-web-api-context.xml    |  10 ++
 .../web/api/metrics/jmx/JmxMetricsFilterTest.java  | 127 +++++++++++++++++
 .../metrics/jmx/JmxMetricsResultConverterTest.java | 158 +++++++++++++++++++++
 15 files changed, 766 insertions(+), 3 deletions(-)

diff --git 
a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
 
b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
index cb9f2dac58..7968fbb56a 100644
--- 
a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
+++ 
b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
@@ -244,6 +244,7 @@ public class NiFiProperties extends ApplicationProperties {
     public static final String WEB_REQUEST_IP_WHITELIST = 
"nifi.web.request.ip.whitelist";
     public static final String WEB_SHOULD_SEND_SERVER_VERSION = 
"nifi.web.should.send.server.version";
     public static final String WEB_REQUEST_LOG_FORMAT = 
"nifi.web.request.log.format";
+    public static final String WEB_JMX_METRICS_ALLOWED_FILTER_PATTERN = 
"nifi.web.jmx.metrics.allowed.filter.pattern";
 
     // ui properties
     public static final String UI_BANNER_TEXT = "nifi.ui.banner.text";
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc 
b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index e315e33dae..7e81718e57 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -4272,6 +4272,8 @@ request headers. The default value is:
 The CustomRequestLog writes formatted messages using the following SLF4J 
logger:
 
 `org.apache.nifi.web.server.RequestLog`
+|`nifi.web.jmx.metrics.allowed.filter.pattern`|The regular expression 
controlling the JMX MBean names that the REST API
+is allowed to return. The default value is empty, blocking all MBeans. 
Configuring `.*` allows all registered MBeans.
 |====
 
 [[security_properties]]
@@ -4932,3 +4934,37 @@ 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_metrics]]
+== JMX Metrics
+
+It is possible to get JMX metrics using the REST API with read permissions on 
system diagnostics resources.
+
+The information available depends on the registered MBeans. Metrics can 
contain data related to performance indicators.
+
+Listing of MBeans is controlled using a regular expression pattern in 
application properties. Leaving the
+property empty means no MBeans will be returned. The default value blocks all 
MBeans and must be changed to return
+information.
+
+ nifi.web.jmx.metrics.allowed.filter.pattern=.*
+
+An optionally provided query parameter using a regular expression pattern, 
will display only MBeans with matching names.
+Leaving this parameter empty means listing all MBeans except those filtered 
out by the blocked filter pattern.
+
+ 
https://localhost:8443/nifi-api/system-diagnostics/jmx-metrics?beanNameFilter=bean.name.1|bean.name.2
+
+An example output would look like this:
+
+ [
+   {
+     "beanName" : "bean.name.1,type=type1",
+     "attributeName" : “attribute-name",
+     "attributeValue" : “attribute-value”
+   },
+   {
+     "beanName" : "bean.name.2, type=type2",
+     "attributeName" : "attribute-name",
+     "attributeValue" : integer-value
+   }
+ ]
+
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java
new file mode 100644
index 0000000000..b36932f786
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/dto/JmxMetricsResultDTO.java
@@ -0,0 +1,49 @@
+/*
+ * 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.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+import javax.xml.bind.annotation.XmlType;
+
+@XmlType(name = "jmxMetricsResults")
+public class JmxMetricsResultDTO {
+    final private String beanName;
+    final private String attributeName;
+    final private Object attributeValue;
+
+    public JmxMetricsResultDTO(final String beanName, final String 
attributeName, final Object attributeValue) {
+        this.beanName = beanName;
+        this.attributeName = attributeName;
+        this.attributeValue = attributeValue;
+    }
+
+    @ApiModelProperty("The bean name of the metrics bean.")
+    public String getBeanName() {
+        return beanName;
+    }
+
+    @ApiModelProperty("The attribute name of the metrics bean's attribute.")
+    public String getAttributeName() {
+        return attributeName;
+    }
+
+    @ApiModelProperty("The attribute value of the the metrics bean's 
attribute")
+    public Object getAttributeValue() {
+        return attributeValue;
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/JmxMetricsResultsEntity.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/JmxMetricsResultsEntity.java
new file mode 100644
index 0000000000..4a11957f3d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/JmxMetricsResultsEntity.java
@@ -0,0 +1,43 @@
+/*
+ * 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.entity;
+
+import org.apache.nifi.web.api.dto.JmxMetricsResultDTO;
+
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.Collection;
+
+/**
+ * A serialized representation of this class can be placed in the entity body 
of a request or response to or from the API. This particular entity holds a 
reference to a list of JmxMetricsResult.
+ */
+@XmlRootElement(name = "jmxMetricsResult")
+public class JmxMetricsResultsEntity extends Entity {
+    private Collection<JmxMetricsResultDTO> jmxMetricsResults;
+
+    /**
+     * A collection of JmxMetricsResultDTO objects that is being serialized.
+     *
+     * @return The collection of JmxMetricsResultDTO objects
+     */
+    public Collection<JmxMetricsResultDTO> getJmxMetricsResults() {
+        return jmxMetricsResults;
+    }
+
+    public void setJmxMetricsResults(final Collection<JmxMetricsResultDTO> 
jmxMetricsResults) {
+        this.jmxMetricsResults = jmxMetricsResults;
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
index 158d930d4d..ca4a6e7a91 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/pom.xml
@@ -140,6 +140,7 @@
         <nifi.web.request.ip.whitelist />
         
<nifi.web.should.send.server.version>true</nifi.web.should.send.server.version>
         <nifi.web.request.log.format>%{client}a - %u %t "%r" %s %O 
"%{Referer}i" "%{User-Agent}i"</nifi.web.request.log.format>
+        <nifi.web.jmx.metrics.allowed.filter.pattern />
         <!-- nifi.properties: security properties -->
         
<nifi.security.autoreload.enabled>false</nifi.security.autoreload.enabled>
         <nifi.security.autoreload.interval>10 
secs</nifi.security.autoreload.interval>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
index 498171b47f..b86db14774 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-resources/src/main/resources/conf/nifi.properties
@@ -166,6 +166,9 @@ 
nifi.web.request.ip.whitelist=${nifi.web.request.ip.whitelist}
 nifi.web.should.send.server.version=${nifi.web.should.send.server.version}
 nifi.web.request.log.format=${nifi.web.request.log.format}
 
+# Filter JMX MBeans available through the System Diagnostics REST API
+nifi.web.jmx.metrics.allowed.filter.pattern=${nifi.web.jmx.metrics.allowed.filter.pattern}
+
 # Include or Exclude TLS Cipher Suites for HTTPS
 nifi.web.https.ciphersuites.include=
 nifi.web.https.ciphersuites.exclude=
@@ -328,8 +331,6 @@ 
nifi.analytics.connection.model.score.threshold=${nifi.analytics.connection.mode
 nifi.monitor.long.running.task.schedule=
 nifi.monitor.long.running.task.threshold=
 
-# Create automatic diagnostics when stopping/restarting NiFi.
-
 # Enable automatic diagnostic at shutdown.
 nifi.diagnostics.on.shutdown.enabled=false
 
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
index 8b9fed401b..7238eaddbf 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/SystemDiagnosticsResource.java
@@ -28,8 +28,11 @@ import org.apache.nifi.authorization.resource.Authorizable;
 import org.apache.nifi.authorization.user.NiFiUserUtils;
 import org.apache.nifi.cluster.manager.NodeResponse;
 import org.apache.nifi.web.NiFiServiceFacade;
+import org.apache.nifi.web.api.dto.JmxMetricsResultDTO;
 import org.apache.nifi.web.api.dto.SystemDiagnosticsDTO;
+import org.apache.nifi.web.api.entity.JmxMetricsResultsEntity;
 import org.apache.nifi.web.api.entity.SystemDiagnosticsEntity;
+import org.apache.nifi.web.api.metrics.jmx.JmxMetricsService;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DefaultValue;
@@ -40,6 +43,7 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.Collection;
 
 /**
  * RESTful endpoint for retrieving system diagnostics.
@@ -50,7 +54,7 @@ import javax.ws.rs.core.Response;
         description = "Endpoint for accessing system diagnostics."
 )
 public class SystemDiagnosticsResource extends ApplicationResource {
-
+    private JmxMetricsService jmxMetricsService;
     private NiFiServiceFacade serviceFacade;
     private Authorizer authorizer;
 
@@ -138,6 +142,56 @@ public class SystemDiagnosticsResource extends 
ApplicationResource {
         return generateOkResponse(entity).build();
     }
 
+    /**
+     * Retrieves the JMX metrics.
+     *
+     * @return A jmxMetricsResult list.
+     */
+    @Path("jmx-metrics")
+    @GET
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @ApiOperation(
+            value = "Retrieve available JMX metrics",
+            notes = NON_GUARANTEED_ENDPOINT,
+            response = JmxMetricsResultsEntity.class,
+            authorizations = {
+                    @Authorization(value = "Read - /system")
+            }
+    )
+    @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 Collection<JmxMetricsResultDTO> results = 
jmxMetricsService.getFilteredMBeanMetrics(beanNameFilter);
+        final JmxMetricsResultsEntity entity = new JmxMetricsResultsEntity();
+        entity.setJmxMetricsResults(results);
+
+        return generateOkResponse(entity)
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .build();
+    }
+
+    private void authorizeJmxMetrics() {
+        serviceFacade.authorizeAccess(lookup -> {
+            final Authorizable system = lookup.getSystem();
+            system.authorize(authorizer, RequestAction.READ, 
NiFiUserUtils.getNiFiUser());
+        });
+    }
+
     // setters
 
     public void setServiceFacade(NiFiServiceFacade serviceFacade) {
@@ -147,4 +201,8 @@ public class SystemDiagnosticsResource extends 
ApplicationResource {
     public void setAuthorizer(Authorizer authorizer) {
         this.authorizer = authorizer;
     }
+
+    public void setJmxMetricsService(final JmxMetricsService 
jmxMetricsService) {
+        this.jmxMetricsService = jmxMetricsService;
+    }
 }
diff --git 
a/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
 
b/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
new file mode 100644
index 0000000000..5281e8a898
--- /dev/null
+++ 
b/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,82 @@
+/*
+ * 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.apache.nifi.web.api.dto.JmxMetricsResultDTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeMBeanException;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+public class JmxMetricsCollector {
+    private static final Logger LOGGER = 
LoggerFactory.getLogger(JmxMetricsCollector.class);
+    private final static String PATTERN_FOR_ALL_OBJECT_NAMES = "*:*";
+    private final JmxMetricsResultConverter resultConverter;
+
+    public JmxMetricsCollector(final JmxMetricsResultConverter 
metricsResultConverter) {
+        this.resultConverter = metricsResultConverter;
+    }
+
+    public Collection<JmxMetricsResultDTO> getBeanMetrics() {
+        final MBeanServer mBeanServer = 
ManagementFactory.getPlatformMBeanServer();
+        final Set<ObjectInstance> instances;
+        try {
+            instances = mBeanServer.queryMBeans(new 
ObjectName(PATTERN_FOR_ALL_OBJECT_NAMES), null);
+        } catch (MalformedObjectNameException e) {
+            throw new RuntimeException("Invalid ObjectName pattern", e);
+        }
+
+        final Collection<JmxMetricsResultDTO> 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 JmxMetricsResultDTO(beanName, 
attributeName, attributeValue));
+                } catch (final MBeanException | RuntimeMBeanException | 
ReflectionException | InstanceNotFoundException | AttributeNotFoundException e) 
{
+                    //Empty or invalid attributes should not stop the loop.
+                    LOGGER.debug("MBean Object [{}] invalid attribute [{}] 
found", instance.getObjectName(), attribute.getName());
+                }
+            }
+        }
+        return results;
+    }
+}
diff --git 
a/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
 
b/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
new file mode 100644
index 0000000000..46c9cdf24d
--- /dev/null
+++ 
b/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,59 @@
+/*
+ * 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.apache.nifi.web.api.dto.JmxMetricsResultDTO;
+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 Pattern allowedNameFilter;
+    private final Pattern beanNameFilter;
+
+    public JmxMetricsFilter(final String allowedNameFilter, final String 
beanNameFilter) {
+        this.allowedNameFilter = createPattern(allowedNameFilter, 
MATCH_NOTHING);
+        this.beanNameFilter = createPattern(beanNameFilter, MATCH_ALL);
+    }
+
+    private Pattern createPattern(final String filter, final String 
defaultValue) {
+        try {
+            if (filter == null || filter.isEmpty()) {
+                return Pattern.compile(defaultValue);
+            } else {
+                return Pattern.compile(filter);
+            }
+        } catch (PatternSyntaxException e) {
+            LOGGER.warn("Invalid JMX MBean filter pattern ignored [{}]", 
filter);
+            return Pattern.compile(defaultValue);
+        }
+    }
+
+    public Collection<JmxMetricsResultDTO> filter(final 
Collection<JmxMetricsResultDTO> results) {
+        return results.stream()
+                .filter(result -> 
allowedNameFilter.asPredicate().test(result.getBeanName()))
+                .filter(result -> 
beanNameFilter.asPredicate().test(result.getBeanName()))
+                .collect(Collectors.toList());
+    }
+}
diff --git 
a/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
 
b/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
new file mode 100644
index 0000000000..afb9c3f4c1
--- /dev/null
+++ 
b/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,66 @@
+/*
+ * 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.LinkedHashMap;
+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 CompositeData[] valueArray = (CompositeData[]) 
attributeValue;
+            final Map<String, Object> values = new LinkedHashMap<>();
+
+            for (int i = 0; i < valueArray.length; i++) {
+                final Map<String, Object> subValues = new LinkedHashMap<>();
+                convertCompositeData(valueArray[i], subValues);
+                values.put(String.format(COMPOSITE_DATA_KEY, i), subValues);
+            }
+            return values;
+        } else if (attributeValue instanceof CompositeData) {
+            final Map<String, Object> values = new LinkedHashMap<>();
+            convertCompositeData(((CompositeData) attributeValue), values);
+            return values;
+        } else if (attributeValue instanceof TabularData) {
+            final Map<String, Object> values = new LinkedHashMap<>();
+            convertTabularData((TabularData) attributeValue, values);
+            return values;
+        } else {
+            return attributeValue;
+        }
+    }
+
+    private void convertCompositeData(CompositeData attributeValue, 
Map<String, Object> values) {
+        for (String key : attributeValue.getCompositeType().keySet()) {
+            values.put(key, convert(attributeValue.get(key)));
+        }
+    }
+
+    private void convertTabularData(TabularData attributeValue, Map<String, 
Object> values) {
+        final Set<List<?>> keys = (Set<List<?>>) attributeValue.keySet();
+        for (List<?> key : keys) {
+            Object value = convert(attributeValue.get(key.toArray()));
+            values.put(key.toString(), value);
+        }
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsService.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsService.java
new file mode 100644
index 0000000000..5a81ae6bf9
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsService.java
@@ -0,0 +1,30 @@
+/*
+ * 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.apache.nifi.web.api.dto.JmxMetricsResultDTO;
+
+import java.util.Collection;
+
+public interface JmxMetricsService {
+    /**
+     * @return a filtered mBean metric collection
+     *
+     * @param beanNameFilter regular expression pattern for bean name filtering
+     */
+    Collection<JmxMetricsResultDTO> getFilteredMBeanMetrics(final String 
beanNameFilter);
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/StandardJmxMetricsService.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/StandardJmxMetricsService.java
new file mode 100644
index 0000000000..a6d6ed933d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/metrics/jmx/StandardJmxMetricsService.java
@@ -0,0 +1,42 @@
+/*
+ * 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.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.web.api.dto.JmxMetricsResultDTO;
+
+import java.util.Collection;
+
+public class StandardJmxMetricsService implements JmxMetricsService {
+    private NiFiProperties properties;
+    private JmxMetricsCollector metricsCollector;
+
+    @Override
+    public Collection<JmxMetricsResultDTO> getFilteredMBeanMetrics(final 
String beanNameFilter) {
+        final String allowedFilterPattern = 
properties.getProperty(NiFiProperties.WEB_JMX_METRICS_ALLOWED_FILTER_PATTERN);
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(allowedFilterPattern, beanNameFilter);
+        return metricsFilter.filter(metricsCollector.getBeanMetrics());
+    }
+
+    public void setProperties(final NiFiProperties properties) {
+        this.properties = properties;
+    }
+
+    public void setMetricsCollector(final JmxMetricsCollector 
metricsCollector) {
+        this.metricsCollector = metricsCollector;
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
index 9cd20ce746..5e356da4bb 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/resources/nifi-web-api-context.xml
@@ -608,6 +608,7 @@
         <property name="requestReplicator" ref="requestReplicator" />
         <property name="authorizer" ref="authorizer"/>
         <property name="flowController" ref="flowController" />
+        <property name="jmxMetricsService" ref="jmxMetricsService" />
     </bean>
     <bean id="accessResource" class="org.apache.nifi.web.api.AccessResource" 
scope="singleton">
         <property name="logoutRequestManager" ref="logoutRequestManager" />
@@ -655,6 +656,15 @@
         <property name="clusterComponentLifecycle" 
ref="clusterComponentLifecycle" />
         <property name="localComponentLifecycle" ref="localComponentLifecycle" 
/>
     </bean>
+    <bean id="jmxMetricsService" 
class="org.apache.nifi.web.api.metrics.jmx.StandardJmxMetricsService">
+        <property name="properties" ref="nifiProperties"/>
+        <property name="metricsCollector" ref="metricsCollector"/>
+    </bean>
+    <bean id="metricsResultConverter" 
class="org.apache.nifi.web.api.metrics.jmx.JmxMetricsResultConverter">
+    </bean>
+    <bean id="metricsCollector" 
class="org.apache.nifi.web.api.metrics.jmx.JmxMetricsCollector">
+        <constructor-arg ref="metricsResultConverter"/>
+    </bean>
 
     <!-- enable aop -->
     <!--
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsFilterTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsFilterTest.java
new file mode 100644
index 0000000000..f525fb0e15
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsFilterTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.apache.nifi.web.api.dto.JmxMetricsResultDTO;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class JmxMetricsFilterTest {
+    private static final String ALLOW_ALL_PATTERN = ".*";
+    private static final String EMPTY_STRING_PATTERN = "";
+    private static final String BEAN_NAME_FILTER = "%s|%s";
+    private static final String INVALID_REGEX = "(";
+    private static final String TEST_BEAN_NAME_ONE = "testBean1";
+    private static final String TEST_BEAN_NAME_TWO = "testBean2";
+    private static final JmxMetricsResultDTO RESULT_ONE = new 
JmxMetricsResultDTO(TEST_BEAN_NAME_ONE, null, null);
+    private static final JmxMetricsResultDTO RESULT_TWO = new 
JmxMetricsResultDTO(TEST_BEAN_NAME_TWO, null, null);
+    private static List<JmxMetricsResultDTO> results;
+
+    @BeforeAll
+    public static void init() {
+        results = new ArrayList<>();
+        results.add(RESULT_ONE);
+        results.add(RESULT_TWO);
+    }
+
+    @Test
+    public void testNotProvidingFiltersReturnsAllMBeans() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(ALLOW_ALL_PATTERN, EMPTY_STRING_PATTERN);
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertEquals(actual.size(), 2);
+        assertTrue(actual.containsAll(results));
+    }
+
+    @Test
+    public void testAllowedNameFiltersRemovesMBeanFromResult() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(TEST_BEAN_NAME_ONE, EMPTY_STRING_PATTERN);
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertEquals(actual.size(), 1);
+        assertTrue(actual.contains(RESULT_ONE));
+        assertFalse(actual.contains(RESULT_TWO));
+    }
+
+    @Test
+    public void testBeanNameFiltersReturnsTheSpecifiedMBeansOnly() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(ALLOW_ALL_PATTERN, String.format(BEAN_NAME_FILTER, 
TEST_BEAN_NAME_ONE, TEST_BEAN_NAME_TWO));
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertEquals(actual.size(), 2);
+        assertTrue(actual.containsAll(results));
+    }
+
+    @Test
+    public void testInvalidAllowedNameFilterRevertingBackToDefaultFiltering() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(INVALID_REGEX, EMPTY_STRING_PATTERN);
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertTrue(actual.isEmpty());
+    }
+
+    @Test
+    public void testInvalidBeanNameFilteringRevertingBackToDefaultFiltering() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(ALLOW_ALL_PATTERN, INVALID_REGEX);
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertEquals(actual.size(), 2);
+        assertTrue(actual.containsAll(results));
+    }
+
+    @Test
+    public void testInvalidFiltersRevertingBackToDefaultFiltering() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(INVALID_REGEX, INVALID_REGEX);
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertTrue(actual.isEmpty());
+    }
+
+    @Test
+    public void testAllowedNameFilterHasPriority() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(TEST_BEAN_NAME_TWO, TEST_BEAN_NAME_ONE);
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertTrue(actual.isEmpty());
+    }
+
+    @Test
+    public void testAllowedNameFilterHasPriorityWhenTheSameFiltersApplied() {
+        final JmxMetricsFilter metricsFilter = new 
JmxMetricsFilter(TEST_BEAN_NAME_TWO, String.format(BEAN_NAME_FILTER, 
TEST_BEAN_NAME_ONE, TEST_BEAN_NAME_TWO));
+
+        final Collection<JmxMetricsResultDTO> actual = 
metricsFilter.filter(results);
+
+        assertEquals(actual.size(), 1);
+        assertFalse(actual.contains(RESULT_ONE));
+        assertTrue(actual.contains(RESULT_TWO));
+    }
+}
\ No newline at end of file
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverterTest.java
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverterTest.java
new file mode 100644
index 0000000000..6f6e64000e
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/metrics/jmx/JmxMetricsResultConverterTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.OpenDataException;
+import javax.management.openmbean.OpenType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularDataSupport;
+import javax.management.openmbean.TabularType;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class JmxMetricsResultConverterTest {
+    private static final String COMPOSITE_DATA_KEY = "CompositeData%s";
+    private static final String TABLE_DATA_KEY = "Test String %s";
+    private static final String CONVERTED_TABLE_DATA_KEY = "[Test String %s]";
+    private static final String ATTRIBUTE_NAME_STRING = "string";
+    private static final String ATTRIBUTE_NAME_INT = "int";
+    private static final String ATTRIBUTE_NAME_BOOLEAN = "boolean";
+    private static final String TABLE_DESCRIPTION = "Table for all tests";
+    private static final String TABLE_NAME = "Test table";
+    private static final String METRIC_TYPE_DESCRIPTION = "Metric type for 
testing";
+    private static final String METRIC_TYPE_NAME = "Metric type";
+    private static JmxMetricsResultConverter metricsResultConverter;
+    private static CompositeData compositeDataOne;
+    private static CompositeData compositeDataTwo;
+    private static CompositeData compositeDataThree;
+    private static TabularType tableType;
+    @BeforeAll
+    public static void init() throws OpenDataException {
+        metricsResultConverter = new JmxMetricsResultConverter();
+
+        final CompositeType compositeType = new CompositeType(METRIC_TYPE_NAME,
+                METRIC_TYPE_DESCRIPTION,
+                new String[]{ATTRIBUTE_NAME_STRING, ATTRIBUTE_NAME_INT, 
ATTRIBUTE_NAME_BOOLEAN},
+                new String[]{ATTRIBUTE_NAME_STRING, ATTRIBUTE_NAME_INT, 
ATTRIBUTE_NAME_BOOLEAN},
+                new OpenType[]{SimpleType.STRING, SimpleType.INTEGER, 
SimpleType.BOOLEAN});
+
+        tableType = new TabularType(TABLE_NAME,
+                TABLE_DESCRIPTION,
+                compositeType,
+                new String[] {ATTRIBUTE_NAME_STRING});
+
+        compositeDataOne = new CompositeDataSupport(compositeType,
+                new String[] {ATTRIBUTE_NAME_STRING, ATTRIBUTE_NAME_INT, 
ATTRIBUTE_NAME_BOOLEAN},
+                new Object[] {"Test String 1", 1, Boolean.FALSE}
+        );
+
+        compositeDataTwo = new CompositeDataSupport(compositeType,
+                new String[] {ATTRIBUTE_NAME_STRING, ATTRIBUTE_NAME_INT, 
ATTRIBUTE_NAME_BOOLEAN},
+                new Object[] {"Test String 2", 2, Boolean.TRUE}
+        );
+
+        compositeDataThree = new CompositeDataSupport(compositeType,
+                new String[] {ATTRIBUTE_NAME_STRING, ATTRIBUTE_NAME_INT, 
ATTRIBUTE_NAME_BOOLEAN},
+                new Object[] {"Test String 3", 3, Boolean.FALSE}
+        );
+    }
+
+    @Test
+    public void testSimpleTypeKeptOriginalType() {
+        final String expectedString = "Test String";
+        final int expectedInt = 1;
+        final boolean expectedBoolean = Boolean.TRUE;
+
+        final Object actualString = 
metricsResultConverter.convert(expectedString);
+        final Object actualInt = metricsResultConverter.convert(expectedInt);
+        final Object actualBoolean = 
metricsResultConverter.convert(expectedBoolean);
+
+        assertEquals(expectedString, actualString);
+        assertEquals(expectedInt, actualInt);
+        assertEquals(expectedBoolean, actualBoolean);
+        assertEquals(SimpleType.STRING.getTypeName(), 
actualString.getClass().getName());
+        assertEquals(SimpleType.INTEGER.getTypeName(), 
actualInt.getClass().getName());
+        assertEquals(SimpleType.BOOLEAN.getTypeName(), 
actualBoolean.getClass().getName());
+    }
+
+    @Test
+    public void testCompositeDataConvertedToMap() {
+        //CompositeData consists of a compositeType and a content which is a 
Map of attribute name and value pairs.
+        //The content will be concerted to a LinkedHashMap.
+        final CompositeData expected = compositeDataOne;
+
+        final Map<String, Object> actual = 
castToMap(metricsResultConverter.convert(expected));
+
+        assertEquals(expected.get(ATTRIBUTE_NAME_STRING), 
actual.get(ATTRIBUTE_NAME_STRING));
+        assertEquals(expected.get(ATTRIBUTE_NAME_STRING).getClass().getName(), 
actual.get(ATTRIBUTE_NAME_STRING).getClass().getName());
+        assertEquals(expected.get(ATTRIBUTE_NAME_INT), 
actual.get(ATTRIBUTE_NAME_INT));
+        assertEquals(expected.get(ATTRIBUTE_NAME_INT).getClass().getName(), 
actual.get(ATTRIBUTE_NAME_INT).getClass().getName());
+        assertEquals(expected.get(ATTRIBUTE_NAME_BOOLEAN), 
actual.get(ATTRIBUTE_NAME_BOOLEAN));
+        
assertEquals(expected.get(ATTRIBUTE_NAME_BOOLEAN).getClass().getName(), 
actual.get(ATTRIBUTE_NAME_BOOLEAN).getClass().getName());
+    }
+
+    @Test
+    public void testCompositeDataListConvertedToMaps() {
+        //A CompositeData array consists of a collection of CompositeData 
objects.
+        //The content will be concerted to a LinkedHashMap where the key is 
'CompositeData<array_index>'
+        // and the value is a LinkedHashmap of the CompositeData content.
+        final CompositeData[] expected = new CompositeData[] {
+                    compositeDataOne,
+                    compositeDataTwo,
+                    compositeDataThree
+                };
+
+        final Map<String, Object> actual = 
castToMap(metricsResultConverter.convert(expected));
+
+        
assertTrue(expected[0].values().containsAll(castToMap(actual.get(String.format(COMPOSITE_DATA_KEY,
 0))).values()));
+        
assertTrue(expected[1].values().containsAll(castToMap(actual.get(String.format(COMPOSITE_DATA_KEY,
 1))).values()));
+        
assertTrue(expected[2].values().containsAll(castToMap(actual.get(String.format(COMPOSITE_DATA_KEY,
 2))).values()));
+        assertEquals(expected.length, actual.size());
+    }
+
+    @Test
+    public void testTabularDataConvertedToMaps() {
+        //A TabularData consists of a Collection where key is a String array 
of attribute names and value is a CompositeData.
+        //The content will be concerted to a LinkedHashMap where the key is 
String output of the Tabular key array
+        // and the value is a LinkedHashmap of the CompositeData content.
+        final TabularData expected = new TabularDataSupport(tableType);
+        expected.put(compositeDataOne);
+        expected.put(compositeDataTwo);
+        expected.put(compositeDataThree);
+
+        final Map<String, Object> actual = 
castToMap(metricsResultConverter.convert(expected));
+
+        assertTrue(expected.get(new String[]{String.format(TABLE_DATA_KEY, 
1)}).values().containsAll(castToMap(actual.get(String.format(CONVERTED_TABLE_DATA_KEY,
 1))).values()));
+        assertTrue(expected.get(new String[]{String.format(TABLE_DATA_KEY, 
2)}).values().containsAll(castToMap(actual.get(String.format(CONVERTED_TABLE_DATA_KEY,
 2))).values()));
+        assertTrue(expected.get(new String[]{String.format(TABLE_DATA_KEY, 
3)}).values().containsAll(castToMap(actual.get(String.format(CONVERTED_TABLE_DATA_KEY,
 3))).values()));
+        assertEquals(expected.values().size(), actual.size());
+    }
+
+    private Map<String, Object> castToMap(final Object object) {
+        return (Map<String, Object>) object;
+    }
+
+}
\ No newline at end of file


Reply via email to