001/* 002 * Copyright 2023 Anyware Services 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 */ 016package org.ametys.runtime.plugins.admin.statistics; 017 018import java.lang.management.ManagementFactory; 019import java.lang.reflect.InvocationTargetException; 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.List; 023import java.util.Map; 024import java.util.Map.Entry; 025import java.util.TreeMap; 026 027import org.apache.avalon.framework.service.ServiceException; 028import org.apache.avalon.framework.service.ServiceManager; 029import org.apache.avalon.framework.service.Serviceable; 030import org.apache.commons.lang3.StringUtils; 031import org.slf4j.Logger; 032import org.slf4j.LoggerFactory; 033 034import org.ametys.core.authentication.CredentialProvider; 035import org.ametys.core.authentication.CredentialProviderFactory; 036import org.ametys.core.authentication.CredentialProviderModel; 037import org.ametys.core.group.GroupDirectoryDAO; 038import org.ametys.core.group.directory.GroupDirectory; 039import org.ametys.core.group.directory.GroupDirectoryFactory; 040import org.ametys.core.user.directory.UserDirectory; 041import org.ametys.core.user.directory.UserDirectoryFactory; 042import org.ametys.core.user.population.UserPopulation; 043import org.ametys.core.user.population.UserPopulationDAO; 044import org.ametys.core.version.VersionsHandler; 045import org.ametys.runtime.config.Config; 046import org.ametys.runtime.i18n.I18nizableText; 047import org.ametys.runtime.plugin.PluginsManager; 048import org.ametys.runtime.plugin.component.PluginAware; 049import org.ametys.runtime.servlet.AnalyseFileForVirusHelper; 050 051import com.jsoftbiz.utils.OS; 052 053/** 054 * All statistics of kernel 055 */ 056public class KernelStatisticsProvider implements StatisticsProvider, Serviceable, PluginAware 057{ 058 private static String _tomcatVersion; 059 private static Logger _logger = LoggerFactory.getLogger(KernelStatisticsProvider.class.getName()); 060 061 private String _id; 062 private VersionsHandler _versionsHandler; 063 private UserPopulationDAO _userPopulationDAO; 064 private UserDirectoryFactory _userDirectoryFactory; 065 private CredentialProviderFactory _credentialProviderFactory; 066 private GroupDirectoryDAO _groupDirectoryDAO; 067 private GroupDirectoryFactory _groupDirectoryFactory; 068 069 public void service(ServiceManager manager) throws ServiceException 070 { 071 _versionsHandler = (VersionsHandler) manager.lookup(VersionsHandler.ROLE); 072 _userPopulationDAO = (UserPopulationDAO) manager.lookup(UserPopulationDAO.ROLE); 073 _userDirectoryFactory = (UserDirectoryFactory) manager.lookup(UserDirectoryFactory.ROLE); 074 _credentialProviderFactory = (CredentialProviderFactory) manager.lookup(CredentialProviderFactory.ROLE); 075 _groupDirectoryDAO = (GroupDirectoryDAO) manager.lookup(GroupDirectoryDAO.ROLE); 076 _groupDirectoryFactory = (GroupDirectoryFactory) manager.lookup(GroupDirectoryFactory.ROLE); 077 } 078 079 public void setPluginInfo(String pluginName, String featureName, String id) 080 { 081 _id = id; 082 } 083 084 /** 085 * Get the Apache Tomcat version such as "9.0.46.0" 086 * @return The version of Apache Tomcat or null if an error occurred while getting it 087 */ 088 @SuppressWarnings("unchecked") 089 public static synchronized String getTomcatVersion() 090 { 091 if (_tomcatVersion == null) 092 { 093 try 094 { 095 Class tomcatServerInfo = KernelStatisticsProvider.class.getClassLoader().loadClass("org.apache.catalina.util.ServerInfo"); 096 _tomcatVersion = (String) tomcatServerInfo.getMethod("getServerNumber").invoke(tomcatServerInfo); 097 } 098 catch (ClassNotFoundException | NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) 099 { 100 // Not computable... 101 _logger.warn("Cannot get the tomcat version", e); 102 } 103 } 104 return _tomcatVersion; 105 } 106 107 public Statistics getStatistics() 108 { 109 return new StatisticsNode( 110 _id, 111 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_LABEL"), 112 "ametysicon-trademark-ametys", 113 null, 114 List.of( 115 _getVersionsStatistics(), 116 _getPluginsStatistics(), 117 _getConfigurationStatistics(), 118 _getPopulationsAndGropDirectoriesStatistics(), 119 _getServerStatistics() 120 ), 121 true 122 ); 123 } 124 125 126 private Statistics _getServerStatistics() 127 { 128 return new StatisticsNode( 129 "server", 130 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_LABEL"), 131 "ametysicon-system-server-sync", 132 null, 133 List.of( 134 new StatisticsValue( 135 "osname", 136 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_OS_LABEL"), 137 "ametysicon-system-terminal", 138 OS.OS.getPlatformName() + " (" + OS.OS.getVersion() + ")" 139 ), 140 new StatisticsValue( 141 "cpu", 142 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_CPU_LABEL"), 143 "ametysicon-trademark-jackrabbit", 144 String.valueOf(ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors()) + " x " + OS.OS.getArch() 145 ), 146 new StatisticsValue( 147 "ram", 148 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_RAM_LABEL"), 149 "ametysicon-system-sgbd", 150 ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getMax() 151 ), 152 new StatisticsValue( 153 "vmvendor", 154 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_VMVENDOR_LABEL"), 155 "ametysicon-trademark-jstack", 156 System.getProperty("java.vendor") + " " + ManagementFactory.getRuntimeMXBean().getVmName() 157 ), 158 new StatisticsValue( 159 "vmversion", 160 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_VMVERSION_LABEL"), 161 "ametysicon-trademark-jstack", 162 System.getProperty("java.version") 163 ), 164 new StatisticsValue( 165 "tomcatversion", 166 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_TOMCATVERSION_LABEL"), 167 "ametysicon-trademark-tomcat", 168 getTomcatVersion() 169 ), 170 new StatisticsValue( 171 "antivirus", 172 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_ANTIVIRUS_LABEL"), 173 "ametysicon-arrow-down-in", 174 AnalyseFileForVirusHelper.isAntivirusEnabled() 175 ) 176 ), 177 false 178 ); 179 } 180 181 private Statistics _getVersionsStatistics() 182 { 183 return new StatisticsNode( 184 "versions", 185 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_VERSIONS_LABEL"), 186 "ametysicon-maths-number-zero-one", 187 null, 188 _getVersionsChildren(), 189 true 190 ); 191 } 192 193 private List<Statistics> _getVersionsChildren() 194 { 195 return _versionsHandler.getVersions().stream() 196 .map(v -> new StatisticsValue( 197 v.getName(), 198 new I18nizableText(v.getName()), 199 "ametysicon-trademark-ametys", 200 v.getVersion()) 201 ) 202 .map(Statistics.class::cast) 203 .toList(); 204 } 205 206 private Statistics _getPluginsStatistics() 207 { 208 List<String> plugins = new ArrayList<>(PluginsManager.getInstance().getBundledPluginsNames()); 209 Collections.sort(plugins); 210 211 return new StatisticsValue( 212 "plugins", 213 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_PLUGINS_LABEL"), 214 "ametysicon-puzzle-piece1", 215 plugins 216 ); 217 } 218 219 private Statistics _getPopulationsAndGropDirectoriesStatistics() 220 { 221 long populations = 0; 222 223 Map<String, Long> userDirectoriesCount = new TreeMap<>(); 224 Map<String, Long> credentialProvidersCount = new TreeMap<>(); 225 226 for (UserPopulation userPopulation : _userPopulationDAO.getUserPopulations(false)) 227 { 228 populations++; 229 230 for (UserDirectory userDirectory : userPopulation.getUserDirectories()) 231 { 232 Long value = userDirectoriesCount.getOrDefault(userDirectory.getUserDirectoryModelId(), 0L); 233 userDirectoriesCount.put(userDirectory.getUserDirectoryModelId(), value + 1); 234 } 235 236 for (CredentialProvider credentialProvider : userPopulation.getCredentialProviders()) 237 { 238 Long value = credentialProvidersCount.getOrDefault(credentialProvider.getCredentialProviderModelId(), 0L); 239 credentialProvidersCount.put(credentialProvider.getCredentialProviderModelId(), value + 1); 240 } 241 } 242 243 List<Statistics> userDirectories = new ArrayList<>(); 244 for (Entry<String, Long> entry : userDirectoriesCount.entrySet()) 245 { 246 userDirectories.add(new StatisticsValue( 247 entry.getKey(), 248 _userDirectoryFactory.getExtension(entry.getKey()).getLabel(), 249 "ametysicon-body-idcard-white", 250 entry.getValue() 251 )); 252 } 253 254 List<Statistics> credentialProviders = new ArrayList<>(); 255 for (Entry<String, Long> entry : credentialProvidersCount.entrySet()) 256 { 257 CredentialProviderModel cp = _credentialProviderFactory.getExtension(entry.getKey()); 258 credentialProviders.add(new StatisticsValue( 259 entry.getKey(), 260 cp.getLabel(), 261 StringUtils.defaultIfBlank(cp.getIconGlyph(), "ametysicon-body-idcard-badge"), 262 entry.getValue() 263 )); 264 } 265 266 long groups = 0; 267 268 Map<String, Long> groupDirectoriesCount = new TreeMap<>(); 269 for (GroupDirectory groupDirectory : _groupDirectoryDAO.getGroupDirectories()) 270 { 271 groups++; 272 273 Long value = groupDirectoriesCount.getOrDefault(groupDirectory.getGroupDirectoryModelId(), 0L); 274 groupDirectoriesCount.put(groupDirectory.getGroupDirectoryModelId(), value + 1); 275 } 276 277 List<Statistics> groupDirectories = new ArrayList<>(); 278 for (Entry<String, Long> entry : groupDirectoriesCount.entrySet()) 279 { 280 groupDirectories.add(new StatisticsValue( 281 entry.getKey(), 282 _groupDirectoryFactory.getExtension(entry.getKey()).getLabel(), 283 "ametysicon-body-people", 284 entry.getValue() 285 )); 286 } 287 288 return new StatisticsNode( 289 "populations-groupdirectories", 290 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_LABEL"), 291 "ametysicon-body-group", 292 populations + groups, 293 List.of( 294 new StatisticsNode( 295 "populations", 296 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_POPULATIONS_LABEL"), 297 "ametysicon-body-people", 298 populations, 299 List.of( 300 new StatisticsNode( 301 "userdirectories", 302 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_POPULATIONS_USERDIRECTORIES_LABEL"), 303 "ametysicon-body-idcard-white", 304 null, 305 userDirectories, 306 false 307 ), 308 new StatisticsNode( 309 "credentialproviders", 310 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_POPULATIONS_CREDENTIALPROVIDERS_LABEL"), 311 "ametysicon-body-idcard-badge", 312 null, 313 credentialProviders, 314 false 315 ) 316 ), 317 false 318 ), 319 new StatisticsNode( 320 "groupdirectories", 321 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_GROUPDIRECTORIES_LABEL"), 322 "ametysicon-body-people", 323 groups, 324 groupDirectories, 325 false 326 ) 327 ), 328 false 329 ); 330 } 331 332 private StatisticsNode _getConfigurationStatistics() 333 { 334 boolean configProd = !Config.getInstance().getValue("runtime.mode.dev", false, true); 335 String configCaptchaType = Config.getInstance().getValue("runtime.captcha.type", false, ""); 336 Long configMaxUpload = Config.getInstance().getValue("runtime.upload.max-size", false, 0L); 337 boolean configGravatar = Config.getInstance().getValue("runtime.userprofile.imagesource.gravatar", false, true); 338 339 return new StatisticsNode( 340 "config", 341 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_LABEL"), 342 "ametysicon-gear39", 343 null, 344 List.of( 345 new StatisticsValue( 346 "production", 347 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_PRODUCTION_LABEL"), 348 "ametysicon-movie16", 349 configProd 350 ), 351 new StatisticsValue( 352 "captcha", 353 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_CAPTCHA_LABEL"), 354 "ametysicon-abecedary4", 355 configCaptchaType 356 ), 357 new StatisticsValue( 358 "upload", 359 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_UPLOAD_LABEL"), 360 "ametysicon-arrow-up-from", 361 configMaxUpload 362 ), 363 new StatisticsValue( 364 "gravatar", 365 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_GRAVATAR_LABEL"), 366 "ametysicon-body-idcard-black", 367 configGravatar 368 ) 369 ), 370 false 371 ); 372 } 373}