001/* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019package org.apache.wiki.ui.admin; 020 021import org.apache.logging.log4j.LogManager; 022import org.apache.logging.log4j.Logger; 023import org.apache.wiki.api.Release; 024import org.apache.wiki.api.core.Engine; 025import org.apache.wiki.event.WikiEngineEvent; 026import org.apache.wiki.event.WikiEvent; 027import org.apache.wiki.event.WikiEventListener; 028import org.apache.wiki.modules.ModuleManager; 029import org.apache.wiki.modules.WikiModuleInfo; 030import org.apache.wiki.ui.admin.beans.CoreBean; 031import org.apache.wiki.ui.admin.beans.FilterBean; 032import org.apache.wiki.ui.admin.beans.PluginBean; 033import org.apache.wiki.ui.admin.beans.SearchManagerBean; 034import org.apache.wiki.ui.admin.beans.UserBean; 035 036import javax.management.DynamicMBean; 037import javax.management.InstanceAlreadyExistsException; 038import javax.management.InstanceNotFoundException; 039import javax.management.MBeanRegistrationException; 040import javax.management.MBeanServer; 041import javax.management.MalformedObjectNameException; 042import javax.management.NotCompliantMBeanException; 043import javax.management.ObjectName; 044import java.lang.management.ManagementFactory; 045import java.util.ArrayList; 046import java.util.Collection; 047import java.util.List; 048 049 050/** 051 * Provides a manager class for all AdminBeans within JSPWiki. This class also manages registration for any 052 * AdminBean which is also a JMX bean. 053 * 054 * @since 2.5.52 055 */ 056public class DefaultAdminBeanManager implements WikiEventListener, AdminBeanManager { 057 058 private final Engine m_engine; 059 private ArrayList< AdminBean > m_allBeans; 060 private final MBeanServer m_mbeanServer; 061 062 private static final Logger log = LogManager.getLogger( DefaultAdminBeanManager.class ); 063 064 public DefaultAdminBeanManager( final Engine engine ) { 065 log.info("Using JDK 1.5 Platform MBeanServer"); 066 m_mbeanServer = MBeanServerFactory15.getServer(); 067 068 m_engine = engine; 069 070 if( m_mbeanServer != null ) { 071 log.info( m_mbeanServer.getClass().getName() ); 072 log.info( m_mbeanServer.getDefaultDomain() ); 073 } 074 075 m_engine.addWikiEventListener( this ); 076 initialize(); 077 } 078 079 /** {@inheritDoc} */ 080 @Override 081 public void initialize() { 082 reload(); 083 } 084 085 private String getJMXTitleString( final int title ) { 086 switch( title ) { 087 case AdminBean.CORE: 088 return "Core"; 089 090 case AdminBean.EDITOR: 091 return "Editors"; 092 093 case AdminBean.UNKNOWN: 094 default: 095 return "Unknown"; 096 } 097 } 098 099 100 /** 101 * Register an AdminBean. If the AdminBean is also a JMX MBean, it also gets registered to the MBeanServer we've found. 102 * 103 * @param ab AdminBean to register. 104 */ 105 private void registerAdminBean( final AdminBean ab ) { 106 try { 107 if( ab instanceof DynamicMBean && m_mbeanServer != null ) { 108 final ObjectName name = getObjectName( ab ); 109 if( !m_mbeanServer.isRegistered( name ) ) { 110 m_mbeanServer.registerMBean( ab, name ); 111 } 112 } 113 114 m_allBeans.add( ab ); 115 116 log.info( "Registered new admin bean " + ab.getTitle() ); 117 } catch( final InstanceAlreadyExistsException e ) { 118 log.error( "Admin bean already registered to JMX", e ); 119 } catch( final MBeanRegistrationException e ) { 120 log.error( "Admin bean cannot be registered to JMX", e ); 121 } catch( final NotCompliantMBeanException e ) { 122 log.error( "Your admin bean is not very good", e ); 123 } catch( final MalformedObjectNameException e ) { 124 log.error( "Your admin bean name is not very good", e ); 125 } catch( final NullPointerException e ) { 126 log.error( "Evil NPE occurred", e ); 127 } 128 } 129 130 private ObjectName getObjectName( final AdminBean ab ) throws MalformedObjectNameException { 131 final String component = getJMXTitleString( ab.getType() ); 132 final String title = ab.getTitle(); 133 return new ObjectName( Release.APPNAME + ":component=" + component + ",name=" + title ); 134 } 135 136 /** 137 * Registers all the beans from a collection of WikiModuleInfos. If some of the beans fail, logs the message and keeps going to the 138 * next bean. 139 * 140 * @param c Collection of WikiModuleInfo instances 141 */ 142 private void registerBeans( final Collection< WikiModuleInfo > c ) { 143 for( final WikiModuleInfo wikiModuleInfo : c ) { 144 final String abname = wikiModuleInfo.getAdminBeanClass(); 145 try { 146 if( abname != null && !abname.isEmpty() ) { 147 final Class< ? > abclass = Class.forName( abname ); 148 final AdminBean ab = ( AdminBean )abclass.newInstance(); 149 registerAdminBean( ab ); 150 } 151 } catch( final ClassNotFoundException | InstantiationException | IllegalAccessException e ) { 152 log.error( e.getMessage(), e ); 153 } 154 } 155 156 } 157 158 // FIXME: Should unload the beans first. 159 private void reload() { 160 m_allBeans = new ArrayList<>(); 161 162 try { 163 registerAdminBean( new CoreBean( m_engine ) ); 164 registerAdminBean( new UserBean( m_engine ) ); 165 registerAdminBean( new SearchManagerBean( m_engine ) ); 166 registerAdminBean( new PluginBean( m_engine ) ); 167 registerAdminBean( new FilterBean( m_engine ) ); 168 } catch( final NotCompliantMBeanException e ) { 169 log.error( e.getMessage(), e ); 170 } 171 for( final ModuleManager moduleManager : m_engine.getManagers( ModuleManager.class ) ) { 172 registerBeans( moduleManager.modules() ); 173 } 174 } 175 176 /* (non-Javadoc) 177 * @see org.apache.wiki.ui.admin.AdminBeanManager#getAllBeans() 178 */ 179 @Override 180 public List< AdminBean > getAllBeans() { 181 if( m_allBeans == null ) { 182 reload(); 183 } 184 185 return m_allBeans; 186 } 187 188 /* (non-Javadoc) 189 * @see org.apache.wiki.ui.admin.AdminBeanManager#findBean(java.lang.String) 190 */ 191 @Override 192 public AdminBean findBean( final String id ) { 193 for( final AdminBean ab : m_allBeans ) { 194 if( ab.getId().equals( id ) ) { 195 return ab; 196 } 197 } 198 199 return null; 200 } 201 202 /** 203 * Provides a JDK 1.5-compliant version of the MBeanServerFactory. This will simply bind to the 204 * platform MBeanServer. 205 */ 206 private static final class MBeanServerFactory15 { 207 private MBeanServerFactory15() 208 {} 209 210 public static MBeanServer getServer() { 211 return ManagementFactory.getPlatformMBeanServer(); 212 } 213 } 214 215 /** 216 * Returns the type identifier for a string type. 217 * 218 * @param type A type string. 219 * @return A type value. 220 */ 221 @Override 222 public int getTypeFromString( final String type ) { 223 if( "core".equals( type ) ) { 224 return AdminBean.CORE; 225 } else if( "editors".equals( type ) ) { 226 return AdminBean.EDITOR; 227 } 228 229 return AdminBean.UNKNOWN; 230 } 231 232 /* (non-Javadoc) 233 * @see org.apache.wiki.ui.admin.AdminBeanManager#actionPerformed(org.apache.wiki.event.WikiEvent) 234 */ 235 @Override 236 public void actionPerformed( final WikiEvent event ) { 237 if( event instanceof WikiEngineEvent ) { 238 if( event.getType() == WikiEngineEvent.SHUTDOWN ) { 239 for( final AdminBean m_allBean : m_allBeans ) { 240 try { 241 final ObjectName on = getObjectName( m_allBean ); 242 if( m_mbeanServer.isRegistered( on ) ) { 243 m_mbeanServer.unregisterMBean( on ); 244 log.info( "Unregistered AdminBean " + m_allBean.getTitle() ); 245 } 246 } catch( final MalformedObjectNameException e ) { 247 log.error( "Malformed object name when unregistering", e ); 248 } catch( final InstanceNotFoundException e ) { 249 log.error( "Object was registered; yet claims that it's not there", e ); 250 } catch( final MBeanRegistrationException e ) { 251 log.error( "Registration exception while unregistering", e ); 252 } 253 } 254 } 255 } 256 } 257 258}