/** * Copyright © 2013 Antonin Stefanutti (antonin.stefanutti@gmail.com) * * 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 * * 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 io.astefanutti.metrics.cdi; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.annotation.CachedGauge; import com.codahale.metrics.annotation.Counted; import com.codahale.metrics.annotation.ExceptionMetered; import com.codahale.metrics.annotation.Gauge; import com.codahale.metrics.annotation.Metered; import com.codahale.metrics.annotation.Timed; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Vetoed; import javax.inject.Inject; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; @ApplicationScoped /* package-private */ class MetricResolver { @Inject private MetricsExtension extension; @Inject private MetricName metricName; Of<CachedGauge> cachedGauge(Method method) { return resolverOf(method, CachedGauge.class); } <E extends Member & AnnotatedElement> Of<Counted> counted(E element) { return resolverOf(element, Counted.class); } <E extends Member & AnnotatedElement> Of<ExceptionMetered> exceptionMetered(E element) { return resolverOf(element, ExceptionMetered.class); } Of<Gauge> gauge(Method method) { return resolverOf(method, Gauge.class); } <E extends Member & AnnotatedElement> Of<Metered> metered(E element) { return resolverOf(element, Metered.class); } <E extends Member & AnnotatedElement> Of<Timed> timed(E element) { return resolverOf(element, Timed.class); } private <E extends Member & AnnotatedElement, T extends Annotation> Of<T> resolverOf(E element, Class<T> type) { if (element.isAnnotationPresent(type)) { T annotation = element.getAnnotation(type); String name = metricName(element, type, metricName(annotation), isMetricAbsolute(annotation)); return new DoesHaveMetric<>(annotation, name); } else { Class<?> bean = element.getDeclaringClass(); if (bean.isAnnotationPresent(type)) { T annotation = bean.getAnnotation(type); String name = metricName(bean, element, type, metricName(annotation), isMetricAbsolute(annotation)); return new DoesHaveMetric<>(annotation, name); } } return new DoesNotHaveMetric<>(); } // TODO: should be grouped with the metric name strategy private <E extends Member & AnnotatedElement> String metricName(E element, Class<? extends Annotation> type, String name, boolean absolute) { String metric = name.isEmpty() ? defaultName(element, type) : metricName.of(name); return absolute ? metric : MetricRegistry.name(element.getDeclaringClass(), metric); } private <E extends Member & AnnotatedElement> String metricName(Class<?> bean, E element, Class<? extends Annotation> type, String name, boolean absolute) { String metric = name.isEmpty() ? bean.getSimpleName() : metricName.of(name); return absolute ? MetricRegistry.name(metric, defaultName(element, type)) : MetricRegistry.name(bean.getPackage().getName(), metric, defaultName(element, type)); } private <E extends Member & AnnotatedElement> String defaultName(E element, Class<? extends Annotation> type) { if (ExceptionMetered.class.equals(type)) return MetricRegistry.name(memberName(element), ExceptionMetered.DEFAULT_NAME_SUFFIX); else return memberName(element); } // While the Member Javadoc states that the getName method should returns // the simple name of the underlying member or constructor, the FQN is returned // for constructors. See JDK-6294399: // http://bugs.java.com/view_bug.do?bug_id=6294399 private String memberName(Member member) { if (member instanceof Constructor) return member.getDeclaringClass().getSimpleName(); else return member.getName(); } private String metricName(Annotation annotation) { if (CachedGauge.class.isInstance(annotation)) return ((CachedGauge) annotation).name(); else if (Counted.class.isInstance(annotation)) return ((Counted) annotation).name(); else if (ExceptionMetered.class.isInstance(annotation)) return ((ExceptionMetered) annotation).name(); else if (Gauge.class.isInstance(annotation)) return ((Gauge) annotation).name(); else if (Metered.class.isInstance(annotation)) return ((Metered) annotation).name(); else if (Timed.class.isInstance(annotation)) return ((Timed) annotation).name(); else throw new IllegalArgumentException("Unsupported Metrics forMethod [" + annotation.getClass().getName() + "]"); } private boolean isMetricAbsolute(Annotation annotation) { if (extension.getParameters().contains(MetricsParameter.useAbsoluteName)) return true; if (CachedGauge.class.isInstance(annotation)) return ((CachedGauge) annotation).absolute(); else if (Counted.class.isInstance(annotation)) return ((Counted) annotation).absolute(); else if (ExceptionMetered.class.isInstance(annotation)) return ((ExceptionMetered) annotation).absolute(); else if (Gauge.class.isInstance(annotation)) return ((Gauge) annotation).absolute(); else if (Metered.class.isInstance(annotation)) return ((Metered) annotation).absolute(); else if (Timed.class.isInstance(annotation)) return ((Timed) annotation).absolute(); else throw new IllegalArgumentException("Unsupported Metrics forMethod [" + annotation.getClass().getName() + "]"); } interface Of<T extends Annotation> { boolean isPresent(); String metricName(); T metricAnnotation(); } private static final class DoesHaveMetric<T extends Annotation> implements Of<T> { private final T annotation; private final String name; private DoesHaveMetric(T annotation, String name) { this.annotation = annotation; this.name = name; } @Override public boolean isPresent() { return true; } @Override public String metricName() { return name; } @Override public T metricAnnotation() { return annotation; } } @Vetoed private static final class DoesNotHaveMetric<T extends Annotation> implements Of<T> { private DoesNotHaveMetric() { } @Override public boolean isPresent() { return false; } @Override public String metricName() { throw new UnsupportedOperationException(); } @Override public T metricAnnotation() { throw new UnsupportedOperationException(); } } }