001/*
002 *  Copyright 2026 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.plugins.repository.activities;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022import java.util.Map.Entry;
023
024import javax.jcr.RepositoryException;
025
026import org.apache.avalon.framework.component.Component;
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.avalon.framework.service.Serviceable;
030
031import org.ametys.plugins.repository.AmetysObject;
032import org.ametys.plugins.repository.AmetysObjectIterable;
033import org.ametys.plugins.repository.AmetysObjectResolver;
034import org.ametys.runtime.i18n.I18nizableText;
035import org.ametys.runtime.plugin.component.AbstractLogEnabled;
036import org.ametys.runtime.plugins.admin.statistics.Statistics;
037import org.ametys.runtime.plugins.admin.statistics.StatisticsNode;
038import org.ametys.runtime.plugins.admin.statistics.StatisticsProvider;
039import org.ametys.runtime.plugins.admin.statistics.StatisticsValue;
040
041/**
042 * Provide different statistics related to the repository
043 */
044public class RepositoryStatisticsProvider extends AbstractLogEnabled implements StatisticsProvider, Component, Serviceable
045{
046    /** The ametys object resolver */
047    protected AmetysObjectResolver _resolver;
048    public void service(ServiceManager manager) throws ServiceException
049    {
050        _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE);
051    }
052    
053    public Statistics getStatistics()
054    {
055        return new StatisticsNode("repository", new I18nizableText("Repository"), "ametysicon-trademark-jackrabbit", null, _computeActivitiesStatistics(), true);
056    }
057
058    private List<Statistics> _computeActivitiesStatistics()
059    {
060        try (AmetysObjectIterable<AmetysObject> activityHolders = _resolver.query("//element(*, ametys:activity-holder)"))
061        {
062            Map<String, List<Integer>> countByType = new HashMap<>();
063            
064            for (AmetysObject ao : activityHolders)
065            {
066                if (ao instanceof ActivityHolder activityHolder)
067                {
068                    Map<String, Integer> count = new HashMap<>();
069                    try (AmetysObjectIterable<Activity> activities = activityHolder.getActivities())
070                    {
071                        for (Activity activity : activities)
072                        {
073                            count.merge(activity.getActivityType().getId(), 1, (i, j) -> i + j);
074                        }
075                    }
076                    catch (RepositoryException e)
077                    {
078                        getLogger().error("An error occurred while trying to compute statistics for {}", ao.getName(), e);
079                    }
080                    
081                    for (Entry<String, Integer> entry : count.entrySet())
082                    {
083                        List<Integer> activityCount = countByType.computeIfAbsent(entry.getKey(), k -> new ArrayList<>());
084                        activityCount.add(entry.getValue());
085                    }
086                }
087            }
088            
089            List<Statistics> statisticsByActivities = new ArrayList<>();
090            int grandTotal = 0;
091            for (String activityType : countByType.keySet())
092            {
093                List<Integer> countByHolder = countByType.get(activityType);
094                int size = countByHolder.size();
095                if (size > 0)
096                {
097                    countByHolder.sort(null);
098                    int median = countByHolder.get(size / 2);
099                    int max = countByHolder.getLast();
100                    int total = countByHolder.stream().mapToInt(i -> i).sum();
101                    
102                    grandTotal += total;
103                    
104                    List<Statistics> typeStats = List.of(
105                        new StatisticsValue("max", new I18nizableText("plugin.repository", "PLUGINS_REPOSITORY_STATISTICS_VALUE_MAXIMUM"), "ametysicon-sort51", max),
106                        new StatisticsValue("median", new I18nizableText("plugin.repository", "PLUGINS_REPOSITORY_STATISTICS_VALUE_MEDIAN"), "ametysicon-maths-window-symbol-x", median),
107                        new StatisticsValue("holderCount", new I18nizableText("plugin.repository", "PLUGINS_REPOSITORY_STATISTICS_VALUE_CONTAINER_COUNT"), "ametysicon-folder250", size)
108                    );
109                    statisticsByActivities.add(new StatisticsNode(activityType, new I18nizableText(activityType), "ametysicon-object-bell-black", total, typeStats, false));
110                }
111            }
112            
113            statisticsByActivities.sort((s1, s2) -> s1.getName().compareTo(s2.getName()));
114            
115            return List.of(
116                new StatisticsValue("activity-holder", new I18nizableText("plugin.repository", "PLUGINS_REPOSITORY_STATISTICS_ACTIVITY_HOLDER"), "ametysicon-folder250", activityHolders.getSize()),
117                new StatisticsNode("activities", new I18nizableText("plugin.repository", "PLUGINS_REPOSITORY_STATISTICS_ACTIVITIES"), "ametysicon-object-bell-black", grandTotal, statisticsByActivities, false)
118            );
119        }
120    }
121}