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