001/*
002 * Copyright 2002-2017 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.assembler;
018
019import javax.management.Descriptor;
020import javax.management.JMException;
021import javax.management.modelmbean.ModelMBeanAttributeInfo;
022import javax.management.modelmbean.ModelMBeanConstructorInfo;
023import javax.management.modelmbean.ModelMBeanInfo;
024import javax.management.modelmbean.ModelMBeanInfoSupport;
025import javax.management.modelmbean.ModelMBeanNotificationInfo;
026import javax.management.modelmbean.ModelMBeanOperationInfo;
027
028import org.springframework.aop.support.AopUtils;
029import org.springframework.jmx.support.JmxUtils;
030
031/**
032 * Abstract implementation of the {@code MBeanInfoAssembler} interface
033 * that encapsulates the creation of a {@code ModelMBeanInfo} instance
034 * but delegates the creation of metadata to subclasses.
035 *
036 * <p>This class offers two flavors of Class extraction from a managed bean
037 * instance: {@link #getTargetClass}, extracting the target class behind
038 * any kind of AOP proxy, and {@link #getClassToExpose}, returning the
039 * class or interface that will be searched for annotations and exposed
040 * to the JMX runtime.
041 *
042 * @author Rob Harrop
043 * @author Juergen Hoeller
044 * @since 1.2
045 */
046public abstract class AbstractMBeanInfoAssembler implements MBeanInfoAssembler {
047
048        /**
049         * Create an instance of the {@code ModelMBeanInfoSupport} class supplied with all
050         * JMX implementations and populates the metadata through calls to the subclass.
051         * @param managedBean the bean that will be exposed (might be an AOP proxy)
052         * @param beanKey the key associated with the managed bean
053         * @return the populated ModelMBeanInfo instance
054         * @throws JMException in case of errors
055         * @see #getDescription(Object, String)
056         * @see #getAttributeInfo(Object, String)
057         * @see #getConstructorInfo(Object, String)
058         * @see #getOperationInfo(Object, String)
059         * @see #getNotificationInfo(Object, String)
060         * @see #populateMBeanDescriptor(javax.management.Descriptor, Object, String)
061         */
062        @Override
063        public ModelMBeanInfo getMBeanInfo(Object managedBean, String beanKey) throws JMException {
064                checkManagedBean(managedBean);
065                ModelMBeanInfo info = new ModelMBeanInfoSupport(
066                                getClassName(managedBean, beanKey), getDescription(managedBean, beanKey),
067                                getAttributeInfo(managedBean, beanKey), getConstructorInfo(managedBean, beanKey),
068                                getOperationInfo(managedBean, beanKey), getNotificationInfo(managedBean, beanKey));
069                Descriptor desc = info.getMBeanDescriptor();
070                populateMBeanDescriptor(desc, managedBean, beanKey);
071                info.setMBeanDescriptor(desc);
072                return info;
073        }
074
075        /**
076         * Check the given bean instance, throwing an IllegalArgumentException
077         * if it is not eligible for exposure with this assembler.
078         * <p>Default implementation is empty, accepting every bean instance.
079         * @param managedBean the bean that will be exposed (might be an AOP proxy)
080         * @throws IllegalArgumentException the bean is not valid for exposure
081         */
082        protected void checkManagedBean(Object managedBean) throws IllegalArgumentException {
083        }
084
085        /**
086         * Return the actual bean class of the given bean instance.
087         * This is the class exposed to description-style JMX properties.
088         * <p>Default implementation returns the target class for an AOP proxy,
089         * and the plain bean class else.
090         * @param managedBean the bean instance (might be an AOP proxy)
091         * @return the bean class to expose
092         * @see org.springframework.aop.support.AopUtils#getTargetClass(Object)
093         */
094        protected Class<?> getTargetClass(Object managedBean) {
095                return AopUtils.getTargetClass(managedBean);
096        }
097
098        /**
099         * Return the class or interface to expose for the given bean.
100         * This is the class that will be searched for attributes and operations
101         * (for example, checked for annotations).
102         * @param managedBean the bean instance (might be an AOP proxy)
103         * @return the bean class to expose
104         * @see JmxUtils#getClassToExpose(Object)
105         */
106        protected Class<?> getClassToExpose(Object managedBean) {
107                return JmxUtils.getClassToExpose(managedBean);
108        }
109
110        /**
111         * Return the class or interface to expose for the given bean class.
112         * This is the class that will be searched for attributes and operations
113         * @param beanClass the bean class (might be an AOP proxy class)
114         * @return the bean class to expose
115         * @see JmxUtils#getClassToExpose(Class)
116         */
117        protected Class<?> getClassToExpose(Class<?> beanClass) {
118                return JmxUtils.getClassToExpose(beanClass);
119        }
120
121        /**
122         * Get the class name of the MBean resource.
123         * <p>Default implementation returns a simple description for the MBean
124         * based on the class name.
125         * @param managedBean the bean instance (might be an AOP proxy)
126         * @param beanKey the key associated with the MBean in the beans map
127         * of the {@code MBeanExporter}
128         * @return the MBean description
129         * @throws JMException in case of errors
130         */
131        protected String getClassName(Object managedBean, String beanKey) throws JMException {
132                return getTargetClass(managedBean).getName();
133        }
134
135        /**
136         * Get the description of the MBean resource.
137         * <p>Default implementation returns a simple description for the MBean
138         * based on the class name.
139         * @param managedBean the bean instance (might be an AOP proxy)
140         * @param beanKey the key associated with the MBean in the beans map
141         * of the {@code MBeanExporter}
142         * @throws JMException in case of errors
143         */
144        protected String getDescription(Object managedBean, String beanKey) throws JMException {
145                String targetClassName = getTargetClass(managedBean).getName();
146                if (AopUtils.isAopProxy(managedBean)) {
147                        return "Proxy for " + targetClassName;
148                }
149                return targetClassName;
150        }
151
152        /**
153         * Called after the {@code ModelMBeanInfo} instance has been constructed but
154         * before it is passed to the {@code MBeanExporter}.
155         * <p>Subclasses can implement this method to add additional descriptors to the
156         * MBean metadata. Default implementation is empty.
157         * @param descriptor the {@code Descriptor} for the MBean resource.
158         * @param managedBean the bean instance (might be an AOP proxy)
159         * @param beanKey the key associated with the MBean in the beans map
160         * of the {@code MBeanExporter}
161         * @throws JMException in case of errors
162         */
163        protected void populateMBeanDescriptor(Descriptor descriptor, Object managedBean, String beanKey)
164                        throws JMException {
165        }
166
167        /**
168         * Get the constructor metadata for the MBean resource. Subclasses should implement
169         * this method to return the appropriate metadata for all constructors that should
170         * be exposed in the management interface for the managed resource.
171         * <p>Default implementation returns an empty array of {@code ModelMBeanConstructorInfo}.
172         * @param managedBean the bean instance (might be an AOP proxy)
173         * @param beanKey the key associated with the MBean in the beans map
174         * of the {@code MBeanExporter}
175         * @return the constructor metadata
176         * @throws JMException in case of errors
177         */
178        protected ModelMBeanConstructorInfo[] getConstructorInfo(Object managedBean, String beanKey)
179                        throws JMException {
180                return new ModelMBeanConstructorInfo[0];
181        }
182
183        /**
184         * Get the notification metadata for the MBean resource. Subclasses should implement
185         * this method to return the appropriate metadata for all notifications that should
186         * be exposed in the management interface for the managed resource.
187         * <p>Default implementation returns an empty array of {@code ModelMBeanNotificationInfo}.
188         * @param managedBean the bean instance (might be an AOP proxy)
189         * @param beanKey the key associated with the MBean in the beans map
190         * of the {@code MBeanExporter}
191         * @return the notification metadata
192         * @throws JMException in case of errors
193         */
194        protected ModelMBeanNotificationInfo[] getNotificationInfo(Object managedBean, String beanKey)
195                        throws JMException {
196                return new ModelMBeanNotificationInfo[0];
197        }
198
199
200        /**
201         * Get the attribute metadata for the MBean resource. Subclasses should implement
202         * this method to return the appropriate metadata for all the attributes that should
203         * be exposed in the management interface for the managed resource.
204         * @param managedBean the bean instance (might be an AOP proxy)
205         * @param beanKey the key associated with the MBean in the beans map
206         * of the {@code MBeanExporter}
207         * @return the attribute metadata
208         * @throws JMException in case of errors
209         */
210        protected abstract ModelMBeanAttributeInfo[] getAttributeInfo(Object managedBean, String beanKey)
211                        throws JMException;
212
213        /**
214         * Get the operation metadata for the MBean resource. Subclasses should implement
215         * this method to return the appropriate metadata for all operations that should
216         * be exposed in the management interface for the managed resource.
217         * @param managedBean the bean instance (might be an AOP proxy)
218         * @param beanKey the key associated with the MBean in the beans map
219         * of the {@code MBeanExporter}
220         * @return the operation metadata
221         * @throws JMException in case of errors
222         */
223        protected abstract ModelMBeanOperationInfo[] getOperationInfo(Object managedBean, String beanKey)
224                        throws JMException;
225
226}