001/*
002 * (C) Copyright 2013-2014 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl-2.1.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     slacoin
016 */
017package org.nuxeo.dmk;
018
019import java.io.IOException;
020import java.lang.management.ManagementFactory;
021import java.net.MalformedURLException;
022import java.util.HashMap;
023import java.util.Map;
024
025import javax.management.InstanceAlreadyExistsException;
026import javax.management.InstanceNotFoundException;
027import javax.management.JMException;
028import javax.management.MBeanRegistrationException;
029import javax.management.MBeanServer;
030import javax.management.MalformedObjectNameException;
031import javax.management.NotCompliantMBeanException;
032import javax.management.ObjectName;
033import javax.management.remote.JMXConnectorServerFactory;
034import javax.management.remote.JMXServiceURL;
035
036import org.apache.commons.logging.Log;
037import org.apache.commons.logging.LogFactory;
038import org.nuxeo.runtime.model.ComponentContext;
039import org.nuxeo.runtime.model.ComponentInstance;
040import org.nuxeo.runtime.model.DefaultComponent;
041
042import com.sun.jdmk.comm.AuthInfo;
043import com.sun.jdmk.comm.GenericHttpConnectorServer;
044import com.sun.jdmk.comm.HtmlAdaptorServer;
045import com.sun.jdmk.comm.internal.JDMKServerConnector;
046
047public class DmkComponent extends DefaultComponent {
048
049    protected final Map<String, DmkProtocol> configs = new HashMap<>();
050
051    protected HtmlAdaptorServer htmlAdaptor;
052
053    protected JDMKServerConnector httpConnector;
054
055    protected JDMKServerConnector httpsConnector;
056
057    protected final Log log = LogFactory.getLog(DmkComponent.class);
058
059    protected final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
060
061    protected HtmlAdaptorServer newAdaptor(DmkProtocol config) {
062        HtmlAdaptorServer adaptor = new HtmlAdaptorServer();
063        adaptor.addUserAuthenticationInfo(new AuthInfo(config.user, config.password));
064        adaptor.setPort(config.port);
065        try {
066            ObjectName name = new ObjectName("org.nuxeo:type=jmx-adaptor,format=html");
067            mbs.registerMBean(adaptor, name);
068        } catch (JMException e) {
069            throw new RuntimeException(e);
070        }
071        return adaptor;
072    }
073
074    protected void destroyAdaptor(HtmlAdaptorServer adaptor) {
075        try {
076            ObjectName name = new ObjectName("org.nuxeo:type=jmx-adaptor,format=html");
077            mbs.unregisterMBean(name);
078        } catch (JMException e) {
079            throw new RuntimeException(e);
080        }
081        if (!adaptor.isActive()) {
082            return;
083        }
084        adaptor.stop();
085    }
086
087    protected JDMKServerConnector newConnector(DmkProtocol config) {
088        try {
089            String protocol = "jdmk-".concat(config.name);
090            JMXServiceURL httpURL = new JMXServiceURL(protocol, null, config.port);
091            JDMKServerConnector connector = (JDMKServerConnector) JMXConnectorServerFactory.newJMXConnectorServer(
092                    httpURL, null, mbs);
093            GenericHttpConnectorServer server = (GenericHttpConnectorServer) connector.getWrapped();
094            server.addUserAuthenticationInfo(new AuthInfo(config.user, config.password));
095            ObjectName name = new ObjectName("org.nuxeo:type=jmx-connector,protocol=".concat(protocol));
096            mbs.registerMBean(connector, name);
097            return connector;
098        } catch (JMException | IOException e) {
099            throw new RuntimeException(e);
100        }
101    }
102
103    protected void destroyConnector(JDMKServerConnector connector) {
104        String protocol = connector.getAddress().getProtocol();
105        try {
106            ObjectName name = new ObjectName("org.nuxeo:type=jmx-connector,protocol=".concat(protocol));
107            mbs.unregisterMBean(name);
108        } catch (JMException e) {
109            throw new RuntimeException(e);
110        }
111        if (!connector.isActive()) {
112            return;
113        }
114        try {
115            connector.stop();
116        } catch (IOException e) {
117            throw new RuntimeException(e);
118        }
119    }
120
121    @Override
122    public void deactivate(ComponentContext arg0) {
123        if (htmlAdaptor != null) {
124            try {
125                destroyAdaptor(htmlAdaptor);
126            } finally {
127                htmlAdaptor = null;
128            }
129        }
130
131        if (httpConnector != null) {
132
133            try {
134                destroyConnector(httpConnector);
135            } finally {
136                httpConnector = null;
137            }
138        }
139
140        if (httpsConnector != null) {
141            try {
142                destroyConnector(httpsConnector);
143            } finally {
144                httpsConnector = null;
145            }
146        }
147
148    }
149
150    @Override
151    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
152        if ("protocols".equals(extensionPoint)) {
153            DmkProtocol protocol = (DmkProtocol) contribution;
154            configs.put(protocol.name, protocol);
155        }
156    }
157
158    @Override
159    public void applicationStarted(ComponentContext context) {
160        if (configs.containsKey("html")) {
161            htmlAdaptor = newAdaptor(configs.get("html"));
162            log.info("JMX HTML adaptor available at port 8081 (not active, to be started in JMX console)");
163        }
164        if (configs.containsKey("http")) {
165            httpConnector = newConnector(configs.get("http"));
166            log.info("JMX HTTP connector available at " + httpConnector.getAddress()
167                    + " (not active, to be started in JMX console)");
168        }
169        if (configs.containsKey("https")) {
170            httpsConnector = newConnector(configs.get("https"));
171            log.info("JMX HTTPS connector available at " + httpConnector.getAddress()
172                    + " (not active, to be started in JMX console)");
173        }
174    }
175}