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}