001/* 002 * Copyright 2002-2012 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.support; 018 019import javax.management.MBeanServer; 020import javax.management.MBeanServerFactory; 021 022import org.apache.commons.logging.Log; 023import org.apache.commons.logging.LogFactory; 024 025import org.springframework.beans.factory.DisposableBean; 026import org.springframework.beans.factory.FactoryBean; 027import org.springframework.beans.factory.InitializingBean; 028import org.springframework.jmx.MBeanServerNotFoundException; 029 030/** 031 * {@link FactoryBean} that obtains an {@link javax.management.MBeanServer} reference 032 * through the standard JMX 1.2 {@link javax.management.MBeanServerFactory} 033 * API (which is available on JDK 1.5 or as part of a JMX 1.2 provider). 034 * Exposes the {@code MBeanServer} for bean references. 035 * 036 * <p>By default, {@code MBeanServerFactoryBean} will always create 037 * a new {@code MBeanServer} even if one is already running. To have 038 * the {@code MBeanServerFactoryBean} attempt to locate a running 039 * {@code MBeanServer} first, set the value of the 040 * "locateExistingServerIfPossible" property to "true". 041 * 042 * @author Rob Harrop 043 * @author Juergen Hoeller 044 * @since 1.2 045 * @see #setLocateExistingServerIfPossible 046 * @see #locateMBeanServer 047 * @see javax.management.MBeanServer 048 * @see javax.management.MBeanServerFactory#findMBeanServer 049 * @see javax.management.MBeanServerFactory#createMBeanServer 050 * @see javax.management.MBeanServerFactory#newMBeanServer 051 * @see MBeanServerConnectionFactoryBean 052 * @see ConnectorServerFactoryBean 053 */ 054public class MBeanServerFactoryBean implements FactoryBean<MBeanServer>, InitializingBean, DisposableBean { 055 056 protected final Log logger = LogFactory.getLog(getClass()); 057 058 private boolean locateExistingServerIfPossible = false; 059 060 private String agentId; 061 062 private String defaultDomain; 063 064 private boolean registerWithFactory = true; 065 066 private MBeanServer server; 067 068 private boolean newlyRegistered = false; 069 070 071 /** 072 * Set whether or not the {@code MBeanServerFactoryBean} should attempt 073 * to locate a running {@code MBeanServer} before creating one. 074 * <p>Default is {@code false}. 075 */ 076 public void setLocateExistingServerIfPossible(boolean locateExistingServerIfPossible) { 077 this.locateExistingServerIfPossible = locateExistingServerIfPossible; 078 } 079 080 /** 081 * Set the agent id of the {@code MBeanServer} to locate. 082 * <p>Default is none. If specified, this will result in an 083 * automatic attempt being made to locate the attendant MBeanServer, 084 * and (importantly) if said MBeanServer cannot be located no 085 * attempt will be made to create a new MBeanServer (and an 086 * MBeanServerNotFoundException will be thrown at resolution time). 087 * <p>Specifying the empty String indicates the platform MBeanServer. 088 * @see javax.management.MBeanServerFactory#findMBeanServer(String) 089 */ 090 public void setAgentId(String agentId) { 091 this.agentId = agentId; 092 } 093 094 /** 095 * Set the default domain to be used by the {@code MBeanServer}, 096 * to be passed to {@code MBeanServerFactory.createMBeanServer()} 097 * or {@code MBeanServerFactory.findMBeanServer()}. 098 * <p>Default is none. 099 * @see javax.management.MBeanServerFactory#createMBeanServer(String) 100 * @see javax.management.MBeanServerFactory#findMBeanServer(String) 101 */ 102 public void setDefaultDomain(String defaultDomain) { 103 this.defaultDomain = defaultDomain; 104 } 105 106 /** 107 * Set whether to register the {@code MBeanServer} with the 108 * {@code MBeanServerFactory}, making it available through 109 * {@code MBeanServerFactory.findMBeanServer()}. 110 * @see javax.management.MBeanServerFactory#createMBeanServer 111 * @see javax.management.MBeanServerFactory#findMBeanServer 112 */ 113 public void setRegisterWithFactory(boolean registerWithFactory) { 114 this.registerWithFactory = registerWithFactory; 115 } 116 117 118 /** 119 * Creates the {@code MBeanServer} instance. 120 */ 121 @Override 122 public void afterPropertiesSet() throws MBeanServerNotFoundException { 123 // Try to locate existing MBeanServer, if desired. 124 if (this.locateExistingServerIfPossible || this.agentId != null) { 125 try { 126 this.server = locateMBeanServer(this.agentId); 127 } 128 catch (MBeanServerNotFoundException ex) { 129 // If agentId was specified, we were only supposed to locate that 130 // specific MBeanServer; so let's bail if we can't find it. 131 if (this.agentId != null) { 132 throw ex; 133 } 134 logger.info("No existing MBeanServer found - creating new one"); 135 } 136 } 137 138 // Create a new MBeanServer and register it, if desired. 139 if (this.server == null) { 140 this.server = createMBeanServer(this.defaultDomain, this.registerWithFactory); 141 this.newlyRegistered = this.registerWithFactory; 142 } 143 } 144 145 /** 146 * Attempt to locate an existing {@code MBeanServer}. 147 * Called if {@code locateExistingServerIfPossible} is set to {@code true}. 148 * <p>The default implementation attempts to find an {@code MBeanServer} using 149 * a standard lookup. Subclasses may override to add additional location logic. 150 * @param agentId the agent identifier of the MBeanServer to retrieve. 151 * If this parameter is {@code null}, all registered MBeanServers are 152 * considered. 153 * @return the {@code MBeanServer} if found 154 * @throws org.springframework.jmx.MBeanServerNotFoundException 155 * if no {@code MBeanServer} could be found 156 * @see #setLocateExistingServerIfPossible 157 * @see JmxUtils#locateMBeanServer(String) 158 * @see javax.management.MBeanServerFactory#findMBeanServer(String) 159 */ 160 protected MBeanServer locateMBeanServer(String agentId) throws MBeanServerNotFoundException { 161 return JmxUtils.locateMBeanServer(agentId); 162 } 163 164 /** 165 * Create a new {@code MBeanServer} instance and register it with the 166 * {@code MBeanServerFactory}, if desired. 167 * @param defaultDomain the default domain, or {@code null} if none 168 * @param registerWithFactory whether to register the {@code MBeanServer} 169 * with the {@code MBeanServerFactory} 170 * @see javax.management.MBeanServerFactory#createMBeanServer 171 * @see javax.management.MBeanServerFactory#newMBeanServer 172 */ 173 protected MBeanServer createMBeanServer(String defaultDomain, boolean registerWithFactory) { 174 if (registerWithFactory) { 175 return MBeanServerFactory.createMBeanServer(defaultDomain); 176 } 177 else { 178 return MBeanServerFactory.newMBeanServer(defaultDomain); 179 } 180 } 181 182 183 @Override 184 public MBeanServer getObject() { 185 return this.server; 186 } 187 188 @Override 189 public Class<? extends MBeanServer> getObjectType() { 190 return (this.server != null ? this.server.getClass() : MBeanServer.class); 191 } 192 193 @Override 194 public boolean isSingleton() { 195 return true; 196 } 197 198 199 /** 200 * Unregisters the {@code MBeanServer} instance, if necessary. 201 */ 202 @Override 203 public void destroy() { 204 if (this.newlyRegistered) { 205 MBeanServerFactory.releaseMBeanServer(this.server); 206 } 207 } 208 209}