001/*
002 * (C) Copyright 2013-2017 Nuxeo (http://nuxeo.com/) and others.
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 * Contributors:
017 *     slacoin
018 */
019package org.nuxeo.dmk;
020
021import java.io.IOException;
022import java.lang.management.ManagementFactory;
023import java.util.HashMap;
024import java.util.Map;
025
026import javax.management.JMException;
027import javax.management.MBeanServer;
028import javax.management.ObjectName;
029import javax.management.remote.JMXConnectorServerFactory;
030import javax.management.remote.JMXServiceURL;
031
032import org.apache.commons.logging.Log;
033import org.apache.commons.logging.LogFactory;
034import org.nuxeo.runtime.model.ComponentContext;
035import org.nuxeo.runtime.model.ComponentInstance;
036import org.nuxeo.runtime.model.DefaultComponent;
037
038import com.sun.jdmk.comm.AuthInfo;
039import com.sun.jdmk.comm.GenericHttpConnectorServer;
040import com.sun.jdmk.comm.HtmlAdaptorServer;
041import com.sun.jdmk.comm.internal.JDMKServerConnector;
042
043public class DmkComponent extends DefaultComponent {
044
045    protected final Map<String, DmkProtocol> configs = new HashMap<>();
046
047    protected HtmlAdaptorServer htmlAdaptor;
048
049    protected JDMKServerConnector httpConnector;
050
051    protected JDMKServerConnector httpsConnector;
052
053    protected final Log log = LogFactory.getLog(DmkComponent.class);
054
055    protected final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
056
057    protected HtmlAdaptorServer newAdaptor(DmkProtocol config) {
058        HtmlAdaptorServer adaptor = new HtmlAdaptorServer();
059        adaptor.addUserAuthenticationInfo(new AuthInfo(config.user, config.password));
060        adaptor.setPort(config.port);
061        try {
062            ObjectName name = new ObjectName("org.nuxeo:type=jmx-adaptor,format=html");
063            mbs.registerMBean(adaptor, name);
064        } catch (JMException e) {
065            throw new RuntimeException(e);
066        }
067        return adaptor;
068    }
069
070    protected void destroyAdaptor(HtmlAdaptorServer adaptor) {
071        try {
072            ObjectName name = new ObjectName("org.nuxeo:type=jmx-adaptor,format=html");
073            mbs.unregisterMBean(name);
074        } catch (JMException e) {
075            throw new RuntimeException(e);
076        }
077        if (!adaptor.isActive()) {
078            return;
079        }
080        adaptor.stop();
081    }
082
083    protected JDMKServerConnector newConnector(DmkProtocol config) {
084        try {
085            String protocol = "jdmk-".concat(config.name);
086            JMXServiceURL httpURL = new JMXServiceURL(protocol, null, config.port);
087            JDMKServerConnector connector = (JDMKServerConnector) JMXConnectorServerFactory.newJMXConnectorServer(
088                    httpURL, null, mbs);
089            GenericHttpConnectorServer server = (GenericHttpConnectorServer) connector.getWrapped();
090            server.addUserAuthenticationInfo(new AuthInfo(config.user, config.password));
091            ObjectName name = new ObjectName("org.nuxeo:type=jmx-connector,protocol=".concat(protocol));
092            mbs.registerMBean(connector, name);
093            return connector;
094        } catch (JMException | IOException e) {
095            throw new RuntimeException(e);
096        }
097    }
098
099    protected void destroyConnector(JDMKServerConnector connector) {
100        String protocol = connector.getAddress().getProtocol();
101        try {
102            ObjectName name = new ObjectName("org.nuxeo:type=jmx-connector,protocol=".concat(protocol));
103            mbs.unregisterMBean(name);
104        } catch (JMException e) {
105            throw new RuntimeException(e);
106        }
107        if (!connector.isActive()) {
108            return;
109        }
110        try {
111            connector.stop();
112        } catch (IOException e) {
113            throw new RuntimeException(e);
114        }
115    }
116
117    @Override
118    public void start(ComponentContext context) {
119        if (configs.containsKey("html")) {
120            htmlAdaptor = newAdaptor(configs.get("html"));
121            log.info("JMX HTML adaptor available at port 8081 (not active, to be started in JMX console)");
122        }
123        if (configs.containsKey("http")) {
124            httpConnector = newConnector(configs.get("http"));
125            log.info("JMX HTTP connector available at " + httpConnector.getAddress()
126                    + " (not active, to be started in JMX console)");
127        }
128        if (configs.containsKey("https")) {
129            httpsConnector = newConnector(configs.get("https"));
130            log.info("JMX HTTPS connector available at " + httpConnector.getAddress()
131                    + " (not active, to be started in JMX console)");
132        }
133    }
134
135    @Override
136    public void stop(ComponentContext arg0) {
137        if (htmlAdaptor != null) {
138            try {
139                destroyAdaptor(htmlAdaptor);
140            } finally {
141                htmlAdaptor = null;
142            }
143        }
144
145        if (httpConnector != null) {
146            try {
147                destroyConnector(httpConnector);
148            } finally {
149                httpConnector = null;
150            }
151        }
152
153        if (httpsConnector != null) {
154            try {
155                destroyConnector(httpsConnector);
156            } finally {
157                httpsConnector = null;
158            }
159        }
160
161    }
162
163    @Override
164    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
165        if ("protocols".equals(extensionPoint)) {
166            DmkProtocol protocol = (DmkProtocol) contribution;
167            configs.put(protocol.name, protocol);
168        }
169    }
170
171}