001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.jmx.support;
018:
019: import java.io.IOException;
020: import java.net.MalformedURLException;
021: import java.util.Map;
022: import java.util.Properties;
023:
024: import javax.management.MBeanServerConnection;
025: import javax.management.remote.JMXConnector;
026: import javax.management.remote.JMXConnectorFactory;
027: import javax.management.remote.JMXServiceURL;
028:
029: import org.springframework.aop.TargetSource;
030: import org.springframework.aop.framework.ProxyFactory;
031: import org.springframework.aop.target.AbstractLazyCreationTargetSource;
032: import org.springframework.beans.factory.BeanClassLoaderAware;
033: import org.springframework.beans.factory.DisposableBean;
034: import org.springframework.beans.factory.FactoryBean;
035: import org.springframework.beans.factory.InitializingBean;
036: import org.springframework.util.ClassUtils;
037:
038: /**
039: * <code>FactoryBean</code> implementation that creates an <code>MBeanServerConnection</code>
040: * to a remote <code>MBeanServer</code> exposed via a <code>JMXServerConnector</code>.
041: * Exposes the <code>MBeanServer</code> for bean references.
042: *
043: * @author Rob Harrop
044: * @author Juergen Hoeller
045: * @since 1.2
046: * @see MBeanServerFactoryBean
047: * @see ConnectorServerFactoryBean
048: */
049: public class MBeanServerConnectionFactoryBean implements FactoryBean,
050: BeanClassLoaderAware, InitializingBean, DisposableBean {
051:
052: private JMXServiceURL serviceUrl;
053:
054: private Map environment;
055:
056: private boolean connectOnStartup = true;
057:
058: private ClassLoader beanClassLoader = ClassUtils
059: .getDefaultClassLoader();
060:
061: private JMXConnector connector;
062:
063: private MBeanServerConnection connection;
064:
065: private JMXConnectorLazyInitTargetSource connectorTargetSource;
066:
067: /**
068: * Set the service URL of the remote <code>MBeanServer</code>.
069: */
070: public void setServiceUrl(String url) throws MalformedURLException {
071: this .serviceUrl = new JMXServiceURL(url);
072: }
073:
074: /**
075: * Set the environment properties used to construct the <code>JMXConnector</code>
076: * as <code>java.util.Properties</code> (String key/value pairs).
077: */
078: public void setEnvironment(Properties environment) {
079: this .environment = environment;
080: }
081:
082: /**
083: * Set the environment properties used to construct the <code>JMXConnector</code>
084: * as a <code>Map</code> of String keys and arbitrary Object values.
085: */
086: public void setEnvironmentMap(Map environment) {
087: this .environment = environment;
088: }
089:
090: /**
091: * Set whether to connect to the server on startup. Default is "true".
092: * <p>Can be turned off to allow for late start of the JMX server.
093: * In this case, the JMX connector will be fetched on first access.
094: */
095: public void setConnectOnStartup(boolean connectOnStartup) {
096: this .connectOnStartup = connectOnStartup;
097: }
098:
099: public void setBeanClassLoader(ClassLoader classLoader) {
100: this .beanClassLoader = classLoader;
101: }
102:
103: /**
104: * Creates a <code>JMXConnector</code> for the given settings
105: * and exposes the associated <code>MBeanServerConnection</code>.
106: */
107: public void afterPropertiesSet() throws IOException {
108: if (this .serviceUrl == null) {
109: throw new IllegalArgumentException("serviceUrl is required");
110: }
111:
112: if (this .connectOnStartup) {
113: connect();
114: } else {
115: createLazyConnection();
116: }
117: }
118:
119: /**
120: * Connects to the remote <code>MBeanServer</code> using the configured service URL and
121: * environment properties.
122: */
123: private void connect() throws IOException {
124: this .connector = JMXConnectorFactory.connect(this .serviceUrl,
125: this .environment);
126: this .connection = this .connector.getMBeanServerConnection();
127: }
128:
129: /**
130: * Creates lazy proxies for the <code>JMXConnector</code> and <code>MBeanServerConnection</code>
131: */
132: private void createLazyConnection() {
133: this .connectorTargetSource = new JMXConnectorLazyInitTargetSource();
134: TargetSource connectionTargetSource = new MBeanServerConnectionLazyInitTargetSource();
135:
136: this .connector = (JMXConnector) new ProxyFactory(
137: JMXConnector.class, this .connectorTargetSource)
138: .getProxy(this .beanClassLoader);
139: this .connection = (MBeanServerConnection) new ProxyFactory(
140: MBeanServerConnection.class, connectionTargetSource)
141: .getProxy(this .beanClassLoader);
142: }
143:
144: public Object getObject() {
145: return this .connection;
146: }
147:
148: public Class getObjectType() {
149: return (this .connection != null ? this .connection.getClass()
150: : MBeanServerConnection.class);
151: }
152:
153: public boolean isSingleton() {
154: return true;
155: }
156:
157: /**
158: * Closes the underlying <code>JMXConnector</code>.
159: */
160: public void destroy() throws IOException {
161: if (this .connectorTargetSource == null
162: || this .connectorTargetSource.isInitialized()) {
163: this .connector.close();
164: }
165: }
166:
167: /**
168: * Lazily creates a <code>JMXConnector</code> using the configured service URL
169: * and environment properties.
170: * @see MBeanServerConnectionFactoryBean#setServiceUrl(String)
171: * @see MBeanServerConnectionFactoryBean#setEnvironment(java.util.Properties)
172: */
173: private class JMXConnectorLazyInitTargetSource extends
174: AbstractLazyCreationTargetSource {
175:
176: protected Object createObject() throws Exception {
177: return JMXConnectorFactory.connect(serviceUrl, environment);
178: }
179:
180: public Class getTargetClass() {
181: return JMXConnector.class;
182: }
183: }
184:
185: /**
186: * Lazily creates an <code>MBeanServerConnection</code>.
187: */
188: private class MBeanServerConnectionLazyInitTargetSource extends
189: AbstractLazyCreationTargetSource {
190:
191: protected Object createObject() throws Exception {
192: return connector.getMBeanServerConnection();
193: }
194:
195: public Class getTargetClass() {
196: return MBeanServerConnection.class;
197: }
198: }
199:
200: }
|