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