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}