001/* 002 * #%L 003 * Netarchivesuite - common 004 * %% 005 * Copyright (C) 2005 - 2018 The Royal Danish 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.util.Hashtable; 027 028import javax.management.InstanceAlreadyExistsException; 029import javax.management.JMException; 030import javax.management.MBeanServer; 031import javax.management.ObjectName; 032import javax.management.StandardMBean; 033 034import dk.netarkivet.common.CommonSettings; 035import dk.netarkivet.common.distribute.arcrepository.Replica; 036import dk.netarkivet.common.exceptions.ArgumentNotValid; 037import dk.netarkivet.common.exceptions.IOFailure; 038import dk.netarkivet.common.exceptions.IllegalState; 039import dk.netarkivet.common.exceptions.UnknownID; 040import dk.netarkivet.common.utils.Settings; 041import dk.netarkivet.common.utils.SystemUtils; 042 043/** 044 * Wrapper class for registering objects of type I as MBeans. 045 * <p> 046 * The register method will register a given object under an object name, generated with the domain given in 047 * constructor, and fields from the Hashtable nameProperties. It is prefilled with values common for all MBeans, but it 048 * is expected to be extended after the object is created with additional info. 049 * 050 * @param <I> The Type of Object to expose as an MBean. Currently only used with {@link SingleMBeanObject} 051 */ 052public class SingleMBeanObject<I> { 053 /** Properties for the ObjectName name. */ 054 private Hashtable<String, String> nameProperties = new Hashtable<String, String>(); 055 /** The domain for this SingleMBeanObject. */ 056 private String domain; 057 /** The object to expose as an MBean. */ 058 private I exposedObject; 059 /** The interface, this SingleMBeanObject should expose on the given MBeanServer. */ 060 private Class<I> asInterface; 061 /** The ObjectName this SingleMBeanObject registers on the given MBeanServer. */ 062 private ObjectName name; 063 /** MBeanServer to register mbeans in. */ 064 private final MBeanServer mBeanServer; 065 066 // FIXME Following environment constant are defined here in order to avoid 067 // refering to independent modules - the environment values are only 068 // used if defined 069 // Note that HARVESTER_HARVEST_CONTROLLER_CHANNEL should be identical to 070 // HarvesterSettings.HARVESTER_HARVEST_CONTROLLER_PRIORITY 071 private static String HARVESTER_HARVEST_CONTROLLER_CHANNEL = "settings.harvester.harvesting.channel"; 072 073 /** 074 * Create a single mbean object. This will fill out nameProperties with default values, and remember the domain and 075 * interface given. It will not, however, register the MBean. 076 * 077 * @param domain The domain of the MBean. 078 * @param object The object to expose as an MBean. 079 * @param asInterface The interface this MBean is exposed as. 080 * @param mBeanServer The server to register the mbean in. 081 * @throws ArgumentNotValid If domain is null or empty, or any other argument is null. 082 */ 083 public SingleMBeanObject(String domain, I object, Class<I> asInterface, MBeanServer mBeanServer) { 084 ArgumentNotValid.checkNotNullOrEmpty(domain, "String domain"); 085 ArgumentNotValid.checkNotNull(object, "I object"); 086 ArgumentNotValid.checkNotNull(asInterface, "Class asInterface"); 087 ArgumentNotValid.checkNotNull(mBeanServer, "MBeanServer mbeanServer"); 088 this.domain = domain; 089 this.asInterface = asInterface; 090 this.exposedObject = object; 091 092 nameProperties.put(Constants.PRIORITY_KEY_LOCATION, Settings.get(CommonSettings.THIS_PHYSICAL_LOCATION)); 093 nameProperties.put(Constants.PRIORITY_KEY_MACHINE, SystemUtils.getLocalHostName()); 094 nameProperties.put(Constants.PRIORITY_KEY_APPLICATIONNAME, Settings.get(CommonSettings.APPLICATION_NAME)); 095 nameProperties.put(Constants.PRIORITY_KEY_APPLICATIONINSTANCEID, 096 Settings.get(CommonSettings.APPLICATION_INSTANCE_ID)); 097 nameProperties.put(Constants.PRIORITY_KEY_HTTP_PORT, Settings.get(CommonSettings.HTTP_PORT_NUMBER)); 098 try { 099 String val; 100 val = Settings.get(HARVESTER_HARVEST_CONTROLLER_CHANNEL); 101 nameProperties.put(Constants.PRIORITY_KEY_CHANNEL, val); 102 } catch (UnknownID e) { 103 nameProperties.put(Constants.PRIORITY_KEY_CHANNEL, ""); 104 } 105 try { 106 String val = Replica.getReplicaFromId(Settings.get(CommonSettings.USE_REPLICA_ID)).getName(); 107 nameProperties.put(Constants.PRIORITY_KEY_REPLICANAME, val); 108 } catch (UnknownID e) { 109 nameProperties.put(Constants.PRIORITY_KEY_REPLICANAME, ""); 110 } 111 112 this.mBeanServer = mBeanServer; 113 } 114 115 /** 116 * Create a single mbean object. 117 * <p> 118 * This is a helper method for the constructor taking a domain, which take the domain from a preconstructed 119 * ObjectName and replaces the nameProperties with the properties from the given object name. Use this if you have 120 * an object name created already, which you wish to use. 121 * 122 * @param name The object name to register under. 123 * @param o The object to register. 124 * @param asInterface The interface o should implement. 125 * @param mBeanServer The mbean server to register o in. 126 * @throws ArgumentNotValid on any null parameter. 127 */ 128 public SingleMBeanObject(ObjectName name, I o, Class<I> asInterface, MBeanServer mBeanServer) { 129 this(name.getDomain(), o, asInterface, mBeanServer); 130 nameProperties.clear(); 131 nameProperties.putAll(name.getKeyPropertyList()); 132 } 133 134 /** 135 * Properties for the ObjectName name. Update these before registering. On construction, initialised with location, 136 * hostname, httpport, priority, replica, applicationname, applicationinstid. 137 * 138 * @return Hashtable of the object name properties. 139 */ 140 public Hashtable<String, String> getNameProperties() { 141 return nameProperties; 142 } 143 144 /** 145 * Registers this object as a standard MBean, with a name generated from domain given in constructor and the 146 * nameProperties hashTable. 147 * 148 * @throws IllegalState if bean is already registered. 149 * @throws IOFailure on trouble registering. 150 */ 151 public void register() { 152 try { 153 name = new ObjectName(domain, nameProperties); 154 mBeanServer.registerMBean(new StandardMBean(exposedObject, asInterface), name); 155 } catch (InstanceAlreadyExistsException e) { 156 throw new IllegalState("this MBean '" + name + "' is already registered on the MBeanServer", e); 157 } catch (JMException e) { 158 throw new IOFailure("Unable to register MBean '" + name + "'", e); 159 } 160 } 161 162 /** 163 * Unregister the object from the MBeanServer. Note: It is not checked that it is actually this mbean that is 164 * registered under the name, this method simply unregisters any object with this object name. 165 * 166 * @throws IOFailure on trouble unregistering. 167 */ 168 public void unregister() throws IOFailure { 169 MBeanServer mbserver = mBeanServer; 170 try { 171 if (name != null) { 172 name = new ObjectName(domain, nameProperties); 173 } 174 if (mbserver.isRegistered(name)) { 175 mbserver.unregisterMBean(name); 176 } 177 } catch (JMException e) { 178 throw new IOFailure("Unable to unregister MBean '" + name + "'", e); 179 } 180 } 181 182 /** @return the name */ 183 public ObjectName getName() { 184 return name; 185 } 186 187}