001    /**
002     *
003     * Copyright 2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  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.geronimo.jmxremoting;
018    
019    import java.net.InetSocketAddress;
020    import java.util.HashMap;
021    import java.util.Map;
022    import javax.management.remote.JMXConnectorServer;
023    import javax.management.remote.JMXConnectorServerFactory;
024    import javax.management.remote.JMXServiceURL;
025    import javax.management.remote.JMXConnectionNotification;
026    import javax.management.MBeanServer;
027    import javax.management.NotificationFilterSupport;
028    
029    import org.apache.commons.logging.Log;
030    import org.apache.commons.logging.LogFactory;
031    import org.apache.geronimo.gbean.GBeanInfo;
032    import org.apache.geronimo.gbean.GBeanInfoBuilder;
033    import org.apache.geronimo.gbean.GBeanLifecycle;
034    import org.apache.geronimo.system.jmx.MBeanServerReference;
035    
036    /**
037     * A Connector that supports the server sideof JSR 160 JMX Remoting.
038     *
039     * @version $Rev: 395155 $ $Date: 2006-04-18 23:44:24 -0700 (Tue, 18 Apr 2006) $
040     */
041    public class JMXConnector implements GBeanLifecycle {
042        private final MBeanServer mbeanServer;
043        private final Log log;
044        private final ClassLoader classLoader;
045        private String applicationConfigName;
046        private Authenticator authenticator;
047    
048        private String protocol;
049        private String host;
050        private int port = -1;
051        private String urlPath;
052    
053        private JMXConnectorServer server;
054        private JMXServiceURL jmxServiceURL;
055    
056        // todo remove this as soon as Geronimo supports factory beans
057        public JMXConnector(MBeanServerReference mbeanServerReference, String objectName, ClassLoader classLoader) {
058            this(mbeanServerReference.getMBeanServer(), objectName, classLoader);
059        }
060    
061        /**
062         * Constructor for creating the connector. The ClassLoader must be
063         * able to load all the LoginModules used in the JAAS login
064         *
065         * @param mbeanServer the mbean server
066         * @param objectName this connector's object name
067         * @param classLoader the classLoader used to create this connector
068         */
069        public JMXConnector(MBeanServer mbeanServer, String objectName, ClassLoader classLoader) {
070            this.mbeanServer = mbeanServer;
071            this.classLoader = classLoader;
072            log = LogFactory.getLog(objectName);
073        }
074    
075        /**
076         * Return the name of the JAAS Application Configuration Entry this
077         * connector uses to authenticate users. If null, users are not
078         * be authenticated (not recommended).
079         *
080         * @return the authentication configuration name
081         */
082        public String getApplicationConfigName() {
083            return applicationConfigName;
084        }
085    
086        /**
087         * Set the name of the JAAS Application Configuration Entry this
088         * connector should use to authenticate users. If null, users will not
089         * be authenticated (not recommended).
090         *
091         * @param applicationConfigName the authentication configuration name
092         */
093        public void setApplicationConfigName(String applicationConfigName) {
094            this.applicationConfigName = applicationConfigName;
095        }
096    
097        /**
098         * Every connector must specify a property of type InetSocketAddress
099         * because we use that to identify the network services to print a list
100         * during startup.  However, this can be read-only since the host and port
101         * are set in the url attribute.
102         */
103        public InetSocketAddress getListenAddress() {
104            return new InetSocketAddress(getHost(), getPort());
105        }
106    
107        /**
108         * Gets the protocol to use for the connection.
109         * @return the protocol to use for the connection
110         */
111        public String getProtocol() {
112            return protocol;
113        }
114    
115        /**
116         * Sets the protocol to use for the connection.
117         * @param protocol the protocol to use for the connection
118         */
119        public void setProtocol(String protocol) {
120            this.protocol = protocol;
121        }
122    
123        /**
124         * Gets the JMX host for this connector.
125         *
126         * @return the JMX host for this connector
127         */
128        public String getHost() {
129            return host;
130        }
131    
132        /**
133         * Sets the JMX host for this connector.
134         * @param host the JMX host for this connector
135         */
136        public void setHost(String host) {
137            this.host = host;
138        }
139    
140        /**
141         * Gets the JMX port for this connector.
142         *
143         * @return the JMX port for this connector
144         */
145        public int getPort() {
146            return port;
147        }
148    
149        /**
150         * Sets the JMX port for this connector.
151         * @param port the JMX port for this connector
152         */
153        public void setPort(int port) {
154            this.port = port;
155        }
156    
157        /**
158         * Gets the path within the target server to look for the connection.  This is commonly
159         * /jndi/rmi://localhost:1099/JMXConnector
160         * @return the path used to loacate the connector on the target server
161         */
162        public String getUrlPath() {
163            return urlPath;
164        }
165    
166        /**
167         * Sets the path within the target server to look for the connection.  This is commonly
168         * /jndi/rmi://localhost:1099/JMXConnector
169         * @param urlPath the path used to loacate the connector on the target server
170         */
171        public void setUrlPath(String urlPath) {
172            this.urlPath = urlPath;
173        }
174    
175        public void doStart() throws Exception {
176            jmxServiceURL = new JMXServiceURL(protocol, host, port, urlPath);
177            Map env = new HashMap();
178            if (applicationConfigName != null) {
179                authenticator = new Authenticator(applicationConfigName, classLoader);
180                env.put(JMXConnectorServer.AUTHENTICATOR, authenticator);
181            } else {
182                log.warn("Starting unauthenticating JMXConnector for " + jmxServiceURL);
183            }
184            server = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, env, mbeanServer);
185            NotificationFilterSupport filter = new NotificationFilterSupport();
186            filter.enableType(JMXConnectionNotification.OPENED);
187            filter.enableType(JMXConnectionNotification.CLOSED);
188            filter.enableType(JMXConnectionNotification.FAILED);
189            server.addNotificationListener(authenticator, filter, null);
190            server.start();
191            log.debug("Started JMXConnector " + server.getAddress());
192        }
193    
194        public void doStop() throws Exception {
195            try {
196                  server.stop();
197            } catch (java.io.IOException e) {
198                  // java.io.IOException is expected.
199            } catch (Exception e) {
200                  // Otherwise, something bad happened.  Rethrow the exception.
201                  throw e;
202            }
203            finally {
204              server = null;
205              log.debug("Stopped JMXConnector " + jmxServiceURL);
206            }
207        }
208    
209        public void doFail() {
210            try {
211                doStop();
212                log.warn("Failure in JMXConnector " + jmxServiceURL);
213            } catch (Exception e) {
214                log.warn("Error stopping JMXConnector after failure", e);
215            }
216        }
217    
218        public static final GBeanInfo GBEAN_INFO;
219    
220        static {
221            GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic("JMX Remoting Connector", JMXConnector.class);
222            infoFactory.addReference("MBeanServerReference", MBeanServerReference.class);
223            infoFactory.addAttribute("objectName", String.class, false);
224            infoFactory.addAttribute("classLoader", ClassLoader.class, false);
225    
226            infoFactory.addAttribute("protocol", String.class, true, true);
227            infoFactory.addAttribute("host", String.class, true, true);
228            infoFactory.addAttribute("port", int.class, true, true);
229            infoFactory.addAttribute("urlPath", String.class, true, true);
230            infoFactory.addAttribute("applicationConfigName", String.class, true, true);
231    
232            infoFactory.setConstructor(new String[]{"MBeanServerReference", "objectName", "classLoader"});
233            GBEAN_INFO = infoFactory.getBeanInfo();
234        }
235    
236        public static GBeanInfo getGBeanInfo() {
237            return GBEAN_INFO;
238        }
239    }