001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (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.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 *     matic
016 */
017package org.nuxeo.runtime.management;
018
019import java.io.IOException;
020import java.lang.management.ManagementFactory;
021import java.net.InetAddress;
022import java.net.MalformedURLException;
023import java.net.UnknownHostException;
024import java.rmi.RemoteException;
025import java.rmi.registry.LocateRegistry;
026import java.util.HashMap;
027import java.util.Map;
028
029import javax.management.MBeanServer;
030import javax.management.MBeanServerFactory;
031import javax.management.ObjectName;
032import javax.management.remote.JMXServiceURL;
033import javax.management.remote.rmi.RMIConnectorServer;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.nuxeo.runtime.model.ComponentInstance;
038import org.nuxeo.runtime.model.DefaultComponent;
039
040public class ServerLocatorService extends DefaultComponent implements ServerLocator {
041
042    public static final String LOCATORS_EXT_KEY = "locators";
043
044    private static final Log log = LogFactory.getLog(ServerLocatorService.class);
045
046    protected final Map<String, MBeanServer> servers = new HashMap<String, MBeanServer>();
047
048    protected MBeanServer defaultServer = ManagementFactory.getPlatformMBeanServer();
049
050    protected String hostname;
051
052    @Override
053    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
054        if (extensionPoint.equals(LOCATORS_EXT_KEY)) {
055            doRegisterLocator((ServerLocatorDescriptor) contribution);
056        }
057    }
058
059    @Override
060    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
061        if (extensionPoint.equals(LOCATORS_EXT_KEY)) {
062            doUnregisterLocator((ServerLocatorDescriptor) contribution);
063        }
064    }
065
066    protected void doRegisterLocator(ServerLocatorDescriptor descriptor) {
067        MBeanServer server = descriptor.isExisting ? doFindServer(descriptor.domainName) : doCreateServer(descriptor);
068        servers.put(descriptor.domainName, server);
069        if (descriptor.isDefault) {
070            defaultServer = server;
071        }
072    }
073
074    protected String doGetHostname() {
075        if (hostname != null) {
076            return hostname;
077        }
078        try {
079            InetAddress addr = InetAddress.getLocalHost();
080            hostname = addr.getHostName();
081        } catch (UnknownHostException e) {
082            hostname = "localhost";
083        }
084        return hostname;
085    }
086
087    protected JMXServiceURL doFormatServerURL(ServerLocatorDescriptor descriptor) {
088        try {
089            return new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + descriptor.rmiPort + "/"
090                    + descriptor.domainName + "/jmxrmi");
091        } catch (MalformedURLException e) {
092            throw new ManagementRuntimeException("Cannot format url for " + descriptor.domainName);
093        }
094    }
095
096    protected String doFormatThreadName(ServerLocatorDescriptor descriptor) {
097        return "mbeanServer-" + descriptor.domainName;
098    }
099
100    protected MBeanServer doCreateServer(final ServerLocatorDescriptor descriptor) {
101        MBeanServer server = MBeanServerFactory.createMBeanServer();
102        JMXServiceURL url = doFormatServerURL(descriptor);
103        if (!descriptor.remote) {
104            return server;
105        }
106        final RMIConnectorServer connector;
107        try {
108            connector = new RMIConnectorServer(url, null, server);
109        } catch (IOException e) {
110            throw new ManagementRuntimeException("Cannot start connector for " + descriptor.domainName, e);
111        }
112        try {
113            connector.start();
114        } catch (IOException e) {
115            try {
116                LocateRegistry.createRegistry(descriptor.rmiPort);
117            } catch (RemoteException e2) {
118                throw new ManagementRuntimeException("Cannot start RMI connector for " + descriptor.domainName, e);
119            }
120            try {
121                connector.start();
122            } catch (IOException e2) {
123                throw new ManagementRuntimeException("Cannot start RMI connector for " + descriptor.domainName, e2);
124            }
125        }
126        assert connector.isActive();
127        log.info("Started a mbean server : " + url);
128        return server;
129    }
130
131    @SuppressWarnings("cast")
132    protected MBeanServer doFindServer(String domainName) {
133        for (MBeanServer server : MBeanServerFactory.findMBeanServer(null)) {
134            String domain = server.getDefaultDomain();
135            if (domain == null || !domain.equals(domainName)) {
136                continue;
137            }
138            return server;
139        }
140        return defaultServer;
141    }
142
143    protected void doUnregisterLocator(ServerLocatorDescriptor descriptor) {
144        servers.remove(descriptor.domainName);
145        if (descriptor.isDefault) {
146            defaultServer = ManagementFactory.getPlatformMBeanServer();
147        }
148    }
149
150    @Override
151    @SuppressWarnings("cast")
152    public MBeanServer lookupServer(ObjectName qualifiedName) {
153        if (defaultServer.isRegistered(qualifiedName)) {
154            return defaultServer;
155        }
156        for (MBeanServer server : MBeanServerFactory.findMBeanServer(null)) {
157            if (server.isRegistered(qualifiedName)) {
158                return server;
159            }
160        }
161        throw new ManagementRuntimeException(qualifiedName + " is not registered");
162    }
163
164    @Override
165    public MBeanServer lookupServer() {
166        return defaultServer;
167    }
168
169    @Override
170    public MBeanServer lookupServer(String domainName) {
171        return doFindServer(domainName);
172    }
173
174    public void registerLocator(String domain, boolean isDefault) {
175        doRegisterLocator(new ServerLocatorDescriptor(domain, isDefault));
176    }
177
178}