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