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}