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.Comparator; 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 ), 171 false 172 ); 173 } 174 175 private Statistics _getVersionsStatistics() 176 { 177 return new StatisticsNode( 178 "versions", 179 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_VERSIONS_LABEL"), 180 "ametysicon-maths-number-zero-one", 181 null, 182 _getVersionsChildren(), 183 true 184 ); 185 } 186 187 private List<Statistics> _getVersionsChildren() 188 { 189 return _versionsHandler.getVersions().stream() 190 .map(v -> new StatisticsValue( 191 v.getName(), 192 new I18nizableText(v.getName()), 193 "ametysicon-trademark-ametys", 194 v.getVersion()) 195 ) 196 .map(Statistics.class::cast) 197 .toList(); 198 } 199 200 private Statistics _getPluginsStatistics() 201 { 202 List<Statistics> plugins = PluginsManager.getInstance().getBundledPluginsNames() 203 .stream() 204 .sorted(Comparator.naturalOrder()) 205 .map(pluginName -> new StatisticsValue(pluginName, 206 new I18nizableText(pluginName), 207 "ametysicon-puzzle-piece1", 208 PluginsManager.getInstance().getVersion(pluginName))) 209 .map(Statistics.class::cast) 210 .toList(); 211 212 return new StatisticsNode( 213 "plugins", 214 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_PLUGINS_LABEL"), 215 "ametysicon-puzzle-piece1", 216 null, 217 plugins, 218 false 219 ); 220 } 221 222 private Statistics _getPopulationsAndGropDirectoriesStatistics() 223 { 224 long populations = 0; 225 226 Map<String, Long> userDirectoriesCount = new TreeMap<>(); 227 Map<String, Long> credentialProvidersCount = new TreeMap<>(); 228 229 for (UserPopulation userPopulation : _userPopulationDAO.getUserPopulations(false)) 230 { 231 populations++; 232 233 for (UserDirectory userDirectory : userPopulation.getUserDirectories()) 234 { 235 Long value = userDirectoriesCount.getOrDefault(userDirectory.getUserDirectoryModelId(), 0L); 236 userDirectoriesCount.put(userDirectory.getUserDirectoryModelId(), value + 1); 237 } 238 239 for (CredentialProvider credentialProvider : userPopulation.getCredentialProviders()) 240 { 241 Long value = credentialProvidersCount.getOrDefault(credentialProvider.getCredentialProviderModelId(), 0L); 242 credentialProvidersCount.put(credentialProvider.getCredentialProviderModelId(), value + 1); 243 } 244 } 245 246 List<Statistics> userDirectories = new ArrayList<>(); 247 for (Entry<String, Long> entry : userDirectoriesCount.entrySet()) 248 { 249 userDirectories.add(new StatisticsValue( 250 entry.getKey(), 251 _userDirectoryFactory.getExtension(entry.getKey()).getLabel(), 252 "ametysicon-body-idcard-white", 253 entry.getValue() 254 )); 255 } 256 257 List<Statistics> credentialProviders = new ArrayList<>(); 258 for (Entry<String, Long> entry : credentialProvidersCount.entrySet()) 259 { 260 CredentialProviderModel cp = _credentialProviderFactory.getExtension(entry.getKey()); 261 credentialProviders.add(new StatisticsValue( 262 entry.getKey(), 263 cp.getLabel(), 264 StringUtils.defaultIfBlank(cp.getIconGlyph(), "ametysicon-body-idcard-badge"), 265 entry.getValue() 266 )); 267 } 268 269 long groups = 0; 270 271 Map<String, Long> groupDirectoriesCount = new TreeMap<>(); 272 for (GroupDirectory groupDirectory : _groupDirectoryDAO.getGroupDirectories()) 273 { 274 groups++; 275 276 Long value = groupDirectoriesCount.getOrDefault(groupDirectory.getGroupDirectoryModelId(), 0L); 277 groupDirectoriesCount.put(groupDirectory.getGroupDirectoryModelId(), value + 1); 278 } 279 280 List<Statistics> groupDirectories = new ArrayList<>(); 281 for (Entry<String, Long> entry : groupDirectoriesCount.entrySet()) 282 { 283 groupDirectories.add(new StatisticsValue( 284 entry.getKey(), 285 _groupDirectoryFactory.getExtension(entry.getKey()).getLabel(), 286 "ametysicon-body-people", 287 entry.getValue() 288 )); 289 } 290 291 return new StatisticsNode( 292 "populations-groupdirectories", 293 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_LABEL"), 294 "ametysicon-body-group", 295 populations + groups, 296 List.of( 297 new StatisticsNode( 298 "populations", 299 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_POPULATIONS_LABEL"), 300 "ametysicon-body-people", 301 populations, 302 List.of( 303 new StatisticsNode( 304 "userdirectories", 305 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_POPULATIONS_USERDIRECTORIES_LABEL"), 306 "ametysicon-body-idcard-white", 307 null, 308 userDirectories, 309 false 310 ), 311 new StatisticsNode( 312 "credentialproviders", 313 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_POPULATIONS_CREDENTIALPROVIDERS_LABEL"), 314 "ametysicon-body-idcard-badge", 315 null, 316 credentialProviders, 317 false 318 ) 319 ), 320 false 321 ), 322 new StatisticsNode( 323 "groupdirectories", 324 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_USERPOPULATIONSANDGROUPDIRECTORIES_GROUPDIRECTORIES_LABEL"), 325 "ametysicon-body-people", 326 groups, 327 groupDirectories, 328 false 329 ) 330 ), 331 false 332 ); 333 } 334 335 private StatisticsNode _getConfigurationStatistics() 336 { 337 boolean configProd = !Config.getInstance().getValue("runtime.mode.dev", false, true); 338 String configCaptchaType = Config.getInstance().getValue("runtime.captcha.type", false, ""); 339 Long configMaxUpload = Config.getInstance().getValue("runtime.upload.max-size", false, 0L); 340 boolean configGravatar = Config.getInstance().getValue("runtime.userprofile.imagesource.gravatar", false, true); 341 342 return new StatisticsNode( 343 "config", 344 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_LABEL"), 345 "ametysicon-gear39", 346 null, 347 List.of( 348 new StatisticsValue( 349 "production", 350 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_PRODUCTION_LABEL"), 351 "ametysicon-movie16", 352 configProd 353 ), 354 new StatisticsValue( 355 "captcha", 356 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_CAPTCHA_LABEL"), 357 "ametysicon-abecedary4", 358 configCaptchaType 359 ), 360 new StatisticsValue( 361 "upload", 362 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_UPLOAD_LABEL"), 363 "ametysicon-arrow-up-from", 364 configMaxUpload 365 ), 366 new StatisticsValue( 367 "gravatar", 368 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_CONFIG_GRAVATAR_LABEL"), 369 "ametysicon-body-idcard-black", 370 configGravatar 371 ), 372 new StatisticsValue( 373 "antivirus", 374 new I18nizableText("plugin.admin", "PLUGINS_ADMIN_STATISTICS_KERNEL_SERVER_ANTIVIRUS_LABEL"), 375 "ametysicon-arrow-down-in", 376 AnalyseFileForVirusHelper.isAntivirusEnabled() 377 ) 378 ), 379 false 380 ); 381 } 382}