001/* 002 * Copyright 2002-2018 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.io.IOException; 020import java.util.Properties; 021 022import javax.management.MalformedObjectNameException; 023import javax.management.ObjectName; 024 025import org.apache.commons.logging.Log; 026import org.apache.commons.logging.LogFactory; 027 028import org.springframework.beans.factory.InitializingBean; 029import org.springframework.core.io.Resource; 030import org.springframework.core.io.support.PropertiesLoaderUtils; 031import org.springframework.jmx.support.ObjectNameManager; 032import org.springframework.lang.Nullable; 033import org.springframework.util.Assert; 034import org.springframework.util.CollectionUtils; 035 036/** 037 * {@code ObjectNamingStrategy} implementation that builds 038 * {@code ObjectName} instances from the key used in the 039 * "beans" map passed to {@code MBeanExporter}. 040 * 041 * <p>Can also check object name mappings, given as {@code Properties} 042 * or as {@code mappingLocations} of properties files. The key used 043 * to look up is the key used in {@code MBeanExporter}'s "beans" map. 044 * If no mapping is found for a given key, the key itself is used to 045 * build an {@code ObjectName}. 046 * 047 * @author Rob Harrop 048 * @author Juergen Hoeller 049 * @since 1.2 050 * @see #setMappings 051 * @see #setMappingLocation 052 * @see #setMappingLocations 053 * @see org.springframework.jmx.export.MBeanExporter#setBeans 054 */ 055public class KeyNamingStrategy implements ObjectNamingStrategy, InitializingBean { 056 057 /** 058 * {@code Log} instance for this class. 059 */ 060 protected final Log logger = LogFactory.getLog(getClass()); 061 062 /** 063 * Stores the mappings of bean key to {@code ObjectName}. 064 */ 065 @Nullable 066 private Properties mappings; 067 068 /** 069 * Stores the {@code Resource}s containing properties that should be loaded 070 * into the final merged set of {@code Properties} used for {@code ObjectName} 071 * resolution. 072 */ 073 @Nullable 074 private Resource[] mappingLocations; 075 076 /** 077 * Stores the result of merging the {@code mappings} {@code Properties} 078 * with the properties stored in the resources defined by {@code mappingLocations}. 079 */ 080 @Nullable 081 private Properties mergedMappings; 082 083 084 /** 085 * Set local properties, containing object name mappings, e.g. via 086 * the "props" tag in XML bean definitions. These can be considered 087 * defaults, to be overridden by properties loaded from files. 088 */ 089 public void setMappings(Properties mappings) { 090 this.mappings = mappings; 091 } 092 093 /** 094 * Set a location of a properties file to be loaded, 095 * containing object name mappings. 096 */ 097 public void setMappingLocation(Resource location) { 098 this.mappingLocations = new Resource[] {location}; 099 } 100 101 /** 102 * Set location of properties files to be loaded, 103 * containing object name mappings. 104 */ 105 public void setMappingLocations(Resource... mappingLocations) { 106 this.mappingLocations = mappingLocations; 107 } 108 109 110 /** 111 * Merges the {@code Properties} configured in the {@code mappings} and 112 * {@code mappingLocations} into the final {@code Properties} instance 113 * used for {@code ObjectName} resolution. 114 */ 115 @Override 116 public void afterPropertiesSet() throws IOException { 117 this.mergedMappings = new Properties(); 118 CollectionUtils.mergePropertiesIntoMap(this.mappings, this.mergedMappings); 119 120 if (this.mappingLocations != null) { 121 for (Resource location : this.mappingLocations) { 122 if (logger.isDebugEnabled()) { 123 logger.debug("Loading JMX object name mappings file from " + location); 124 } 125 PropertiesLoaderUtils.fillProperties(this.mergedMappings, location); 126 } 127 } 128 } 129 130 131 /** 132 * Attempts to retrieve the {@code ObjectName} via the given key, trying to 133 * find a mapped value in the mappings first. 134 */ 135 @Override 136 public ObjectName getObjectName(Object managedBean, @Nullable String beanKey) throws MalformedObjectNameException { 137 Assert.notNull(beanKey, "KeyNamingStrategy requires bean key"); 138 String objectName = null; 139 if (this.mergedMappings != null) { 140 objectName = this.mergedMappings.getProperty(beanKey); 141 } 142 if (objectName == null) { 143 objectName = beanKey; 144 } 145 return ObjectNameManager.getInstance(objectName); 146 } 147 148}