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