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; 035import org.apache.wiki.util.ClassUtil; 036 037import javax.management.DynamicMBean; 038import javax.management.InstanceAlreadyExistsException; 039import javax.management.InstanceNotFoundException; 040import javax.management.MBeanRegistrationException; 041import javax.management.MBeanServer; 042import javax.management.MalformedObjectNameException; 043import javax.management.NotCompliantMBeanException; 044import javax.management.ObjectName; 045import java.lang.management.ManagementFactory; 046import java.util.ArrayList; 047import java.util.Collection; 048import java.util.List; 049 050 051/** 052 * Provides a manager class for all AdminBeans within JSPWiki. This class also manages registration for any 053 * AdminBean which is also a JMX bean. 054 * 055 * @since 2.5.52 056 */ 057public class DefaultAdminBeanManager implements WikiEventListener, AdminBeanManager { 058 059 private final Engine m_engine; 060 private ArrayList< AdminBean > m_allBeans; 061 private final MBeanServer m_mbeanServer; 062 063 private static final Logger LOG = LogManager.getLogger( DefaultAdminBeanManager.class ); 064 065 public DefaultAdminBeanManager( final Engine engine ) { 066 LOG.info("Using JDK 1.5 Platform MBeanServer"); 067 m_mbeanServer = MBeanServerFactory15.getServer(); 068 069 m_engine = engine; 070 071 if( m_mbeanServer != null ) { 072 LOG.info( m_mbeanServer.getClass().getName() ); 073 LOG.info( m_mbeanServer.getDefaultDomain() ); 074 } 075 076 m_engine.addWikiEventListener( this ); 077 initialize(); 078 } 079 080 /** {@inheritDoc} */ 081 @Override 082 public void initialize() { 083 reload(); 084 } 085 086 private String getJMXTitleString( final int title ) { 087 switch( title ) { 088 case AdminBean.CORE: 089 return "Core"; 090 091 case AdminBean.EDITOR: 092 return "Editors"; 093 094 case AdminBean.UNKNOWN: 095 default: 096 return "Unknown"; 097 } 098 } 099 100 101 /** 102 * Register an AdminBean. If the AdminBean is also a JMX MBean, it also gets registered to the MBeanServer we've found. 103 * 104 * @param ab AdminBean to register. 105 */ 106 private void registerAdminBean( final AdminBean ab ) { 107 try { 108 if( ab instanceof DynamicMBean && m_mbeanServer != null ) { 109 final ObjectName name = getObjectName( ab ); 110 if( !m_mbeanServer.isRegistered( name ) ) { 111 m_mbeanServer.registerMBean( ab, name ); 112 } 113 } 114 115 m_allBeans.add( ab ); 116 117 LOG.info( "Registered new admin bean " + ab.getTitle() ); 118 } catch( final InstanceAlreadyExistsException e ) { 119 LOG.error( "Admin bean already registered to JMX", e ); 120 } catch( final MBeanRegistrationException e ) { 121 LOG.error( "Admin bean cannot be registered to JMX", e ); 122 } catch( final NotCompliantMBeanException e ) { 123 LOG.error( "Your admin bean is not very good", e ); 124 } catch( final MalformedObjectNameException e ) { 125 LOG.error( "Your admin bean name is not very good", e ); 126 } catch( final NullPointerException e ) { 127 LOG.error( "Evil NPE occurred", e ); 128 } 129 } 130 131 private ObjectName getObjectName( final AdminBean ab ) throws MalformedObjectNameException { 132 final String component = getJMXTitleString( ab.getType() ); 133 final String title = ab.getTitle(); 134 return new ObjectName( Release.APPNAME + ":component=" + component + ",name=" + title ); 135 } 136 137 /** 138 * Registers all the beans from a collection of WikiModuleInfos. If some of the beans fail, logs the message and keeps going to the 139 * next bean. 140 * 141 * @param c Collection of WikiModuleInfo instances 142 */ 143 private void registerBeans( final Collection< WikiModuleInfo > c ) { 144 for( final WikiModuleInfo wikiModuleInfo : c ) { 145 final String abname = wikiModuleInfo.getAdminBeanClass(); 146 try { 147 if( abname != null && !abname.isEmpty() ) { 148 final AdminBean ab = ClassUtil.buildInstance( abname ); 149 registerAdminBean( ab ); 150 } 151 } catch( final ReflectiveOperationException 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 return m_allBeans.stream().filter(ab -> ab.getId().equals(id)).findFirst().orElse(null); 194 195 } 196 197 /** 198 * Provides a JDK 1.5-compliant version of the MBeanServerFactory. This will simply bind to the 199 * platform MBeanServer. 200 */ 201 private static final class MBeanServerFactory15 { 202 private MBeanServerFactory15() 203 {} 204 205 public static MBeanServer getServer() { 206 return ManagementFactory.getPlatformMBeanServer(); 207 } 208 } 209 210 /** 211 * Returns the type identifier for a string type. 212 * 213 * @param type A type string. 214 * @return A type value. 215 */ 216 @Override 217 public int getTypeFromString( final String type ) { 218 if( "core".equals( type ) ) { 219 return AdminBean.CORE; 220 } else if( "editors".equals( type ) ) { 221 return AdminBean.EDITOR; 222 } 223 224 return AdminBean.UNKNOWN; 225 } 226 227 /* (non-Javadoc) 228 * @see org.apache.wiki.ui.admin.AdminBeanManager#actionPerformed(org.apache.wiki.event.WikiEvent) 229 */ 230 @Override 231 public void actionPerformed( final WikiEvent event ) { 232 if( event instanceof WikiEngineEvent ) { 233 if( event.getType() == WikiEngineEvent.SHUTDOWN ) { 234 for( final AdminBean m_allBean : m_allBeans ) { 235 try { 236 final ObjectName on = getObjectName( m_allBean ); 237 if( m_mbeanServer.isRegistered( on ) ) { 238 m_mbeanServer.unregisterMBean( on ); 239 LOG.info( "Unregistered AdminBean " + m_allBean.getTitle() ); 240 } 241 } catch( final MalformedObjectNameException e ) { 242 LOG.error( "Malformed object name when unregistering", e ); 243 } catch( final InstanceNotFoundException e ) { 244 LOG.error( "Object was registered; yet claims that it's not there", e ); 245 } catch( final MBeanRegistrationException e ) { 246 LOG.error( "Registration exception while unregistering", e ); 247 } 248 } 249 } 250 } 251 } 252 253}