From 0bd23e09ab9e7d26138637afb838973711475260 Mon Sep 17 00:00:00 2001 From: "Christian P. MOMON" Date: Sun, 23 May 2021 02:03:40 +0200 Subject: [PATCH] Improved metric bar chart computation. --- src/fr/devinsy/statoolinfos/core/Service.java | 78 -- .../statoolinfos/core/StatoolInfos.java | 2 +- .../statoolinfos/htmlize/ChartHtmlizer.java | 1194 +++++++++++++++++ .../statoolinfos/htmlize/ServicePage.java | 115 +- .../htmlize/charts/MonthValues.java | 309 +++++ .../statoolinfos/htmlize/service.xhtml | 2 +- .../devinsy/statoolinfos/metrics/Metric.java | 25 + .../properties/PathPropertyList.java | 116 ++ 8 files changed, 1694 insertions(+), 147 deletions(-) create mode 100644 src/fr/devinsy/statoolinfos/htmlize/ChartHtmlizer.java create mode 100644 src/fr/devinsy/statoolinfos/htmlize/charts/MonthValues.java diff --git a/src/fr/devinsy/statoolinfos/core/Service.java b/src/fr/devinsy/statoolinfos/core/Service.java index 782ab49..ec47fff 100644 --- a/src/fr/devinsy/statoolinfos/core/Service.java +++ b/src/fr/devinsy/statoolinfos/core/Service.java @@ -23,23 +23,16 @@ import java.net.MalformedURLException; import java.net.URL; import java.time.LocalDate; import java.time.LocalDateTime; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.apache.commons.codec.digest.DigestUtils; -import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.devinsy.statoolinfos.checker.PropertyChecks; import fr.devinsy.statoolinfos.crawl.CrawlJournal; -import fr.devinsy.statoolinfos.metrics.Metric; import fr.devinsy.statoolinfos.properties.PathProperties; -import fr.devinsy.statoolinfos.properties.PathProperty; import fr.devinsy.statoolinfos.properties.PathPropertyList; -import fr.devinsy.strings.StringList; -import fr.devinsy.strings.StringSet; /** * The Class Service. @@ -454,82 +447,11 @@ public class Service extends PathPropertyList return result; } - /** - * Gets the metric. - * - * @param path - * the path - * @return the metric - */ - public Metric getMetric(final String path) - { - Metric result; - - String metricName = StringUtils.defaultIfBlank(get(path + ".name"), RegExUtils.removeFirst(path, "^metrics\\.")); - String metricDescription = StringUtils.defaultIfBlank(get(path + ".description"), metricName); - - StringList years = getMetricYears(path).sort(); - - if (years.isEmpty()) - { - result = null; - } - else - { - result = new Metric(path, metricName, metricDescription, years.get(0)); - - for (String year : years) - { - result.getYearValues().add(get(path + "." + year)); - result.getMonthValues().addAll(StatoolInfosUtils.splitMonthValues(get(path + "." + year + ".months"))); - result.getWeekValues().addAll(StatoolInfosUtils.splitWeekValues(get(path + "." + year + ".weeks"))); - result.getDayValues().addAll(StatoolInfosUtils.splitDayValues(get(path + "." + year + ".weeks"))); - } - } - - // - return result; - } - public MetricsList getMetrics() { return this.metricsList; } - /** - * Gets the metric years. - * - * @param path - * the path - * @return the metric years - */ - public StringList getMetricYears(final String path) - { - StringList result; - - StringSet years = new StringSet(); - - Pattern pattern = Pattern.compile("^" + path + "\\.(?\\d{4}).*$"); - - for (PathProperty property : getByPrefix(path)) - { - String subPath = property.getPath(); - Matcher matcher = pattern.matcher(subPath); - if (matcher.matches()) - { - if (matcher.start("year") != -1) - { - years.add(matcher.group("year")); - } - } - } - - result = new StringList(years); - - // - return result; - } - /** * Gets the name. * diff --git a/src/fr/devinsy/statoolinfos/core/StatoolInfos.java b/src/fr/devinsy/statoolinfos/core/StatoolInfos.java index fd76a27..6f9e415 100644 --- a/src/fr/devinsy/statoolinfos/core/StatoolInfos.java +++ b/src/fr/devinsy/statoolinfos/core/StatoolInfos.java @@ -199,7 +199,7 @@ public class StatoolInfos if (StringUtils.startsWith(line, "file.datetime=")) { - lines.set(lineIndex, "file.datetime=" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("YYYY-MM-dd'T'HH:mm:ss"))); + lines.set(lineIndex, "file.datetime=" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))); } } diff --git a/src/fr/devinsy/statoolinfos/htmlize/ChartHtmlizer.java b/src/fr/devinsy/statoolinfos/htmlize/ChartHtmlizer.java new file mode 100644 index 0000000..b4dcd81 --- /dev/null +++ b/src/fr/devinsy/statoolinfos/htmlize/ChartHtmlizer.java @@ -0,0 +1,1194 @@ +/* + * Copyright (C) 2020-2021 Christian Pierre MOMON + * + * This file is part of StatoolInfos, simple service statistics tool. + * + * StatoolInfos is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * StatoolInfos is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with StatoolInfos. If not, see . + */ +package fr.devinsy.statoolinfos.htmlize; + +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fr.devinsy.statoolinfos.HtmlizerContext; +import fr.devinsy.statoolinfos.core.Categories; +import fr.devinsy.statoolinfos.core.Federation; +import fr.devinsy.statoolinfos.core.Organization; +import fr.devinsy.statoolinfos.core.Organizations; +import fr.devinsy.statoolinfos.core.Service; +import fr.devinsy.statoolinfos.core.Services; +import fr.devinsy.statoolinfos.core.StatoolInfosException; +import fr.devinsy.statoolinfos.core.StatoolInfosUtils; +import fr.devinsy.statoolinfos.htmlize.charts.BarChart; +import fr.devinsy.statoolinfos.htmlize.charts.BarChartView; +import fr.devinsy.statoolinfos.htmlize.charts.ChartColor; +import fr.devinsy.statoolinfos.htmlize.charts.ChartColors; +import fr.devinsy.statoolinfos.htmlize.charts.DoughnutChartView; +import fr.devinsy.statoolinfos.htmlize.charts.MonthValues; +import fr.devinsy.statoolinfos.htmlize.charts.PieChart; +import fr.devinsy.statoolinfos.htmlize.charts.PieChart.Position; +import fr.devinsy.statoolinfos.htmlize.charts.PieChartView; +import fr.devinsy.statoolinfos.metrics.StringCounter; +import fr.devinsy.statoolinfos.metrics.StringCounterList; +import fr.devinsy.statoolinfos.metrics.StringCounters; +import fr.devinsy.statoolinfos.properties.PathProperty; +import fr.devinsy.statoolinfos.properties.PathPropertyList; +import fr.devinsy.statoolinfos.stats.StatAgent; +import fr.devinsy.statoolinfos.stats.categories.CategoryStat; +import fr.devinsy.statoolinfos.stats.categories.CategoryStats; +import fr.devinsy.statoolinfos.stats.country.CountryStats; +import fr.devinsy.statoolinfos.stats.organizations.OrganizationTurnoutStats; +import fr.devinsy.statoolinfos.stats.services.HostProviderTypeStats; +import fr.devinsy.statoolinfos.stats.services.HostServerTypeStats; +import fr.devinsy.statoolinfos.stats.services.RegistrationStats; +import fr.devinsy.statoolinfos.stats.services.ServiceInstallTypeStats; +import fr.devinsy.statoolinfos.stats.softwares.SoftwareStat; +import fr.devinsy.statoolinfos.stats.softwares.SoftwareStats; +import fr.devinsy.strings.StringList; + +/** + * The Class ChartHtmlizer. + */ +public class ChartHtmlizer +{ + private static Logger logger = LoggerFactory.getLogger(ChartHtmlizer.class); + + /** + * Instantiates a new chart htmlizer. + */ + private ChartHtmlizer() + { + } + + /** + * Htmlize category distribution chart. + * + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeCategoryDistributionChart() throws StatoolInfosException + { + String result; + + BarChart chart; + + chart = new BarChart("Distribution des catégories les plus proposées"); + chart.addDataset("Catégories"); + + Federation federation = HtmlizerContext.instance().getFederation(); + Categories categories = HtmlizerContext.instance().getCategories(); + + CategoryStats stats = StatAgent.statAllCategories(federation, categories); + stats.sortByServiceCount().reverse(); + + for (CategoryStat stat : stats) + { + if (stat.getServiceCount() > 0) + { + chart.add(stat.getCategory().getName(), stat.getServiceCount(), ChartColor.PURPLE); + } + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize catergory distribution pie chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeCatergoryDistributionPieChart(final Services services) throws StatoolInfosException + { + String result; + + Federation federation = HtmlizerContext.instance().getFederation(); + Categories categories = HtmlizerContext.instance().getCategories(); + + CategoryStats stats = StatAgent.statAllCategories(federation, categories); + stats.sortByServiceCount().reverse(); + + ChartColors colors = ChartColor.valueList(); + colors.remove(ChartColor.BLUE); + + PieChart pie = new PieChart("Répartition des services par catégorie"); + int index = 0; + while ((index < stats.size() && (index < 10))) + { + ChartColor color = colors.get(index); + CategoryStat stat = stats.get(index); + pie.add(StringUtils.abbreviate(stat.getCategory().getName(), 30), stat.getServiceCount(), color); + + index += 1; + } + + int others = 0; + while (index < stats.size()) + { + CategoryStat stat = stats.get(index); + others += stat.getServiceCount(); + + index += 1; + } + pie.add("Autres catégories", others, ChartColor.BLUE); + pie.setLegendPosition(Position.RIGHT); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize host name pie chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeHostNamePieChart(final Services services) throws StatoolInfosException + { + String result; + + ChartColors colors = ChartColor.valueList(); + colors.remove(ChartColor.BLUE); + + StringCounters counters = new StringCounters(); + long unknowns = 0; + for (Service service : services) + { + if (service.getHostProviderType() == null) + { + unknowns += 1; + } + else + { + switch (service.getHostProviderType()) + { + case HOME: + counters.inc("Auto-hébergé"); + break; + + case HOSTEDBAY: + case HOSTEDSERVER: + case OUTSOURCED: + counters.inc(service.getHostName()); + break; + + case UNKNOWN: + unknowns += 1; + default: + } + } + } + + StringCounterList list = counters.toList().sortByCounter().reverse(); + + PieChart pie = new PieChart("Hébergeurs des services"); + pie.setLegendPosition(Position.RIGHT); + + int index = 0; + while ((index < list.size() && (index < 9))) + { + ChartColor color = colors.get(index); + StringCounter counter = list.get(index); + pie.add(counter.getString(), counter.getCounter(), color); + + index += 1; + } + + int others = 0; + while (index < list.size()) + { + StringCounter counter = list.get(index); + others += counter.getCounter(); + + index += 1; + } + pie.add("Autres", others, ChartColor.GREY); + pie.add("Inconnus", unknowns, ChartColor.BLUE); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize host provider type chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + */ + public static String htmlizeHostProviderTypeChart(final Services services) throws StatoolInfosException + { + String result; + + HostProviderTypeStats stats = StatAgent.statHostProviderType(services); + + PieChart pie = new PieChart("Types d'hébergement"); + pie.add("Home", stats.getHomeCount(), ChartColor.GREEN); + pie.add("Baie", stats.getHostedBayCount(), ChartColor.YELLOW); + pie.add("Serveur", stats.getHostedServerCount(), ChartColor.ORANGE); + pie.add("Externalisé", stats.getOutsourcedCount(), ChartColor.RED); + pie.add("Inconnu", stats.getUnknownCount(), ChartColor.BLUE); + pie.setLegendPosition(Position.RIGHT); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize host server type chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + */ + public static String htmlizeHostServerTypeChart(final Services services) throws StatoolInfosException + { + String result; + + HostServerTypeStats stats = StatAgent.statHostServerType(services); + + PieChart pie = new PieChart("Types de serveur"); + pie.add("Nano", stats.getNanoCount(), ChartColor.PURPLE); + pie.add("Physique", stats.getPhysicalCount(), ChartColor.GREEN); + pie.add("Virtuel", stats.getVirtualCount(), ChartColor.YELLOW); + pie.add("Mutualisé", stats.getSharedCount(), ChartColor.ORANGE); + pie.add("Cloud", stats.getCloudCount(), ChartColor.RED); + pie.add("Inconnu", stats.getUnknownCount(), ChartColor.BLUE); + pie.setLegendPosition(Position.RIGHT); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + public static String htmlizeMetricsChart(final String title, final YearMonth start, final YearMonth end, final ChartColor[] colors, final MonthValues... datasets) throws StatoolInfosException + { + String result; + + YearMonth startTarget; + if (start == null) + { + startTarget = null; + for (MonthValues dataset : datasets) + { + YearMonth current = dataset.getOldestTimestamp(); + + if ((startTarget == null) || (current.isBefore(startTarget))) + { + startTarget = current; + } + } + } + else + { + startTarget = start; + } + + YearMonth endTarget; + if (end == null) + { + endTarget = YearMonth.now(); + } + else + { + endTarget = end; + } + + BarChart chart = new BarChart(title); + chart.setStacked(true); + for (MonthValues dataset : datasets) + { + chart.addDataset(dataset.getLabel()); + } + + if (startTarget != null) + { + for (YearMonth timestamp = startTarget; !timestamp.isAfter(endTarget); timestamp = timestamp.plusMonths(1)) + { + String timestampLabel = timestamp.format(DateTimeFormatter.ofPattern("yyyy-MMM", Locale.FRANCE)); + chart.getLabels().add(timestampLabel); + + for (int index = 0; index < datasets.length; index++) + { + double value = datasets[index].getValue(timestamp); + chart.add(index, value, colors[index % colors.length]); + } + } + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize metrics chart. + * + * @param start + * the start + * @param end + * the end + * @param datasets + * the values + * @return the string + * @throws StatoolInfosException + */ + public static String htmlizeMetricsChart(final YearMonth start, final YearMonth end, final MonthValues dataset, final ChartColor color) throws StatoolInfosException + { + String result; + + YearMonth startTarget; + if (start == null) + { + startTarget = dataset.getOldestTimestamp(); + } + else + { + startTarget = start; + } + + YearMonth endTarget; + if (end == null) + { + endTarget = YearMonth.now(); + } + else + { + endTarget = end; + } + + ChartColor targetColor; + if (color == null) + { + targetColor = ChartColor.BLUE; + } + else + { + targetColor = color; + } + + BarChart chart = new BarChart(dataset.getLabel()); + // chart.setStacked(true); + chart.addDataset(dataset.getLabel()); + + if (startTarget != null) + { + for (YearMonth timestamp = startTarget; !timestamp.isAfter(endTarget); timestamp = timestamp.plusMonths(1)) + { + String timestampLabel = timestamp.format(DateTimeFormatter.ofPattern("yyyy-MMM", Locale.FRANCE)); + chart.getLabels().add(timestampLabel); + + double value = dataset.getValue(timestamp); + chart.add(0, value, targetColor); + } + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize organization count chart. + * + * @param federation + * the federation + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeOrganizationCountChart(final Federation federation) throws StatoolInfosException + { + String result; + + BarChart chart; + + chart = new BarChart("Nombre de membres"); + chart.addDataset("Membres"); + + PathPropertyList values = federation.getByYearPrefix("metrics.members.count").sortByPath(); + + for (PathProperty property : values) + { + chart.add(property.getLeaf(), Double.parseDouble(property.getValue()), ChartColor.GREEN); + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * @param organizations + * @return + * @throws StatoolInfosException + */ + public static String htmlizeOrganizationCountryChart(final Organizations organizations) throws StatoolInfosException + { + String result; + + CountryStats stats = StatAgent.statsCountry(organizations); + + PieChart pie = new PieChart("Pays des membres"); + + StringList countries = new StringList(stats.keySet()).sort(); + countries.remove(CountryStats.UNKNOWN_LABEL); + + ChartColors colors = new ChartColors(); + colors.add(ChartColor.GREEN); + colors.add(ChartColor.ORANGE); + colors.add(ChartColor.RED); + colors.add(ChartColor.PURPLE); + colors.add(ChartColor.TURQUOISE); + colors.add(ChartColor.YELLOW); + + int index = 0; + for (String country : countries) + { + pie.add(country, stats.get(country), colors.get(index)); + + index += 1; + } + pie.add("Inconnu", stats.getUnknown(), ChartColor.BLUE); + + pie.setLegendPosition(Position.RIGHT); + + result = PieChartView.build(pie); + + // + return result; + } + + /** + * Htmlize organization in out chart. + * + * @param federation + * the federation + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeOrganizationInOutChart(final Federation federation) throws StatoolInfosException + { + String result; + + BarChart chart = new BarChart("Entrées/Sorties"); + // chart.setStacked(true); + + chart.addDataset("Entrées"); + PathPropertyList values = federation.getByYearPrefix("metrics.members.in").sortByPath(); + for (PathProperty property : values) + { + chart.getLabels().add(property.getLeaf()); + chart.add(0, Double.parseDouble(property.getValue()), ChartColor.GREEN); + } + + chart.addDataset("Sorties"); + values = federation.getByYearPrefix("metrics.members.out").sortByPath(); + for (PathProperty property : values) + { + chart.add(1, Double.parseDouble(property.getValue()), ChartColor.RED); + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize organization turnout chart. + * + * @param organization + * the organization + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeOrganizationTurnoutChart(final Organization organization) throws StatoolInfosException + { + String result; + + Organizations organizations = new Organizations(); + organizations.add(organization); + + result = htmlizeOrganizationTurnoutChart(organizations); + + // + return result; + } + + /** + * Htmlize organization turnout chart. + * + * @param organizations + * the organizations + * @return the string + * @throws StatoolInfosException + */ + public static String htmlizeOrganizationTurnoutChart(final Organizations organizations) throws StatoolInfosException + { + String result; + + OrganizationTurnoutStats stats = StatAgent.statsOrganizationTurnout(organizations); + + PieChart pie = new PieChart("Participation"); + pie.add("1 fichier", stats.getWithSelfFileCount(), ChartColor.ORANGE); + pie.add("n fichiers", stats.getWithServiceFileCount(), ChartColor.YELLOW); + pie.add("Métriques", stats.getWithServiceMetricCount(), ChartColor.GREEN); + pie.add("Passive", stats.getPassiveCount(), ChartColor.BLUE); + pie.setLegendPosition(Position.RIGHT); + + result = PieChartView.build(pie); + + // + return result; + } + + /** + * Htmlize registration chart. + * + * @param stats + * the stats + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeRegistrationBarChart(final RegistrationStats stats) throws StatoolInfosException + { + String result; + + BarChart bar = new BarChart("Types d'inscription"); + bar.addDataset("Nombre"); + bar.add("Sans", stats.getNoneCount(), ChartColor.GREEN); + bar.add("Libre", stats.getFreeCount(), ChartColor.YELLOW); + bar.add("Membre", stats.getMemberCount(), ChartColor.ORANGE); + bar.add("Client", stats.getClientCount(), ChartColor.RED); + bar.add("Inconnu", stats.getUnknownCount(), ChartColor.BLUE); + + result = BarChartView.build(bar); + + // + return result; + } + + /** + * Htmlize registration client pie chart. + * + * @param stats + * the stats + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeRegistrationClientPieChart(final RegistrationStats stats) throws StatoolInfosException + { + String result; + + PieChart pie = new PieChart("Client"); + pie.setLegendVisible(false); + pie.add("Sans", stats.getClientCount(), ChartColor.RED); + pie.add("Client", stats.getCount() - stats.getClientCount(), ChartColor.BLUE); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize registration free pie chart. + * + * @param stats + * the stats + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeRegistrationFreePieChart(final RegistrationStats stats) throws StatoolInfosException + { + String result; + + PieChart pie = new PieChart("Libre"); + pie.setLegendVisible(false); + pie.add("Sans", stats.getFreeCount(), ChartColor.YELLOW); + pie.add("Libre", stats.getCount() - stats.getFreeCount(), ChartColor.BLUE); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize registration member pie chart. + * + * @param stats + * the stats + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeRegistrationMemberPieChart(final RegistrationStats stats) throws StatoolInfosException + { + String result; + + PieChart pie = new PieChart("Membre"); + pie.setLegendVisible(false); + pie.add("Sans", stats.getMemberCount(), ChartColor.ORANGE); + pie.add("Membre", stats.getCount() - stats.getMemberCount(), ChartColor.BLUE); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize registration none pie chart. + * + * @param stats + * the stats + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeRegistrationNonePieChart(final RegistrationStats stats) throws StatoolInfosException + { + String result; + + PieChart pie = new PieChart("Sans"); + pie.setLegendVisible(false); + pie.add("Sans", stats.getNoneCount(), ChartColor.GREEN); + pie.add("Autre", stats.getCount() - stats.getNoneCount(), ChartColor.BLUE); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize service count month chart. + * + * @param federation + * the federation + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountMonthChart(final Federation federation) throws StatoolInfosException + { + String result; + + result = htmlizeServiceCountMonthChart(federation.getAllServices(), + YearMonth.from(StatoolInfosUtils.parseDate(federation.getStartDate()))); + + // + return result; + } + + /** + * Htmlize service count chart. + * + * @param organization + * the organization + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountMonthChart(final Organization organization) throws StatoolInfosException + { + String result; + + LocalDate startDate = StatoolInfosUtils.parseDate(organization.getFederation().getStartDate()); + + if (startDate == null) + { + result = null; + } + else + { + result = htmlizeServiceCountMonthChart(organization.getServices(), YearMonth.from(startDate)); + } + + // + return result; + } + + /** + * Htmlize service count chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountMonthChart(final Services services) throws StatoolInfosException + { + String result; + + YearMonth first = null; + for (Service service : services) + { + LocalDate date = StatoolInfosUtils.parseDate(service.getStartDate()); + if (date != null) + { + YearMonth current = YearMonth.from(date); + if ((first == null) || (first.isBefore(current))) + { + first = current; + } + } + } + + result = htmlizeServiceCountMonthChart(services, first); + + // + return result; + } + + /** + * Htmlize service count month chart. + * + * @param services + * the services + * @param first + * the first + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountMonthChart(final Services services, final YearMonth first) throws StatoolInfosException + { + String result; + + BarChart chart; + + chart = new BarChart("Nombre de services (mois)"); + chart.addDataset("Services"); + + YearMonth now = YearMonth.now(); + YearMonth current = first; + while (current.compareTo(now) <= 0) + { + long count = 0; + for (Service service : services) + { + LocalDate startDate = StatoolInfosUtils.parseDate(service.getStartDate()); + LocalDate endDate = StatoolInfosUtils.parseDate(service.getEndDate()); + + if (startDate != null) + { + YearMonth start = YearMonth.from(startDate); + YearMonth end; + if (endDate == null) + { + end = now; + } + else + { + end = YearMonth.from(endDate); + } + + if ((current.compareTo(start) >= 0) && (current.compareTo(end) <= 0)) + { + count += 1; + } + } + } + + chart.add(current.toString(), count, ChartColor.VIOLET); + + current = current.plusMonths(1); + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize service country chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * )* the statool infos exception + */ + public static String htmlizeServiceCountryChart(final Services services) throws StatoolInfosException + { + String result; + + CountryStats stats = StatAgent.statsCountry(services); + + PieChart pie = new PieChart("Pays des services"); + StringList countries = new StringList(stats.keySet()).sort(); + countries.remove(CountryStats.UNKNOWN_LABEL); + + ChartColors colors = new ChartColors(); + colors.add(ChartColor.GREEN); + colors.add(ChartColor.ORANGE); + colors.add(ChartColor.RED); + colors.add(ChartColor.PURPLE); + colors.add(ChartColor.TURQUOISE); + colors.add(ChartColor.YELLOW); + + int index = 0; + for (String country : countries) + { + pie.add(country, stats.get(country), colors.get(index)); + + index += 1; + } + pie.add("Inconnu", stats.getUnknown(), ChartColor.BLUE); + + pie.setLegendPosition(Position.RIGHT); + + result = PieChartView.build(pie); + + // + return result; + } + + /** + * Htmlize service count year chart. + * + * @param federation + * the federation + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountYearChart(final Federation federation) throws StatoolInfosException + { + String result; + + result = htmlizeServiceCountYearChart(federation.getAllServices(), + StatoolInfosUtils.parseDate(federation.getStartDate()).getYear()); + + // + return result; + } + + /** + * Htmlize service count year chart. + * + * @param organization + * the organization + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountYearChart(final Organization organization) throws StatoolInfosException + { + String result; + + LocalDate startDate = StatoolInfosUtils.parseDate(organization.getFederation().getStartDate()); + + if (startDate == null) + { + result = null; + } + else + { + result = htmlizeServiceCountYearChart(organization.getServices(), startDate.getYear()); + } + + // + return result; + } + + /** + * Htmlize service count year chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountYearChart(final Services services) throws StatoolInfosException + { + String result; + + Integer first = null; + for (Service service : services) + { + LocalDate date = StatoolInfosUtils.parseDate(service.getStartDate()); + if (date != null) + { + int current = date.getYear(); + if ((first == null) || (first < current)) + { + first = current; + } + } + } + + result = htmlizeServiceCountYearChart(services, first); + + // + return result; + } + + /** + * Htmlize service count chart. + * + * @param services + * the services + * @param first + * the first + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceCountYearChart(final Services services, final int first) throws StatoolInfosException + { + String result; + + BarChart chart; + + chart = new BarChart("Nombre de services"); + chart.addDataset("Services"); + + int now = LocalDate.now().getYear(); + int current = first; + while (current <= now) + { + long count = 0; + for (Service service : services) + { + LocalDate startDate = StatoolInfosUtils.parseDate(service.getStartDate()); + LocalDate endDate = StatoolInfosUtils.parseDate(service.getEndDate()); + + if (startDate != null) + { + int start = startDate.getYear(); + int end; + if (endDate == null) + { + end = now; + } + else + { + end = endDate.getYear(); + } + + if ((current >= start) && (current <= end)) + { + count += 1; + } + } + } + + chart.add(String.valueOf(current), count, ChartColor.VIOLET); + + current += 1; + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize service date status chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceDateStatusChart(final Services services) throws StatoolInfosException + { + String result; + + PieChart pie = new PieChart("Services avec ou sans date"); + + long filled = 0; + long unfilled = 0; + for (Service service : services) + { + if (StatoolInfosUtils.parseDate(service.getStartDate()) == null) + { + unfilled += 1; + } + else + { + filled += 1; + } + } + + pie.add("Avec", filled, ChartColor.VIOLET); + pie.add("Sans", unfilled, ChartColor.BLUE); + + pie.setLegendPosition(Position.RIGHT); + + result = PieChartView.build(pie); + + // + return result; + } + + /** + * Htmlize service install type chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeServiceInstallTypeChart(final Services services) throws StatoolInfosException + { + String result; + + ServiceInstallTypeStats stats = StatAgent.statServiceInstallType(services); + + PieChart pie = new PieChart("Types d'installation du service"); + pie.add("Distribution", stats.getDistributionCount(), ChartColor.PURPLE); + pie.add("Fournisseur", stats.getProviderCount(), ChartColor.GREEN); + pie.add("Paquet", stats.getPackageCount(), ChartColor.YELLOW); + pie.add("Outillage", stats.getToolingCount(), ChartColor.ORANGE); + pie.add("Dépôt cloné", stats.getClonerepoCount(), ChartColor.RED); + pie.add("Archive", stats.getArchiveCount(), ChartColor.VIOLET); + pie.add("Sources", stats.getSourcesCount(), ChartColor.GREY); + pie.add("Containeur", stats.getContainerCount(), ChartColor.TURQUOISE); + pie.add("Inconnu", stats.getUnknownCount(), ChartColor.BLUE); + pie.setLegendPosition(Position.RIGHT); + + result = DoughnutChartView.build(pie); + + // + return result; + } + + /** + * Htmlize software distribution chart. + * + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeSoftwareDistributionChart() throws StatoolInfosException + { + String result; + + BarChart chart = new BarChart("Distribution des logiciels proposés par au moins deux services"); + chart.addDataset("Logiciel"); + + Federation federation = HtmlizerContext.instance().getFederation(); + Categories categories = HtmlizerContext.instance().getCategories(); + + SoftwareStats stats = StatAgent.statAllSoftwares(federation, categories); + stats.sortByServiceCount().reverse(); + + for (SoftwareStat stat : stats) + { + if (stat.getServiceCount() > 1) + { + chart.add(stat.getName(), stat.getServiceCount(), ChartColor.PURPLE); + } + } + + result = BarChartView.build(chart); + + // + return result; + } + + /** + * Htmlize software used chart. + * + * @param services + * the services + * @return the string + * @throws StatoolInfosException + * the statool infos exception + */ + public static String htmlizeSoftwareDistributionPieChart(final Services services) throws StatoolInfosException + { + String result; + + Federation federation = HtmlizerContext.instance().getFederation(); + Categories categories = HtmlizerContext.instance().getCategories(); + + SoftwareStats stats = StatAgent.statAllSoftwares(federation, categories); + stats.sortByServiceCount().reverse(); + + ChartColors colors = ChartColor.valueList(); + colors.remove(ChartColor.BLUE); + + PieChart pie = new PieChart("Répartition des services par logiciel"); + int index = 0; + while ((index < stats.size() && (index < 10))) + { + ChartColor color = colors.get(index); + SoftwareStat stat = stats.get(index); + pie.add(stat.getName(), stat.getServiceCount(), color); + + index += 1; + } + + int others = 0; + while (index < stats.size()) + { + SoftwareStat stat = stats.get(index); + others += stat.getServiceCount(); + + index += 1; + } + pie.add("Autres", others, ChartColor.BLUE); + pie.setLegendPosition(Position.RIGHT); + + result = DoughnutChartView.build(pie); + + // + return result; + } +} diff --git a/src/fr/devinsy/statoolinfos/htmlize/ServicePage.java b/src/fr/devinsy/statoolinfos/htmlize/ServicePage.java index c1372c1..a1508d0 100644 --- a/src/fr/devinsy/statoolinfos/htmlize/ServicePage.java +++ b/src/fr/devinsy/statoolinfos/htmlize/ServicePage.java @@ -35,9 +35,8 @@ import fr.devinsy.statoolinfos.core.Organization; import fr.devinsy.statoolinfos.core.Service; import fr.devinsy.statoolinfos.core.StatoolInfosException; import fr.devinsy.statoolinfos.crawl.CrawlCache; -import fr.devinsy.statoolinfos.htmlize.charts.BarMonthsChartView; import fr.devinsy.statoolinfos.htmlize.charts.ChartColor; -import fr.devinsy.statoolinfos.metrics.Metric; +import fr.devinsy.statoolinfos.htmlize.charts.MonthValues; import fr.devinsy.xidyn.XidynException; import fr.devinsy.xidyn.data.DisplayMode; import fr.devinsy.xidyn.data.TagDataManager; @@ -255,83 +254,65 @@ public class ServicePage // service.getPrefixes(); - Metric metric = service.getMetric("metrics.http.hits"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric)); - } + MonthValues metric = service.getMetricMonthValues("metrics.http.hits"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.BLUE)); - metric = service.getMetric("metrics.http.errors"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.RED)); - } + MonthValues metric4 = service.getMetricMonthValues("metrics.http.hits.ipv4"); + MonthValues metric6 = service.getMetricMonthValues("metrics.http.hits.ipv6"); + data.setContent("fooChart", graphicIndex++, + ChartHtmlizer.htmlizeMetricsChart("http.hits (ipv4 + ipv6)", null, null, new ChartColor[] { ChartColor.YELLOW, ChartColor.GREEN }, metric4, metric6)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric4, ChartColor.YELLOW)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric6, ChartColor.GREEN)); - metric = service.getMetric("metrics.http.errors.php"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.RED)); - } + metric4 = service.getMetricMonthValues("metrics.http.hits.bots"); + metric6 = service.getMetricMonthValues("metrics.http.hits.visitors"); + data.setContent("fooChart", graphicIndex++, + ChartHtmlizer.htmlizeMetricsChart("http.hits (visitors + bots)", null, null, new ChartColor[] { ChartColor.GREEN, ChartColor.YELLOW }, metric6, metric4)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric4, ChartColor.YELLOW)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric6, ChartColor.GREEN)); - metric = service.getMetric("metrics.http.hits.ipv4"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric = service.getMetricMonthValues("metrics.http.errors"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.RED)); - metric = service.getMetric("metrics.http.hits.ipv6"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric = service.getMetricMonthValues("metrics.http.errors.php"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.RED)); - metric = service.getMetric("metrics.http.hits.bots"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric = service.getMetricMonthValues("metrics.http.files"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.BLUE)); - metric = service.getMetric("metrics.http.files"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric = service.getMetricMonthValues("metrics.http.pages"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.BLUE)); - metric = service.getMetric("metrics.http.pages"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric = service.getMetricMonthValues("metrics.http.bytes"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.BLUE)); - metric = service.getMetric("metrics.http.bytes"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric = service.getMetricMonthValues("metrics.http.ip"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.BLUE)); - metric = service.getMetric("metrics.http.ip"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric4 = service.getMetricMonthValues("metrics.http.ip.bots"); + metric6 = service.getMetricMonthValues("metrics.http.ip.visitors"); + data.setContent("fooChart", graphicIndex++, + ChartHtmlizer.htmlizeMetricsChart("http.ip (visitors + bots)", null, null, new ChartColor[] { ChartColor.GREEN, ChartColor.YELLOW }, metric6, metric4)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric6, ChartColor.GREEN)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric4, ChartColor.YELLOW)); - metric = service.getMetric("metrics.http.ip.ipv4"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.BLUE)); - } + metric4 = service.getMetricMonthValues("metrics.http.ip.ipv4"); + metric6 = service.getMetricMonthValues("metrics.http.ip.ipv6"); + data.setContent("fooChart", graphicIndex++, + ChartHtmlizer.htmlizeMetricsChart("http.ip (ipv4 + ipv6)", null, null, new ChartColor[] { ChartColor.YELLOW, ChartColor.GREEN }, metric4, metric6)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric4, ChartColor.YELLOW)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric6, ChartColor.GREEN)); - metric = service.getMetric("metrics.http.ip.ipv6"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.RED)); - } + metric = service.getMetricMonthValues("metrics.http.visits"); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric, ChartColor.BLUE)); - metric = service.getMetric("metrics.http.visits"); - if ((metric != null) && (!metric.isEmpty())) - { - data.setContent("fooChart", graphicIndex++, BarMonthsChartView.build(metric, ChartColor.RED)); - } + metric4 = service.getMetricMonthValues("metrics.http.visits.bots"); + metric6 = service.getMetricMonthValues("metrics.http.visits.visitors"); + data.setContent("fooChart", graphicIndex++, + ChartHtmlizer.htmlizeMetricsChart("http.visits (visitors + bots)", null, null, new ChartColor[] { ChartColor.GREEN, ChartColor.YELLOW }, metric6, metric4)); + + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric6, ChartColor.GREEN)); + data.setContent("fooChart", graphicIndex++, ChartHtmlizer.htmlizeMetricsChart(null, null, metric4, ChartColor.YELLOW)); // String content = PresenterUtils.dynamize("/fr/devinsy/statoolinfos/htmlize/service.xhtml", data).toString(); diff --git a/src/fr/devinsy/statoolinfos/htmlize/charts/MonthValues.java b/src/fr/devinsy/statoolinfos/htmlize/charts/MonthValues.java new file mode 100644 index 0000000..4ae8a4d --- /dev/null +++ b/src/fr/devinsy/statoolinfos/htmlize/charts/MonthValues.java @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2021 Christian Pierre MOMON + * + * This file is part of StatoolInfos, simple service statistics tool. + * + * StatoolInfos is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * StatoolInfos is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with StatoolInfos. If not, see . + */ +package fr.devinsy.statoolinfos.htmlize.charts; + +import java.time.YearMonth; +import java.util.HashMap; + +import fr.devinsy.strings.StringList; + +/** + * The Class MonthValues. + */ +public class MonthValues extends HashMap +{ + private static final long serialVersionUID = 1868850913480770744L; + + private String label; + private String description; + + /** + * Instantiates a new month values. + */ + public MonthValues() + { + this(null, null); + } + + /** + * Instantiates a new month values. + * + * @param label + * the label + * @param description + * the description + */ + public MonthValues(final String label, final String description) + { + super(); + this.label = label; + this.description = description; + } + + /** + * Adds the. + * + * @param timestamp + * the timestamp + * @param value + * the value + */ + public void add(final YearMonth timestamp, final double value) + { + put(timestamp, getValue(timestamp) + value); + } + + /** + * Adds the all. + * + * @param source + * the source + */ + public void addAll(final MonthValues source) + { + if (source != null) + { + for (YearMonth timestamp : source.keySet()) + { + add(timestamp, source.getValue(timestamp)); + } + } + } + + /** + * Dec. + * + * @param timestamp + * the timestamp + */ + public void dec(final YearMonth timestamp) + { + put(timestamp, getValue(timestamp) - 1); + } + + /** + * Extract. + * + * @param start + * the start + * @param end + * the end + * @return the month value map + */ + public MonthValues extract(final YearMonth start, final YearMonth end) + { + MonthValues result; + + YearMonth startTarget = normalizeStart(start); + YearMonth endTarget = normalizeEnd(end); + + result = new MonthValues(); + for (YearMonth timestamp : this.keySet()) + { + if ((!timestamp.isBefore(startTarget)) && + (!timestamp.isAfter(endTarget))) + { + result.put(timestamp, get(timestamp)); + } + } + + // + return result; + } + + public String getDescription() + { + return this.description; + } + + public String getLabel() + { + return this.label; + } + + /** + * Gets the normalized timestamps. + * + * @param start + * the start + * @param end + * the end + * @return the normalized timestamps + */ + public StringList getNormalizedTimestamps(final YearMonth start, final YearMonth end) + { + StringList result; + + YearMonth startTarget = normalizeStart(start); + YearMonth endTarget = normalizeEnd(end); + + result = new StringList(); + for (YearMonth timestamp = startTarget; endTarget.isAfter(timestamp); timestamp = timestamp.plusMonths(1)) + { + result.append(timestamp); + } + + // + return result; + } + + /** + * Gets the oldest timestamp. + * + * @return the oldest timestamp + */ + public YearMonth getOldestTimestamp() + { + YearMonth result; + + result = null; + + for (YearMonth timestamp : this.keySet()) + { + if ((result == null) || (timestamp.isBefore(result))) + { + result = timestamp; + } + } + + // + return result; + } + + /** + * Gets the value. + * + * @param timestamp + * the timestamp + * @return the value + */ + public double getValue(final YearMonth timestamp) + { + double result; + + Double value = get(timestamp); + if (value == null) + { + result = 0.0; + } + else + { + result = value; + } + + // + return result; + } + + /** + * Inc. + * + * @param timestamp + * the timestamp + */ + public void inc(final YearMonth timestamp) + { + put(timestamp, getValue(timestamp) + 1); + } + + /** + * Normalize end. + * + * @param end + * the end + * @return the year month + */ + public YearMonth normalizeEnd(final YearMonth end) + { + YearMonth result; + + YearMonth endTarget; + if (end == null) + { + result = YearMonth.now(); + } + else + { + result = end; + } + + // + return result; + } + + /** + * Normalize start. + * + * @param start + * the start + * @return the year month + */ + public YearMonth normalizeStart(final YearMonth start) + { + YearMonth result; + + if (start == null) + { + result = getOldestTimestamp(); + } + else + { + result = start; + } + + // + return result; + } + + public void setDescription(final String description) + { + this.description = description; + } + + public void setLabel(final String label) + { + this.label = label; + } + + /** + * Gets the normalized values. + * + * @param start + * the start + * @param end + * the end + * @return the normalized values + */ + public StringList toNormalizedValues(final YearMonth start, final YearMonth end) + { + StringList result; + + YearMonth startTarget = normalizeStart(start); + YearMonth endTarget = normalizeEnd(end); + + result = new StringList(); + for (YearMonth timestamp = startTarget; endTarget.isAfter(timestamp); timestamp = timestamp.plusMonths(1)) + { + result.append(getValue(timestamp)); + } + + // + return result; + } +} diff --git a/src/fr/devinsy/statoolinfos/htmlize/service.xhtml b/src/fr/devinsy/statoolinfos/htmlize/service.xhtml index f156923..d42c82d 100644 --- a/src/fr/devinsy/statoolinfos/htmlize/service.xhtml +++ b/src/fr/devinsy/statoolinfos/htmlize/service.xhtml @@ -61,7 +61,7 @@
-
+
diff --git a/src/fr/devinsy/statoolinfos/metrics/Metric.java b/src/fr/devinsy/statoolinfos/metrics/Metric.java index f5178ea..b88a156 100644 --- a/src/fr/devinsy/statoolinfos/metrics/Metric.java +++ b/src/fr/devinsy/statoolinfos/metrics/Metric.java @@ -18,9 +18,12 @@ */ package fr.devinsy.statoolinfos.metrics; +import java.time.YearMonth; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import fr.devinsy.statoolinfos.htmlize.charts.MonthValues; import fr.devinsy.strings.StringList; /** @@ -133,4 +136,26 @@ public class Metric this.startYear = startYear; } + /** + * To month values. + * + * @return the month values + */ + public MonthValues toMonthValues() + { + MonthValues result; + + result = new MonthValues(); + result.setLabel(this.name); + + YearMonth timestamp = YearMonth.of(Integer.valueOf(this.startYear), 01); + for (String value : this.monthValues) + { + result.put(timestamp, Double.valueOf(value)); + timestamp = timestamp.plusMonths(1); + } + + // + return result; + } } diff --git a/src/fr/devinsy/statoolinfos/properties/PathPropertyList.java b/src/fr/devinsy/statoolinfos/properties/PathPropertyList.java index ad9603d..8b23c18 100644 --- a/src/fr/devinsy/statoolinfos/properties/PathPropertyList.java +++ b/src/fr/devinsy/statoolinfos/properties/PathPropertyList.java @@ -20,15 +20,20 @@ package fr.devinsy.statoolinfos.properties; import java.net.MalformedURLException; import java.net.URL; +import java.time.YearMonth; import java.util.ArrayList; import java.util.Iterator; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang3.RegExUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import fr.devinsy.statoolinfos.core.StatoolInfosUtils; +import fr.devinsy.statoolinfos.htmlize.charts.MonthValues; +import fr.devinsy.statoolinfos.metrics.Metric; import fr.devinsy.strings.StringList; import fr.devinsy.strings.StringSet; @@ -315,6 +320,117 @@ public class PathPropertyList extends ArrayList implements PathPro return result; } + /** + * Gets the metric. + * + * @param path + * the path + * @return the metric + */ + public Metric getMetric(final String path) + { + Metric result; + + String metricName = StringUtils.defaultIfBlank(get(path + ".name"), RegExUtils.removeFirst(path, "^metrics\\.")); + String metricDescription = StringUtils.defaultIfBlank(get(path + ".description"), metricName); + + StringList years = getMetricYears(path).sort(); + + if (years.isEmpty()) + { + result = null; + } + else + { + result = new Metric(path, metricName, metricDescription, years.get(0)); + + for (String year : years) + { + result.getYearValues().add(get(path + "." + year)); + result.getMonthValues().addAll(StatoolInfosUtils.splitMonthValues(get(path + "." + year + ".months"))); + result.getWeekValues().addAll(StatoolInfosUtils.splitWeekValues(get(path + "." + year + ".weeks"))); + result.getDayValues().addAll(StatoolInfosUtils.splitDayValues(get(path + "." + year + ".weeks"))); + } + } + + // + return result; + } + + /** + * Gets the metric. + * + * @param path + * the path + * @return the metric + */ + public MonthValues getMetricMonthValues(final String path) + { + MonthValues result; + + String metricName = StringUtils.defaultIfBlank(get(path + ".name"), RegExUtils.removeFirst(path, "^metrics\\.")); + String metricDescription = StringUtils.defaultIfBlank(get(path + ".description"), metricName); + + StringList years = getMetricYears(path).sort(); + + result = new MonthValues(metricName, metricDescription); + + for (String year : years) + { + String line = get(path + "." + year + ".months"); + StringList values = StatoolInfosUtils.splitMonthValues(line); + int monthIndex = 1; + for (String value : values) + { + if (!StringUtils.isBlank(value)) + { + YearMonth timestamp = YearMonth.of(Integer.valueOf(year), monthIndex); + + result.put(timestamp, Double.valueOf(value)); + } + + monthIndex += 1; + } + } + + // + return result; + } + + /** + * Gets the metric years. + * + * @param path + * the path + * @return the metric years + */ + public StringList getMetricYears(final String path) + { + StringList result; + + StringSet years = new StringSet(); + + Pattern pattern = Pattern.compile("^" + path + "\\.(?\\d{4}).*$"); + + for (PathProperty property : getByPrefix(path)) + { + String subPath = property.getPath(); + Matcher matcher = pattern.matcher(subPath); + if (matcher.matches()) + { + if (matcher.start("year") != -1) + { + years.add(matcher.group("year")); + } + } + } + + result = new StringList(years); + + // + return result; + } + /** * Gets the keys. *