001/*
002 * Copyright 2002-2016 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jmx.export.annotation;
018
019import java.lang.annotation.Annotation;
020import java.lang.reflect.Array;
021import java.lang.reflect.Method;
022import java.lang.reflect.Modifier;
023import java.util.Collection;
024import java.util.Set;
025
026import org.springframework.beans.BeanUtils;
027import org.springframework.beans.annotation.AnnotationBeanUtils;
028import org.springframework.beans.factory.BeanFactory;
029import org.springframework.beans.factory.BeanFactoryAware;
030import org.springframework.beans.factory.config.ConfigurableBeanFactory;
031import org.springframework.beans.factory.config.EmbeddedValueResolver;
032import org.springframework.core.annotation.AnnotationUtils;
033import org.springframework.jmx.export.metadata.InvalidMetadataException;
034import org.springframework.jmx.export.metadata.JmxAttributeSource;
035import org.springframework.util.StringValueResolver;
036
037/**
038 * Implementation of the {@code JmxAttributeSource} interface that
039 * reads annotations and exposes the corresponding attributes.
040 *
041 * @author Rob Harrop
042 * @author Juergen Hoeller
043 * @author Jennifer Hickey
044 * @author Stephane Nicoll
045 * @since 1.2
046 * @see ManagedResource
047 * @see ManagedAttribute
048 * @see ManagedOperation
049 */
050public class AnnotationJmxAttributeSource implements JmxAttributeSource, BeanFactoryAware {
051
052        private StringValueResolver embeddedValueResolver;
053
054
055        @Override
056        public void setBeanFactory(BeanFactory beanFactory) {
057                if (beanFactory instanceof ConfigurableBeanFactory) {
058                        this.embeddedValueResolver = new EmbeddedValueResolver((ConfigurableBeanFactory) beanFactory);
059                }
060        }
061
062
063        @Override
064        public org.springframework.jmx.export.metadata.ManagedResource getManagedResource(Class<?> beanClass) throws InvalidMetadataException {
065                ManagedResource ann = AnnotationUtils.findAnnotation(beanClass, ManagedResource.class);
066                if (ann == null) {
067                        return null;
068                }
069                Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(ManagedResource.class, beanClass);
070                Class<?> target = (declaringClass != null && !declaringClass.isInterface() ? declaringClass : beanClass);
071                if (!Modifier.isPublic(target.getModifiers())) {
072                        throw new InvalidMetadataException("@ManagedResource class '" + target.getName() + "' must be public");
073                }
074                org.springframework.jmx.export.metadata.ManagedResource managedResource = new org.springframework.jmx.export.metadata.ManagedResource();
075                AnnotationBeanUtils.copyPropertiesToBean(ann, managedResource, this.embeddedValueResolver);
076                return managedResource;
077        }
078
079        @Override
080        public org.springframework.jmx.export.metadata.ManagedAttribute getManagedAttribute(Method method) throws InvalidMetadataException {
081                ManagedAttribute ann = AnnotationUtils.findAnnotation(method, ManagedAttribute.class);
082                if (ann == null) {
083                        return null;
084                }
085                org.springframework.jmx.export.metadata.ManagedAttribute managedAttribute = new org.springframework.jmx.export.metadata.ManagedAttribute();
086                AnnotationBeanUtils.copyPropertiesToBean(ann, managedAttribute, "defaultValue");
087                if (ann.defaultValue().length() > 0) {
088                        managedAttribute.setDefaultValue(ann.defaultValue());
089                }
090                return managedAttribute;
091        }
092
093        @Override
094        public org.springframework.jmx.export.metadata.ManagedMetric getManagedMetric(Method method) throws InvalidMetadataException {
095                ManagedMetric ann = AnnotationUtils.findAnnotation(method, ManagedMetric.class);
096                return copyPropertiesToBean(ann, org.springframework.jmx.export.metadata.ManagedMetric.class);
097        }
098
099        @Override
100        public org.springframework.jmx.export.metadata.ManagedOperation getManagedOperation(Method method) throws InvalidMetadataException {
101                ManagedOperation ann = AnnotationUtils.findAnnotation(method, ManagedOperation.class);
102                return copyPropertiesToBean(ann, org.springframework.jmx.export.metadata.ManagedOperation.class);
103        }
104
105        @Override
106        public org.springframework.jmx.export.metadata.ManagedOperationParameter[] getManagedOperationParameters(Method method)
107                        throws InvalidMetadataException {
108
109                Set<ManagedOperationParameter> anns = AnnotationUtils.getRepeatableAnnotations(
110                                method, ManagedOperationParameter.class, ManagedOperationParameters.class);
111                return copyPropertiesToBeanArray(anns, org.springframework.jmx.export.metadata.ManagedOperationParameter.class);
112        }
113
114        @Override
115        public org.springframework.jmx.export.metadata.ManagedNotification[] getManagedNotifications(Class<?> clazz)
116                        throws InvalidMetadataException {
117
118                Set<ManagedNotification> anns = AnnotationUtils.getRepeatableAnnotations(
119                                clazz, ManagedNotification.class, ManagedNotifications.class);
120                return copyPropertiesToBeanArray(anns, org.springframework.jmx.export.metadata.ManagedNotification.class);
121        }
122
123
124        @SuppressWarnings("unchecked")
125        private static <T> T[] copyPropertiesToBeanArray(Collection<? extends Annotation> anns, Class<T> beanClass) {
126                T[] beans = (T[]) Array.newInstance(beanClass, anns.size());
127                int i = 0;
128                for (Annotation ann : anns) {
129                        beans[i++] = copyPropertiesToBean(ann, beanClass);
130                }
131                return beans;
132        }
133
134        private static <T> T copyPropertiesToBean(Annotation ann, Class<T> beanClass) {
135                if (ann == null) {
136                        return null;
137                }
138                T bean = BeanUtils.instantiateClass(beanClass);
139                AnnotationBeanUtils.copyPropertiesToBean(ann, bean);
140                return bean;
141        }
142
143}