/**
 * Copyright 2017 Pivotal Software, Inc.
 * <p>
 * Licensed 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
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * 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 io.micrometer.core.instrument.binder.cache;

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Tags;
import io.micrometer.core.instrument.config.InvalidConfigurationException;
import io.micrometer.core.lang.NonNullApi;
import io.micrometer.core.lang.NonNullFields;
import io.micrometer.core.lang.Nullable;

import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.management.*;
import java.util.List;

/**
 * Collect metrics on JSR-107 JCache caches, including detailed metrics on manual puts and removals.
 * See https://github.com/jsr107/demo/blob/master/src/test/java/javax/cache/core/StatisticsExample.java
 * <p>
 * Note that JSR-107 does not provide any insight into the size or estimated size of the cache, so
 * the size metric of a JCache cache will always report 0.
 *
 * @author Jon Schneider
 */
@NonNullApi
@NonNullFields
public class JCacheMetrics extends CacheMeterBinder {
    @Nullable
    private ObjectName objectName;

    /**
     * Record metrics on a JCache cache.
     *
     * @param registry The registry to bind metrics to.
     * @param cache    The cache to instrument.
     * @param tags     Tags to apply to all recorded metrics. Must be an even number of arguments representing key/value pairs of tags.
     * @param <C>      The cache type.
     * @param <K>      The cache key type.
     * @param <V>      The cache value type.
     * @return The instrumented cache, unchanged. The original cache is not wrapped or proxied in any way.
     */
    public static <K, V, C extends Cache<K, V>> C monitor(MeterRegistry registry, C cache, String... tags) {
        return monitor(registry, cache, Tags.of(tags));
    }

    /**
     * Record metrics on a JCache cache.
     *
     * @param registry The registry to bind metrics to.
     * @param cache    The cache to instrument.
     * @param tags     Tags to apply to all recorded metrics.
     * @param <C>      The cache type.
     * @param <K>      The cache key type.
     * @param <V>      The cache value type.
     * @return The instrumented cache, unchanged. The original cache is not wrapped or proxied in any way.
     */
    public static <K, V, C extends Cache<K, V>> C monitor(MeterRegistry registry, C cache, Iterable<Tag> tags) {
        new JCacheMetrics(cache, tags).bindTo(registry);
        return cache;
    }

    public JCacheMetrics(Cache<?, ?> cache, Iterable<Tag> tags) {
        super(cache, cache.getName(), tags);
        try {
            CacheManager cacheManager = cache.getCacheManager();
            if (cacheManager != null) {
                String cacheManagerUri = cacheManager.getURI().toString()
                        .replace(':', '.'); // ehcache's uri is prefixed with 'urn:'

                this.objectName = new ObjectName("javax.cache:type=CacheStatistics"
                        + ",CacheManager=" + cacheManagerUri
                        + ",Cache=" + cache.getName());
            }
        } catch (MalformedObjectNameException ignored) {
            throw new InvalidConfigurationException("Cache name '" + cache.getName() + "' results in an invalid JMX name");
        }
    }

    @Override
    protected Long size() {
        // JCache statistics don't support size
        return null;
    }

    @Override
    protected long hitCount() {
        return lookupStatistic("CacheHits");
    }

    @Override
    protected Long missCount() {
        return lookupStatistic("CacheMisses");
    }

    @Override
    protected Long evictionCount() {
        return lookupStatistic("CacheEvictions");
    }

    @Override
    protected long putCount() {
        return lookupStatistic("CachePuts");
    }

    @Override
    protected void bindImplementationSpecificMetrics(MeterRegistry registry) {
        if (objectName != null) {
            Gauge.builder("cache.removals", objectName, objectName -> lookupStatistic("CacheRemovals"))
                    .tags(getTagsWithCacheName())
                    .description("Cache removals")
                    .register(registry);
        }
    }

    private long lookupStatistic(String name) {
        try {
            List<MBeanServer> mBeanServers = MBeanServerFactory.findMBeanServer(null);
            for (MBeanServer mBeanServer : mBeanServers) {
                try {
                    Object attribute = mBeanServer.getAttribute(objectName, name);
                    return (Long) attribute;
                } catch (AttributeNotFoundException | InstanceNotFoundException ex) {
                    // did not find MBean, try the next server
                }
            }
        } catch (MBeanException | ReflectionException ex) {
            throw new IllegalStateException(ex);
        }

        // didn't find the MBean in any servers
        return 0;
    }
}

@@ -4796,17 +4796,17 @@
 private 
-l
+L
 ong look
@@ -5038,26 +5038,21 @@
     
-Object attribute =
+return (Long)
  mBe
@@ -5096,53 +5096,8 @@
 e);%0A
-                    return (Long) attribute;%0A
     
@@ -5457,16 +5457,17 @@
 return 0
+L
 ;%0A    %7D%0A

Change the return value of JCacheMetrics.lookupStatistic() to Long