001/* 002 * #%L 003 * Netarchivesuite - common 004 * %% 005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023 024package dk.netarkivet.common.management; 025 026import java.io.IOException; 027import java.io.Serializable; 028import java.lang.management.ManagementFactory; 029import java.rmi.registry.LocateRegistry; 030import java.text.MessageFormat; 031import java.util.HashMap; 032import java.util.Map; 033 034import javax.management.MBeanServer; 035import javax.management.remote.JMXConnectorServer; 036import javax.management.remote.JMXConnectorServerFactory; 037import javax.management.remote.JMXServiceURL; 038 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042import dk.netarkivet.common.CommonSettings; 043import dk.netarkivet.common.distribute.monitorregistry.MonitorRegistryClientFactory; 044import dk.netarkivet.common.exceptions.IOFailure; 045import dk.netarkivet.common.utils.Settings; 046import dk.netarkivet.common.utils.SystemUtils; 047 048/** 049 * Utility class that handles exposing the platform mbean server using rmi, and using specified ports and password 050 * files. <br/> 051 * <br/> 052 * <p> 053 * See http://java.sun.com/j2se/1.5.0/docs/guide/jmx/tutorial/security.html <br/> 054 * <br/> 055 * <p> 056 * TODO This implementation is not robust and could be improved. <br/> 057 * TODO For instance: - Singleton behaviour <br/> 058 * TODO -Reuse of already created registry <br/> 059 * TODO Usage of access rights (for read-only mbeans) (see reference above) 060 */ 061public class MBeanConnectorCreator { 062 063 private static final Logger log = LoggerFactory.getLogger(MBeanConnectorCreator.class); 064 065 public static boolean isExposed = false; 066 067 private static final String SERVICE_JMX_RMI_URL = "service:jmx:rmi://{0}:{1}/jndi/rmi://{0}:{2}/jmxrmi"; 068 069 private static final String ENVIRONMENT_PASSWORD_FILE_PROPERTY = "jmx.remote.x.password.file"; 070 071 /** 072 * Registers an RMI connector to the local mbean server in a private RMI registry, under the name "jmxrmi". The port 073 * for the registry is read from settings, and the RMI port used for exposing the connector is also read from 074 * settings. Access to the mbean server is restricted by the rules set in the password file, likewise read from 075 * settings. 076 * 077 * @throws IOFailure on trouble exposing the server. 078 */ 079 public static synchronized void exposeJMXMBeanServer() { 080 try { 081 if (!isExposed) { 082 int jmxPort = Settings.getInt(CommonSettings.JMX_PORT); 083 int rmiPort = Settings.getInt(CommonSettings.JMX_RMI_PORT); 084 String passwordFile = Settings.get(CommonSettings.JMX_PASSWORD_FILE); 085 086 // Create a private registry for the exposing the JMX connector. 087 LocateRegistry.createRegistry(jmxPort); 088 // Create a URL that signifies that we wish to use the local 089 // registry created above, and listen for rmi callbacks on the 090 // RMI port of this machine, exposing the mbeanserver with the 091 // name "jmxrmi". 092 String canonicalHostName = SystemUtils.getLocalHostName(); 093 JMXServiceURL url = new JMXServiceURL(MessageFormat.format(SERVICE_JMX_RMI_URL, canonicalHostName, 094 Integer.toString(rmiPort), Integer.toString(jmxPort))); 095 // Insert the password file into environment used when creating 096 // the connector server. 097 Map<String, Serializable> env = new HashMap<String, Serializable>(); 098 env.put(ENVIRONMENT_PASSWORD_FILE_PROPERTY, passwordFile); 099 // Register the connector to the local mbean server in this 100 // registry under that URL, using the created environment 101 // settings. 102 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 103 JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); 104 // Start the connector server. 105 cs.start(); 106 isExposed = true; 107 // Register the JMX server at the registry. 108 MonitorRegistryClientFactory.getInstance().register(canonicalHostName, 109 Settings.getInt(CommonSettings.JMX_PORT), Settings.getInt(CommonSettings.JMX_RMI_PORT)); 110 111 if (log.isInfoEnabled()) { 112 log.info("Registered mbean server in registry on port {} communicating on port {} " 113 + "using password file '{}'." + "\nService URL is {}", jmxPort, rmiPort, passwordFile, 114 url.toString()); 115 } 116 } 117 } catch (IOException e) { 118 throw new IOFailure("Error creating and registering an RMIConnector to the platform mbean server.", e); 119 } 120 } 121 122}