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.naming; 018 019import java.util.Hashtable; 020 021import javax.management.MalformedObjectNameException; 022import javax.management.ObjectName; 023 024import org.springframework.aop.support.AopUtils; 025import org.springframework.beans.factory.InitializingBean; 026import org.springframework.jmx.export.metadata.JmxAttributeSource; 027import org.springframework.jmx.export.metadata.ManagedResource; 028import org.springframework.jmx.support.ObjectNameManager; 029import org.springframework.lang.Nullable; 030import org.springframework.util.Assert; 031import org.springframework.util.ClassUtils; 032import org.springframework.util.StringUtils; 033 034/** 035 * An implementation of the {@link ObjectNamingStrategy} interface 036 * that reads the {@code ObjectName} from the source-level metadata. 037 * Falls back to the bean key (bean name) if no {@code ObjectName} 038 * can be found in source-level metadata. 039 * 040 * <p>Uses the {@link JmxAttributeSource} strategy interface, so that 041 * metadata can be read using any supported implementation. Out of the box, 042 * {@link org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource} 043 * introspects a well-defined set of Java 5 annotations that come with Spring. 044 * 045 * @author Rob Harrop 046 * @author Juergen Hoeller 047 * @since 1.2 048 * @see ObjectNamingStrategy 049 * @see org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource 050 */ 051public class MetadataNamingStrategy implements ObjectNamingStrategy, InitializingBean { 052 053 /** 054 * The {@code JmxAttributeSource} implementation to use for reading metadata. 055 */ 056 @Nullable 057 private JmxAttributeSource attributeSource; 058 059 @Nullable 060 private String defaultDomain; 061 062 063 /** 064 * Create a new {@code MetadataNamingStrategy} which needs to be 065 * configured through the {@link #setAttributeSource} method. 066 */ 067 public MetadataNamingStrategy() { 068 } 069 070 /** 071 * Create a new {@code MetadataNamingStrategy} for the given 072 * {@code JmxAttributeSource}. 073 * @param attributeSource the JmxAttributeSource to use 074 */ 075 public MetadataNamingStrategy(JmxAttributeSource attributeSource) { 076 Assert.notNull(attributeSource, "JmxAttributeSource must not be null"); 077 this.attributeSource = attributeSource; 078 } 079 080 081 /** 082 * Set the implementation of the {@code JmxAttributeSource} interface to use 083 * when reading the source-level metadata. 084 */ 085 public void setAttributeSource(JmxAttributeSource attributeSource) { 086 Assert.notNull(attributeSource, "JmxAttributeSource must not be null"); 087 this.attributeSource = attributeSource; 088 } 089 090 /** 091 * Specify the default domain to be used for generating ObjectNames 092 * when no source-level metadata has been specified. 093 * <p>The default is to use the domain specified in the bean name 094 * (if the bean name follows the JMX ObjectName syntax); else, 095 * the package name of the managed bean class. 096 */ 097 public void setDefaultDomain(String defaultDomain) { 098 this.defaultDomain = defaultDomain; 099 } 100 101 @Override 102 public void afterPropertiesSet() { 103 if (this.attributeSource == null) { 104 throw new IllegalArgumentException("Property 'attributeSource' is required"); 105 } 106 } 107 108 109 /** 110 * Reads the {@code ObjectName} from the source-level metadata associated 111 * with the managed resource's {@code Class}. 112 */ 113 @Override 114 public ObjectName getObjectName(Object managedBean, @Nullable String beanKey) throws MalformedObjectNameException { 115 Assert.state(this.attributeSource != null, "No JmxAttributeSource set"); 116 Class<?> managedClass = AopUtils.getTargetClass(managedBean); 117 ManagedResource mr = this.attributeSource.getManagedResource(managedClass); 118 119 // Check that an object name has been specified. 120 if (mr != null && StringUtils.hasText(mr.getObjectName())) { 121 return ObjectNameManager.getInstance(mr.getObjectName()); 122 } 123 else { 124 Assert.state(beanKey != null, "No ManagedResource attribute and no bean key specified"); 125 try { 126 return ObjectNameManager.getInstance(beanKey); 127 } 128 catch (MalformedObjectNameException ex) { 129 String domain = this.defaultDomain; 130 if (domain == null) { 131 domain = ClassUtils.getPackageName(managedClass); 132 } 133 Hashtable<String, String> properties = new Hashtable<>(); 134 properties.put("type", ClassUtils.getShortName(managedClass)); 135 properties.put("name", beanKey); 136 return ObjectNameManager.getInstance(domain, properties); 137 } 138 } 139 } 140 141}