001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.jbi.jmx;
018    
019    import java.util.Map;
020    
021    import javax.management.MBeanServer;
022    import javax.management.MalformedObjectNameException;
023    
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.springframework.beans.factory.DisposableBean;
027    import org.springframework.beans.factory.FactoryBean;
028    import org.springframework.beans.factory.InitializingBean;
029    import org.springframework.core.Constants;
030    
031    /**
032     * <code>FactoryBean</code> that creates a JSR-160 <code>JMXConnectorServer</code>,
033     * optionally registers it with the <code>MBeanServer</code> and then starts it.
034     *
035     * <p>The <code>JMXConnectorServer</code> can be started in a separate thread by setting the
036     * <code>threaded</code> property to <code>true</code>. You can configure this thread to be a
037     * daemon thread by setting the <code>daemon</code> property to <code>true</code>.
038     *
039     * This xbean-enabled factory is a wrapper on top of the existing Spring
040     * factory bean.  It also logs the serviceUrl when starting.
041     * 
042     * @author gnodet
043     * @org.apache.xbean.XBean element="jmxConnector"
044     */
045    public class ConnectorServerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
046    
047        /**
048         * Constant indicating that registration should fail when
049         * attempting to register an MBean under a name that already exists.
050         * <p>This is the default registration behavior.
051         */
052        public static final int REGISTRATION_FAIL_ON_EXISTING = 0;
053    
054        /**
055         * Constant indicating that registration should ignore the affected MBean
056         * when attempting to register an MBean under a name that already exists.
057         */
058        public static final int REGISTRATION_IGNORE_EXISTING = 1;
059    
060        /**
061         * Constant indicating that registration should replace the affected MBean
062         * when attempting to register an MBean under a name that already exists.
063         */
064        public static final int REGISTRATION_REPLACE_EXISTING = 2;
065    
066        private static final Constants CONSTANTS = new Constants(ConnectorServerFactoryBean.class);
067    
068        private Log log = LogFactory.getLog(ConnectorServerFactoryBean.class);
069        private org.springframework.jmx.support.ConnectorServerFactoryBean csfb = 
070                        new org.springframework.jmx.support.ConnectorServerFactoryBean();
071        private String serviceUrl = org.springframework.jmx.support.ConnectorServerFactoryBean.DEFAULT_SERVICE_URL;
072        private boolean daemon;
073        private boolean threaded;
074        private Map environment;
075        private Object objectName;
076        private int registrationBehavior = REGISTRATION_FAIL_ON_EXISTING;
077        private MBeanServer server;
078        
079    
080        /**
081         * Set whether any threads started for the <code>JMXConnectorServer</code> should be
082         * started as daemon threads.
083         * @param daemon
084         * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setDaemon(boolean)
085         */
086        public void setDaemon(boolean daemon) {
087            this.daemon = daemon;
088        }
089    
090        /**
091         * Set the environment properties used to construct the <code>JMXConnector</code>
092         * as a <code>Map</code> of String keys and arbitrary Object values.
093         * @param environment
094         * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setEnvironmentMap(java.util.Map)
095         */
096        public void setEnvironment(Map environment) {
097            this.environment = environment;
098        }
099    
100        /**
101         * Set the <code>ObjectName</code> used to register the <code>JMXConnectorServer</code>
102         * itself with the <code>MBeanServer</code>.
103         * @param objectName
104         * @throws MalformedObjectNameException if the <code>ObjectName</code> is malformed
105         * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setObjectName(java.lang.String)
106         */
107        public void setObjectName(String objectName) throws MalformedObjectNameException {
108            this.objectName = objectName;
109        }
110        
111        /**
112         * Specify  what action should be taken when attempting to register an MBean
113         * under an {@link javax.management.ObjectName} that already exists.
114         * <p>Default is REGISTRATION_FAIL_ON_EXISTING.
115         * @see #setRegistrationBehaviorName(String)
116         * @see #REGISTRATION_FAIL_ON_EXISTING
117         * @see #REGISTRATION_IGNORE_EXISTING
118         * @see #REGISTRATION_REPLACE_EXISTING
119         * @param registrationBehavior
120         * @see org.springframework.jmx.support.MBeanRegistrationSupport#setRegistrationBehavior(int)
121         */
122        public void setRegistrationBehavior(int registrationBehavior) {
123            this.registrationBehavior = registrationBehavior;
124        }
125    
126        /**
127         * Set the registration behavior by the name of the corresponding constant,
128         * e.g. "REGISTRATION_IGNORE_EXISTING".
129         * @see #setRegistrationBehavior
130         * @see #REGISTRATION_FAIL_ON_EXISTING
131         * @see #REGISTRATION_IGNORE_EXISTING
132         * @see #REGISTRATION_REPLACE_EXISTING
133         * @param behavior
134         * @see org.springframework.jmx.support.MBeanRegistrationSupport#setRegistrationBehaviorName(java.lang.String)
135         */
136        public void setRegistrationBehaviorName(String behavior) {
137            setRegistrationBehavior(CONSTANTS.asNumber(behavior).intValue());
138        }
139    
140        /**
141         * Specify the <code>MBeanServer</code> instance with which all beans should
142         * be registered. The <code>MBeanExporter</code> will attempt to locate an
143         * existing <code>MBeanServer</code> if none is supplied.
144         * @param server
145         * @see org.springframework.jmx.support.MBeanRegistrationSupport#setServer(javax.management.MBeanServer)
146         */
147        public void setServer(MBeanServer server) {
148            this.server = server;
149        }
150    
151        /**
152         * Set the service URL for the <code>JMXConnectorServer</code>.
153         * @param serviceUrl
154         * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setServiceUrl(java.lang.String)
155         */
156        public void setServiceUrl(String serviceUrl) {
157            this.serviceUrl = serviceUrl;
158        }
159    
160        /**
161         * Set whether the <code>JMXConnectorServer</code> should be started in a separate thread.
162         * @param threaded
163         * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setThreaded(boolean)
164         */
165        public void setThreaded(boolean threaded) {
166            csfb.setThreaded(threaded);
167        }
168    
169        public Object getObject() throws Exception {
170            return csfb.getObject();
171        }
172    
173        public Class getObjectType() {
174            return csfb.getObjectType();
175        }
176    
177        public boolean isSingleton() {
178            return csfb.isSingleton();
179        }
180    
181        public void afterPropertiesSet() throws Exception {
182            csfb = new org.springframework.jmx.support.ConnectorServerFactoryBean();
183            csfb.setDaemon(daemon);
184            csfb.setThreaded(threaded);
185            csfb.setRegistrationBehavior(registrationBehavior);
186            csfb.setEnvironmentMap(environment);
187            csfb.setObjectName(objectName);
188            serviceUrl = serviceUrl.replaceAll(" ", "");
189            csfb.setServiceUrl(serviceUrl);
190            csfb.setServer(server);
191            csfb.afterPropertiesSet();
192            log.info("JMX connector available at: " + serviceUrl);
193        }
194    
195        public void destroy() throws Exception {
196            if (csfb != null) {
197                try {
198                    csfb.destroy();
199                } finally {
200                    csfb = null;
201                }
202            }
203        }
204    
205    }