diff --git a/application-admintools-api/src/main/java/com/xwiki/admintools/ServerIdentifier.java b/application-admintools-api/src/main/java/com/xwiki/admintools/ServerInfo.java similarity index 98% rename from application-admintools-api/src/main/java/com/xwiki/admintools/ServerIdentifier.java rename to application-admintools-api/src/main/java/com/xwiki/admintools/ServerInfo.java index db1a71c7..dae979be 100644 --- a/application-admintools-api/src/main/java/com/xwiki/admintools/ServerIdentifier.java +++ b/application-admintools-api/src/main/java/com/xwiki/admintools/ServerInfo.java @@ -30,7 +30,7 @@ * @version $Id$ */ @Role -public interface ServerIdentifier +public interface ServerInfo { /** * Verify if a specific server is used. If a server path is provided in the XWiki configurations, it verifies if the diff --git a/application-admintools-api/src/main/java/com/xwiki/admintools/WikiSizeResult.java b/application-admintools-api/src/main/java/com/xwiki/admintools/WikiSizeResult.java new file mode 100644 index 00000000..69e99f11 --- /dev/null +++ b/application-admintools-api/src/main/java/com/xwiki/admintools/WikiSizeResult.java @@ -0,0 +1,149 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools; + +import org.xwiki.stability.Unstable; + +/** + * Stores info about the size of a wiki. + * + * @version $Id$ + * @since 1.0 + */ +@Unstable +public class WikiSizeResult +{ + private String name; + + private Long userCount; + + private String attachmentsSize; + + private Long attachmentsCount; + + private Long documentsCount; + + /** + * Null constructor to initialize a {@link WikiSizeResult} object. + */ + public WikiSizeResult() + { + } + + /** + * Get the name of the wiki. + * + * @return the name of the wiki. + */ + public String getName() + { + return name; + } + + /** + * Set the name of the wiki. + * + * @param name representing the name of the wiki. + */ + public void setName(String name) + { + this.name = name; + } + + /** + * Get the number of users registered in the wiki. + * + * @return {@link Long} representing the number of users in the wiki. + */ + public Long getUserCount() + { + return userCount; + } + + /** + * Set the number of users registered in the wiki. + * + * @param userCount the number of users in the wiki. + */ + public void setUserCount(Long userCount) + { + this.userCount = userCount; + } + + /** + * Get the total size of the attachments in the wiki. + * + * @return formatted {@link String} with the size of the attachments in the wiki and corresponding size unit. + */ + public String getAttachmentsSize() + { + return attachmentsSize; + } + + /** + * Set the total size of the attachments in the wiki. + * + * @param attachmentsSize the size of the attachments in the wiki and corresponding size unit. + */ + public void setAttachmentsSize(String attachmentsSize) + { + this.attachmentsSize = attachmentsSize; + } + + /** + * Get the total number of the attachments in wiki. + * + * @return the total number of the attachments in wiki. + */ + public Long getAttachmentsCount() + { + return attachmentsCount; + } + + /** + * Set the total number of the attachments in wiki. + * + * @param attachmentsCount the total number of the attachments in wiki. + */ + public void setAttachmentsCount(Long attachmentsCount) + { + this.attachmentsCount = attachmentsCount; + } + + /** + * Get the total number of documents in wiki. + * + * @return the total number of documents in wiki. + */ + public Long getDocumentsCount() + { + return documentsCount; + } + + /** + * Set the total number of documents in wiki. + * + * @param documentsCount the total number of documents in wiki. + */ + public void setDocumentsCount(Long documentsCount) + { + this.documentsCount = documentsCount; + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java index 7dc00973..256a4234 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/AdminToolsManager.java @@ -33,9 +33,10 @@ import com.xwiki.admintools.DataProvider; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; import com.xwiki.admintools.internal.files.ImportantFilesManager; +import com.xwiki.admintools.internal.wikiUsage.InstanceUsage; /** - * Manages the data providers. + * Manages the data that needs to be used by the Admin Tools application. * * @version $Id$ */ @@ -58,6 +59,9 @@ public class AdminToolsManager @Inject private ImportantFilesManager importantFilesManager; + @Inject + private InstanceUsage instanceUsage; + @Inject @Named("context") private ComponentManager contextComponentManager; @@ -119,4 +123,14 @@ public String getFilesSection() { return this.importantFilesManager.renderTemplate(); } + + /** + * Get the rendered template for viewing info about the size of the XWiki instance. + * + * @return a {@link String} representation of the rendered template. + */ + public String getInstanceSizeTemplate() + { + return instanceUsage.renderTemplate(); + } } diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/PingProvider.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/PingProvider.java deleted file mode 100644 index f2d10c10..00000000 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/PingProvider.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * See the NOTICE file distributed with this work for additional - * information regarding copyright ownership. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package com.xwiki.admintools.internal; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - -import org.xwiki.activeinstalls2.internal.PingDataProvider; -import org.xwiki.activeinstalls2.internal.data.DatabasePing; -import org.xwiki.activeinstalls2.internal.data.Ping; -import org.xwiki.activeinstalls2.internal.data.ServletContainerPing; -import org.xwiki.component.annotation.Component; -import org.xwiki.component.phase.Initializable; -import org.xwiki.component.phase.InitializationException; - -/** - * Retrieves {@link Ping} data from Active Installs 2. - * - * @version $Id$ - */ -@Component(roles = PingProvider.class) -@Singleton -public class PingProvider implements Initializable -{ - @Inject - @Named("database") - private PingDataProvider databasePingDataProvider; - - @Inject - @Named("servlet") - private PingDataProvider servletPingDataProvider; - - private Ping ping; - - /** - * Initialize {@link Ping}. - * - * @throws InitializationException - */ - @Override - public void initialize() throws InitializationException - { - ping = new Ping(); - } - - /** - * Initialize and get {@link DatabasePing}. - * - * @return {@link DatabasePing} containing info about the used database. - */ - public DatabasePing getDatabasePing() - { - databasePingDataProvider.provideData(ping); - return ping.getDatabase(); - } - - /** - * Initialize and get {@link ServletContainerPing}. - * - * @return {@link ServletContainerPing} containing info about the used server. - */ - public ServletContainerPing getServletPing() - { - servletPingDataProvider.provideData(ping); - return ping.getServletContainer(); - } -} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/ConfigurationDataProvider.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/ConfigurationDataProvider.java index 2feaa046..b65f9de2 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/ConfigurationDataProvider.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/ConfigurationDataProvider.java @@ -27,14 +27,12 @@ import javax.inject.Singleton; import org.apache.commons.lang.exception.ExceptionUtils; -import org.xwiki.activeinstalls2.internal.data.DatabasePing; -import org.xwiki.activeinstalls2.internal.data.ServletContainerPing; import org.xwiki.component.annotation.Component; import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; -import com.xwiki.admintools.ServerIdentifier; -import com.xwiki.admintools.internal.PingProvider; +import com.xwiki.admintools.ServerInfo; +import com.xwiki.admintools.internal.wikiUsage.UsageDataProvider; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; /** @@ -62,7 +60,7 @@ public class ConfigurationDataProvider extends AbstractDataProvider private CurrentServer currentServer; @Inject - private PingProvider pingProvider; + private UsageDataProvider usageDataProvider; @Override public String getIdentifier() @@ -90,16 +88,16 @@ public Map getDataAsJSON() throws Exception { try { Map systemInfo = new HashMap<>(); - Map dbMetadata = this.identifyDB(); + Map dbMetadata = this.usageDataProvider.getDatabaseMetadata(); systemInfo.put("databaseName", dbMetadata.get(METADATA_NAME)); systemInfo.put("databaseVersion", dbMetadata.get(METADATA_VERSION)); systemInfo.put("xwikiCfgPath", getCurrentServer().getXwikiCfgFolderPath()); systemInfo.put("serverPath", getCurrentServer().getServerPath()); systemInfo.put("tomcatConfPath", this.getCurrentServer().getServerCfgPath()); systemInfo.put("javaVersion", this.getJavaVersion()); - ServletContainerPing currentServerMetadata = this.currentServer.getServerMetadata(); - systemInfo.put("usedServerName", currentServerMetadata.getName()); - systemInfo.put("usedServerVersion", currentServerMetadata.getVersion()); + Map serverMetadata = this.usageDataProvider.getServerMetadata(); + systemInfo.put("usedServerName", serverMetadata.get(METADATA_NAME)); + systemInfo.put("usedServerVersion", serverMetadata.get(METADATA_VERSION)); systemInfo.put("xwikiVersion", getXWikiVersion()); systemInfo.putAll(this.getOSInfo()); return systemInfo; @@ -118,20 +116,6 @@ private String getJavaVersion() return System.getProperty("java.version"); } - /** - * Identify the used database for XWiki by accessing the {@link DatabasePing}. - * - * @return database metadata or {@code null} in case of an error or if the used DB is not supported. - */ - private Map identifyDB() - { - DatabasePing databasePing = pingProvider.getDatabasePing(); - if (databasePing == null) { - return new HashMap<>(); - } - return Map.of(METADATA_NAME, databasePing.getName(), METADATA_VERSION, databasePing.getVersion()); - } - /** * Get info about the OS that XWiki is running on. * @@ -147,13 +131,13 @@ private Map getOSInfo() return result; } - private ServerIdentifier getCurrentServer() + private ServerInfo getCurrentServer() { - ServerIdentifier serverIdentifier = currentServer.getCurrentServer(); - if (serverIdentifier == null) { + ServerInfo serverInfo = currentServer.getCurrentServer(); + if (serverInfo == null) { throw new NullPointerException("Failed to retrieve the current used server, check your configurations."); } - return serverIdentifier; + return serverInfo; } private String getXWikiVersion() diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/AbstractServerIdentifier.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/AbstractServerInfo.java similarity index 92% rename from application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/AbstractServerIdentifier.java rename to application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/AbstractServerInfo.java index d6d51bd5..b6902e7a 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/AbstractServerIdentifier.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/AbstractServerInfo.java @@ -24,15 +24,15 @@ import javax.inject.Inject; import javax.inject.Named; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.configuration.AdminToolsConfiguration; /** - * Common methods for {@link ServerIdentifier} classes. + * Common methods for {@link ServerInfo} classes. * * @version $Id$ */ -public abstract class AbstractServerIdentifier implements ServerIdentifier +public abstract class AbstractServerInfo implements ServerInfo { protected String[] serverCfgPossiblePaths; diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java index 1fb2ac37..5d1dd32e 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/CurrentServer.java @@ -31,8 +31,7 @@ import org.xwiki.component.phase.Initializable; import org.xwiki.component.phase.InitializationException; -import com.xwiki.admintools.ServerIdentifier; -import com.xwiki.admintools.internal.PingProvider; +import com.xwiki.admintools.ServerInfo; /** * Manages the server identifiers and offers endpoints to retrieve info about their paths. @@ -48,12 +47,9 @@ public class CurrentServer implements Initializable private static final String SERVER_VERSION_KEY = "version"; @Inject - private Provider> supportedServers; + private Provider> supportedServers; - private ServerIdentifier currentServerIdentifier; - - @Inject - private PingProvider pingProvider; + private ServerInfo currentServerInfo; @Override public void initialize() throws InitializationException @@ -64,11 +60,11 @@ public void initialize() throws InitializationException /** * Get the used server identifier. * - * @return {@link ServerIdentifier} + * @return {@link ServerInfo} */ - public ServerIdentifier getCurrentServer() + public ServerInfo getCurrentServer() { - return this.currentServerIdentifier; + return this.currentServerInfo; } /** @@ -89,8 +85,8 @@ public List getSupportedDBs() public List getSupportedServers() { List supportedServerList = new ArrayList<>(); - for (ServerIdentifier serverIdentifier : this.supportedServers.get()) { - supportedServerList.add(serverIdentifier.getComponentHint()); + for (ServerInfo serverInfo : this.supportedServers.get()) { + supportedServerList.add(serverInfo.getComponentHint()); } return supportedServerList; } @@ -110,13 +106,11 @@ public ServletContainerPing getServerMetadata() */ public void updateCurrentServer() { - this.currentServerIdentifier = null; - for (ServerIdentifier serverIdentifier : this.supportedServers.get()) { - boolean matchingHint = - getServerMetadata().getName().toLowerCase().contains(serverIdentifier.getComponentHint()); - if (matchingHint && serverIdentifier.foundServerPath()) { - this.currentServerIdentifier = serverIdentifier; - this.currentServerIdentifier.updatePossiblePaths(); + this.currentServerInfo = null; + for (ServerInfo serverInfo : this.supportedServers.get()) { + if (serverInfo.isUsed()) { + this.currentServerInfo = serverInfo; + this.currentServerInfo.updatePossiblePaths(); break; } } diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifier.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/TomcatInfo.java similarity index 75% rename from application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifier.java rename to application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/TomcatInfo.java index 17da35fa..74a7d10f 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifier.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/data/identifiers/TomcatInfo.java @@ -25,25 +25,43 @@ import javax.inject.Named; import javax.inject.Singleton; -import org.apache.commons.lang.StringUtils; import org.xwiki.component.annotation.Component; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; /** - * {@link ServerIdentifier} implementation used for identifying a Tomcat server and retrieving its info. + * {@link ServerInfo} implementation used for identifying a Tomcat server and retrieving its info. * * @version $Id$ */ @Component -@Named(TomcatIdentifier.HINT) +@Named(TomcatInfo.HINT) @Singleton -public class TomcatIdentifier extends AbstractServerIdentifier +public class TomcatInfo extends AbstractServerInfo { /** * Component identifier. */ - public static final String HINT = "tomcat"; + public static final String HINT = "Tomcat"; + + @Override + public boolean isUsed() + { + this.serverPath = null; + String providedConfigServerPath = this.adminToolsConfig.getServerPath(); + if (providedConfigServerPath != null && !providedConfigServerPath.isEmpty()) { + return checkAndSetServerPath(providedConfigServerPath); + } else { + String catalinaBase = System.getProperty("catalina.base"); + String catalinaHome = System.getenv("CATALINA_HOME"); + if (catalinaBase != null && !catalinaBase.isEmpty()) { + return checkAndSetServerPath(catalinaBase); + } else if (catalinaHome != null && !catalinaHome.isEmpty()) { + return checkAndSetServerPath(catalinaHome); + } + } + return false; + } @Override public String getComponentHint() diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/LogsDataResource.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/LogsDataResource.java index b295cf3d..3446f532 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/LogsDataResource.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/LogsDataResource.java @@ -48,7 +48,7 @@ import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.download.DataResource; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; @@ -96,7 +96,7 @@ public String getIdentifier() public byte[] getByteData(Map params) throws IOException, NumberFormatException { try { - ServerIdentifier usedServer = currentServer.getCurrentServer(); + ServerInfo usedServer = currentServer.getCurrentServer(); if (usedServer == null) { throw new NullPointerException("Server not found! Configure path in extension configuration."); } diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResource.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResource.java index 4550f128..f981b2c6 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResource.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResource.java @@ -36,7 +36,7 @@ import org.slf4j.Logger; import org.xwiki.component.annotation.Component; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.configuration.AdminToolsConfiguration; import com.xwiki.admintools.download.DataResource; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; @@ -78,7 +78,7 @@ public void addZipEntry(ZipOutputStream zipOutputStream, Map f public byte[] getByteData(Map params) throws IOException { try { - ServerIdentifier usedServer = currentServer.getCurrentServer(); + ServerInfo usedServer = currentServer.getCurrentServer(); if (usedServer == null) { throw new NullPointerException("Server not found! Configure path in extension configuration."); } diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResource.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResource.java index 28caf86a..c0d8cc3a 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResource.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResource.java @@ -36,7 +36,7 @@ import org.slf4j.Logger; import org.xwiki.component.annotation.Component; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.configuration.AdminToolsConfiguration; import com.xwiki.admintools.download.DataResource; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; @@ -78,7 +78,7 @@ public void addZipEntry(ZipOutputStream zipOutputStream, Map f public byte[] getByteData(Map params) throws IOException { try { - ServerIdentifier usedServer = currentServer.getCurrentServer(); + ServerInfo usedServer = currentServer.getCurrentServer(); if (usedServer == null) { throw new NullPointerException("Server not found! Configure path in extension configuration."); } diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java index 9dbbcc5b..99409f18 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/health/checks/performance/PhysicalSpaceHealthCheck.java @@ -30,7 +30,7 @@ import org.slf4j.Logger; import org.xwiki.component.annotation.Component; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.health.HealthCheck; import com.xwiki.admintools.health.HealthCheckResult; import com.xwiki.admintools.health.HealthCheckResultLevel; @@ -61,7 +61,7 @@ public class PhysicalSpaceHealthCheck implements HealthCheck public HealthCheckResult check() { File diskPartition; - ServerIdentifier server = currentServer.getCurrentServer(); + ServerInfo server = currentServer.getCurrentServer(); if (server == null) { if (System.getProperty("os.name").toLowerCase().contains("windows")) { diskPartition = new File("C:"); diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/wikiUsage/InstanceUsage.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/wikiUsage/InstanceUsage.java new file mode 100644 index 00000000..33949d71 --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/wikiUsage/InstanceUsage.java @@ -0,0 +1,114 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.wikiUsage; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.inject.Inject; +import javax.inject.Singleton; +import javax.script.ScriptContext; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.xwiki.component.annotation.Component; +import org.xwiki.script.ScriptContextManager; +import org.xwiki.template.TemplateManager; +import org.xwiki.wiki.descriptor.WikiDescriptor; +import org.xwiki.wiki.descriptor.WikiDescriptorManager; + +import com.xwiki.admintools.WikiSizeResult; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; + +/** + * Access info about the size of the existing wikis. + * + * @version $Id$ + */ +@Component(roles = InstanceUsage.class) +@Singleton +public class InstanceUsage +{ + private static final String TEMPLATE_NAME = "wikiSizeTemplate.vm"; + + @Inject + private UsageDataProvider usageDataProvider; + + @Inject + private WikiDescriptorManager wikiDescriptorManager; + + @Inject + private Logger logger; + + @Inject + private CurrentServer currentServer; + + @Inject + private TemplateManager templateManager; + + @Inject + private ScriptContextManager scriptContextManager; + + /** + * Get the data in a format given by the associated template. + * + * @return the rendered template as a {@link String}. + */ + public String renderTemplate() + { + try { + ScriptContext scriptContext = this.scriptContextManager.getScriptContext(); + boolean found = currentServer.getCurrentServer() != null; + scriptContext.setAttribute("found", found, ScriptContext.ENGINE_SCOPE); + if (!found) { + this.logger.error("Used server not found!"); + return this.templateManager.render(TEMPLATE_NAME); + } + List instanceUsage = getWikisSize(); + scriptContext.setAttribute("instanceUsage", instanceUsage, ScriptContext.ENGINE_SCOPE); + int extensionCount = usageDataProvider.getExtensionCount(); + scriptContext.setAttribute("extensionCount", extensionCount, ScriptContext.ENGINE_SCOPE); + long totalUsers = usageDataProvider.getInstanceUsersCount(); + scriptContext.setAttribute("totalUsers", totalUsers, ScriptContext.ENGINE_SCOPE); + return this.templateManager.render(TEMPLATE_NAME); + } catch (Exception e) { + this.logger.warn("Failed to render [{}] template. Root cause is: [{}]", TEMPLATE_NAME, + ExceptionUtils.getRootCauseMessage(e)); + return null; + } + } + + private List getWikisSize() + { + List result = new ArrayList<>(); + try { + Collection wikisDescriptors = this.wikiDescriptorManager.getAll(); + for (WikiDescriptor wikiDescriptor : wikisDescriptors) { + result.add(usageDataProvider.getWikiSize(wikiDescriptor)); + } + return result; + } catch (Exception e) { + logger.warn("There have been issues while gathering instance usage data. Root cause is: [{}]", + ExceptionUtils.getRootCauseMessage(e)); + return new ArrayList<>(); + } + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/internal/wikiUsage/UsageDataProvider.java b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/wikiUsage/UsageDataProvider.java new file mode 100644 index 00000000..f4166d9d --- /dev/null +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/internal/wikiUsage/UsageDataProvider.java @@ -0,0 +1,203 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.wikiUsage; + +import java.text.DecimalFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.xwiki.activeinstalls2.internal.PingDataProvider; +import org.xwiki.activeinstalls2.internal.data.DatabasePing; +import org.xwiki.activeinstalls2.internal.data.ExtensionPing; +import org.xwiki.activeinstalls2.internal.data.Ping; +import org.xwiki.activeinstalls2.internal.data.ServletContainerPing; +import org.xwiki.activeinstalls2.internal.data.UsersPing; +import org.xwiki.component.annotation.Component; +import org.xwiki.query.Query; +import org.xwiki.query.QueryException; +import org.xwiki.query.QueryFilter; +import org.xwiki.query.QueryManager; +import org.xwiki.wiki.descriptor.WikiDescriptor; + +import com.xwiki.admintools.WikiSizeResult; + +/** + * Retrieves {@link Ping} data from Active Installs 2. + * + * @version $Id$ + */ +@Component(roles = UsageDataProvider.class) +@Singleton +public class UsageDataProvider +{ + private static final String METADATA_NAME = "name"; + + private static final String METADATA_VERSION = "version"; + + @Inject + @Named("database") + private PingDataProvider databasePingDataProvider; + + @Inject + @Named("servlet") + private PingDataProvider servletPingDataProvider; + + @Inject + @Named("extensions") + private PingDataProvider extensionsPingDataProvider; + + @Inject + @Named("users") + private PingDataProvider usersPingDataProvider; + + @Inject + private QueryManager queryManager; + + @Inject + @Named("count") + private QueryFilter countFilter; + + /** + * Get the database metadata using {@link DatabasePing}. + * + * @return a {@link Map} containing the database metadata. + */ + public Map getDatabaseMetadata() + { + Ping ping = new Ping(); + databasePingDataProvider.provideData(ping); + DatabasePing databasePing = ping.getDatabase(); + if (databasePing == null) { + return new HashMap<>(); + } + return Map.of(METADATA_NAME, databasePing.getName(), METADATA_VERSION, databasePing.getVersion()); + } + + /** + * Get the server metadata using {@link ServletContainerPing}. + * + * @return a {@link Map} containing the server metadata. + */ + public Map getServerMetadata() + { + Ping ping = new Ping(); + servletPingDataProvider.provideData(ping); + String serverName = ping.getServletContainer().getName(); + String serverVersion = ping.getServletContainer().getVersion(); + return Map.of(METADATA_NAME, serverName, METADATA_VERSION, serverVersion); + } + + /** + * Get the number of extensions using {@link ExtensionPing}. + * + * @return a count of the current extensions. + */ + public int getExtensionCount() + { + Ping ping = new Ping(); + extensionsPingDataProvider.provideData(ping); + return ping.getExtensions().size(); + } + + /** + * Get the number of users in instance using {@link UsersPing}. + * + * @return the number of users in the XWiki instance. + */ + public long getInstanceUsersCount() + { + Ping ping = new Ping(); + usersPingDataProvider.provideData(ping); + return ping.getUsers().getTotal(); + } + + /** + * Retrieve info about the size of a given wiki. + * + * @param wikiDescriptor the wiki for which the data will be retrieved. + * @return a {@link WikiSizeResult} containing info about the size of the wiki. + * @throws QueryException if there are any exceptions while running the queries for data retrieval. + */ + public WikiSizeResult getWikiSize(WikiDescriptor wikiDescriptor) throws QueryException + { + WikiSizeResult wikiData = new WikiSizeResult(); + String wikiId = wikiDescriptor.getId(); + wikiData.setName(wikiDescriptor.getPrettyName()); + wikiData.setUserCount(getWikiUserCount(wikiId)); + wikiData.setDocumentsCount(getWikiDocumentsCount(wikiId)); + wikiData.setAttachmentsCount(getWikiAttachmentsCount(wikiId)); + wikiData.setAttachmentsSize(readableSize(getWikiAttachmentSize(wikiId))); + + return wikiData; + } + + private Long getWikiUserCount(String wikiId) throws QueryException + { + StringBuilder statement = new StringBuilder(", BaseObject as obj, IntegerProperty as prop "); + statement.append("where doc.fullName = obj.name and obj.className = 'XWiki.XWikiUsers' and "); + statement.append("prop.id.id = obj.id and prop.id.name = 'active' and prop.value = '1'"); + + Query query = this.queryManager.createQuery(statement.toString(), Query.HQL); + query.addFilter(this.countFilter).setWiki(wikiId); + List results = query.execute(); + return results.get(0); + } + + private long getWikiDocumentsCount(String wikiId) throws QueryException + { + List results = + this.queryManager.createQuery("", Query.XWQL).setWiki(wikiId).addFilter(this.countFilter).execute(); + return results.get(0); + } + + private Long getWikiAttachmentSize(String wikiId) throws QueryException + { + List results = this.queryManager.createQuery( + "select sum(attach.longSize) from XWikiAttachment attach", + Query.XWQL).setWiki(wikiId).execute(); + return results.get(0); + } + + private Long getWikiAttachmentsCount(String wikiId) throws QueryException + { + List results = this.queryManager.createQuery( + "select count(attach) from XWikiAttachment attach", + Query.XWQL).setWiki(wikiId).execute(); + return results.get(0); + } + + private String readableSize(Long number) + { + if (number == null || number <= 0) { + return "0"; + } + List units = List.of("B", "KB", "MB", "GB"); + + int digitGroup = (int) (Math.log10(number) / Math.log10(1024)); + DecimalFormat decimalFormat = new DecimalFormat("#,##0.#"); + String resultedSize = decimalFormat.format(number / Math.pow(1024, digitGroup)); + return String.format("%s %s", resultedSize, units.get(digitGroup)); + } +} diff --git a/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java b/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java index 500be1e5..94197f51 100644 --- a/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java +++ b/application-admintools-default/src/main/java/com/xwiki/admintools/script/AdminToolsScriptService.java @@ -122,6 +122,17 @@ public String getFilesSection() throws AccessDeniedException return this.adminToolsManager.getFilesSection(); } + /** + * Get the rendered template for viewing info about the size of the XWiki instance. + * + * @return a {@link String} representation of the template. + */ + public String getInstanceSizeSection() throws AccessDeniedException + { + this.contextualAuthorizationManager.checkAccess(Right.ADMIN); + return adminToolsManager.getInstanceSizeTemplate(); + } + /** * Check if an Admin Tools Health Check job for the wiki from where the request was made exists. If it does, return * the job instance, else create a new Admin Tools health check request for the given wiki and start the execution. diff --git a/application-admintools-default/src/main/resources/META-INF/components.txt b/application-admintools-default/src/main/resources/META-INF/components.txt index deb7fa2e..886b1356 100644 --- a/application-admintools-default/src/main/resources/META-INF/components.txt +++ b/application-admintools-default/src/main/resources/META-INF/components.txt @@ -3,7 +3,7 @@ com.xwiki.admintools.internal.AdminToolsManager com.xwiki.admintools.internal.data.ConfigurationDataProvider com.xwiki.admintools.internal.data.SecurityDataProvider com.xwiki.admintools.internal.data.identifiers.CurrentServer -com.xwiki.admintools.internal.data.identifiers.TomcatIdentifier +com.xwiki.admintools.internal.data.identifiers.TomcatInfo com.xwiki.admintools.internal.files.resources.XWikiPropertiesFileDataResource com.xwiki.admintools.internal.files.resources.XWikiConfigFileDataResource com.xwiki.admintools.internal.files.resources.LogsDataResource @@ -26,4 +26,5 @@ com.xwiki.admintools.internal.health.checks.memory.CacheMemoryHealthCheck com.xwiki.admintools.internal.health.checks.memory.MemoryHealthCheck com.xwiki.admintools.internal.health.job.HealthCheckJob com.xwiki.admintools.internal.rest.DefaultAdminToolsResource -com.xwiki.admintools.internal.PingProvider +com.xwiki.admintools.internal.wikiUsage.UsageDataProvider +com.xwiki.admintools.internal.wikiUsage.InstanceUsage diff --git a/application-admintools-default/src/main/resources/templates/configurationTemplate.vm b/application-admintools-default/src/main/resources/templates/configurationTemplate.vm index 32ee9f42..1d2b23b7 100644 --- a/application-admintools-default/src/main/resources/templates/configurationTemplate.vm +++ b/application-admintools-default/src/main/resources/templates/configurationTemplate.vm @@ -78,8 +78,7 @@ #else - #set($warningMessage = - $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', + #set($warningMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', [$stringtool.join($services.admintools.getSupportedServers(), ', ')]))) #warning($warningMessage) #end diff --git a/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm b/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm index ab477097..a478a557 100644 --- a/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm +++ b/application-admintools-default/src/main/resources/templates/filesSectionTemplate.vm @@ -60,8 +60,7 @@ #viewLastNLinesMoldal("files") #downloadArchiveModal() #else - #set($warningMessage = - $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', + #set($warningMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', [$stringtool.join($services.admintools.getSupportedServers(), ', ')]))) #warning($warningMessage) #end diff --git a/application-admintools-default/src/main/resources/templates/securityTemplate.vm b/application-admintools-default/src/main/resources/templates/securityTemplate.vm index efcd8d9c..c5b5e23b 100644 --- a/application-admintools-default/src/main/resources/templates/securityTemplate.vm +++ b/application-admintools-default/src/main/resources/templates/securityTemplate.vm @@ -47,8 +47,7 @@ #else - #set($warningMessage = - $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', + #set($warningMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', [$stringtool.join($services.admintools.getSupportedServers(), ', ')]))) #warning($warningMessage) #end diff --git a/application-admintools-default/src/main/resources/templates/wikiSizeTemplate.vm b/application-admintools-default/src/main/resources/templates/wikiSizeTemplate.vm new file mode 100644 index 00000000..bb31338b --- /dev/null +++ b/application-admintools-default/src/main/resources/templates/wikiSizeTemplate.vm @@ -0,0 +1,64 @@ +## --------------------------------------------------------------------------- +## See the NOTICE file distributed with this work for additional +## information regarding copyright ownership. +## +## This is free software; you can redistribute it and/or modify it +## under the terms of the GNU Lesser General Public License as +## published by the Free Software Foundation; either version 2.1 of +## the License, or (at your option) any later version. +## +## This software 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 +## Lesser General Public License for more details. +## +## You should have received a copy of the GNU Lesser General Public +## License along with this software; if not, write to the Free +## Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +## 02110-1301 USA, or see the FSF site: http://www.fsf.org. +## --------------------------------------------------------------------------- +#set ($mainReference = $services.model.createDocumentReference('', ['AdminTools', 'Code'], 'ConfigurationClass')) +#if ($services.licensing.licensor.hasLicensureForEntity($mainReference)) + #if($found == 'true') +
+

$services.icon.renderHTML('drive') + $escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.title'))

+

$escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.description'))

+
+

$escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.total.extensions', + [$extensionCount]))

+

$escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.total.users', + [$totalUsers]))

+
+ #if ($instanceUsage.size() != 0) +
    + #foreach($wikiData in $instanceUsage) + #set($wikiName = "$wikiData.getName()") +
  • $escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.wiki.name', [ + '__WIKINAME__'])).replace('__WIKINAME__', $wikiName)
  • +
      +
    • $escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.wiki.users', [ + $wikiData.getUserCount()]))
    • +
    • $escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.wiki.documents', + [$wikiData.getDocumentsCount()]))
    • +
    • $escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.wiki.attachments', + [$wikiData.getAttachmentsCount(), $wikiData.getAttachmentsSize()]))
    • +
    + #end +
+ #else + #error($escapetool.xml($services.localization.render('adminTools.dashboard.instanceUsage.error'))) + #end +
+
+ #else + #set($warningMessage = $escapetool.xml($services.localization.render('adminTools.dashboard.serverNotFound.error', + [$stringtool.join($services.admintools.getSupportedServers(), ', ')]))) + #warning($warningMessage) + #end +#else + #includeMacros('Licenses.Code.VelocityMacros') + {{error}} + #getMissingLicenseMessage('adminTools.extension.name') + {{/error}} +#end \ No newline at end of file diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java index 977eede5..3e8303e5 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/ConfigurationDataProviderTest.java @@ -31,7 +31,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; -import org.slf4j.Logger; import org.xwiki.activeinstalls2.internal.data.DatabasePing; import org.xwiki.activeinstalls2.internal.data.ServletContainerPing; import org.xwiki.component.util.ReflectionUtils; @@ -45,9 +44,9 @@ import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; -import com.xwiki.admintools.ServerIdentifier; -import com.xwiki.admintools.internal.PingProvider; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; +import com.xwiki.admintools.internal.wikiUsage.UsageDataProvider; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -89,16 +88,13 @@ class ConfigurationDataProviderTest private ScriptContextManager scriptContextManager; @Mock - private ServerIdentifier serverIdentifier; + private ServerInfo serverInfo; @Mock private ScriptContext scriptContext; @MockComponent - private PingProvider pingProvider; - - @Mock - private DatabasePing databasePing; + private UsageDataProvider usageDataProvider; @Mock private ServletContainerPing servletContainerPing; @@ -146,15 +142,12 @@ void beforeEach() when(xcontextProvider.get()).thenReturn(xWikiContext); when(xWikiContext.getWiki()).thenReturn(wiki); when(wiki.getVersion()).thenReturn("xwiki_version"); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn("xwiki_config_folder_path"); - when(serverIdentifier.getServerCfgPath()).thenReturn("server_config_folder_path"); - when(currentServer.getServerMetadata()).thenReturn(servletContainerPing); - when(servletContainerPing.getName()).thenReturn("test_server_name"); - when(servletContainerPing.getVersion()).thenReturn("test_server_version"); - when(pingProvider.getDatabasePing()).thenReturn(databasePing); - when(databasePing.getName()).thenReturn("MySQL"); - when(databasePing.getVersion()).thenReturn("x.y.z"); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn("xwiki_config_folder_path"); + when(serverInfo.getServerCfgPath()).thenReturn("server_config_folder_path"); + when(usageDataProvider.getServerMetadata()).thenReturn( + Map.of("name", "test_server_name", "version", "test_server_version")); + when(usageDataProvider.getDatabaseMetadata()).thenReturn(Map.of("name", "MySQL", "version", "x.y.z")); } @Test @@ -166,7 +159,7 @@ void getIdentifier() @Test void getDataAsJsonDatabaseFail() throws Exception { - when(pingProvider.getDatabasePing()).thenReturn(null); + when(usageDataProvider.getDatabaseMetadata()).thenReturn(new HashMap<>()); Map json = new HashMap<>(defaultJson); json.put("databaseName", null); json.put("databaseVersion", null); @@ -178,9 +171,6 @@ void getDataAsJsonDatabaseFail() throws Exception void getDataAsJsonWithSuccessfulExecution() throws Exception { Map json = new HashMap<>(defaultJson); - when(pingProvider.getDatabasePing()).thenReturn(databasePing); - when(databasePing.getName()).thenReturn("MySQL"); - when(databasePing.getVersion()).thenReturn("x.y.z"); assertEquals(json, configurationDataProvider.getDataAsJSON()); } @@ -214,7 +204,7 @@ void getRenderedDataWithSuccessfulExecution() throws Exception @Test void getRenderedDataWithSuccessfulExecutionButUnsupportedDB() throws Exception { - when(pingProvider.getDatabasePing()).thenReturn(null); + when(usageDataProvider.getDatabaseMetadata()).thenReturn(new HashMap<>()); Map json = new HashMap<>(defaultJson); json.put("databaseName", null); diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java index f102193a..064625d6 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/CurrentServerTest.java @@ -34,7 +34,7 @@ import org.xwiki.test.junit5.mockito.InjectMockComponents; import org.xwiki.test.junit5.mockito.MockComponent; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.configuration.AdminToolsConfiguration; import com.xwiki.admintools.internal.PingProvider; @@ -54,37 +54,26 @@ class CurrentServerTest private CurrentServer currentServer; @MockComponent - private Provider> supportedServers; + private Provider> supportedServers; @MockComponent - private ServerIdentifier serverIdentifier; + private ServerInfo serverInfo; @MockComponent @Named("default") private AdminToolsConfiguration adminToolsConfig; - @MockComponent - private PingProvider pingProvider; - - private ServletContainerPing containerPing; - @BeforeComponent void setUp() { // Mock the list of supported servers. - List mockServerIdentifiers = new ArrayList<>(); - mockServerIdentifiers.add(serverIdentifier); - when(supportedServers.get()).thenReturn(mockServerIdentifiers); - when(serverIdentifier.foundServerPath()).thenReturn(true); - when(serverIdentifier.getComponentHint()).thenReturn("tomcat"); + List mockServerInfos = new ArrayList<>(); + mockServerInfos.add(serverInfo); + when(supportedServers.get()).thenReturn(mockServerInfos); + when(serverInfo.isUsed()).thenReturn(true); // Mock the behavior of adminToolsConfig. when(adminToolsConfig.getServerPath()).thenReturn("exampleServerPath"); - - containerPing = new ServletContainerPing(); - containerPing.setName("tomcat"); - containerPing.setVersion("x.y.z"); - when(pingProvider.getServletPing()).thenReturn(containerPing); } @Test @@ -94,13 +83,13 @@ void initializeFound() throws InitializationException currentServer.initialize(); // Verify that the currentServerIdentifier is set correctly. - assertEquals(serverIdentifier, currentServer.getCurrentServer()); + assertEquals(serverInfo, currentServer.getCurrentServer()); } @Test void initializeWithServerNotFound() throws InitializationException { - when(serverIdentifier.foundServerPath()).thenReturn(false); + when(serverInfo.isUsed()).thenReturn(false); currentServer.initialize(); assertNull(currentServer.getCurrentServer()); @@ -109,19 +98,19 @@ void initializeWithServerNotFound() throws InitializationException @Test void updateCurrentServer() { - when(serverIdentifier.foundServerPath()).thenReturn(false); + when(serverInfo.isUsed()).thenReturn(false); currentServer.updateCurrentServer(); assertNull(currentServer.getCurrentServer()); - when(serverIdentifier.foundServerPath()).thenReturn(true); + when(serverInfo.isUsed()).thenReturn(true); currentServer.updateCurrentServer(); - assertEquals(serverIdentifier, currentServer.getCurrentServer()); + assertEquals(serverInfo, currentServer.getCurrentServer()); } @Test void getSupportedServers() { - when(serverIdentifier.getComponentHint()).thenReturn("testServer"); + when(serverInfo.getComponentHint()).thenReturn("testServer"); // Create the expected list. List testServersList = new ArrayList<>(); diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java index e8f10216..23040098 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/data/identifiers/TomcatIdentifierTest.java @@ -38,7 +38,7 @@ import static org.mockito.Mockito.when; /** - * Unit test for {@link TomcatIdentifier} + * Unit test for {@link TomcatInfo} * * @version $Id$ */ @@ -46,7 +46,7 @@ class TomcatIdentifierTest { @InjectMockComponents - private TomcatIdentifier tomcatIdentifier; + private TomcatInfo tomcatIdentifier; @MockComponent @Named("default") diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java index b0579841..9f8bcf9f 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/ImportantFilesManagerTest.java @@ -40,7 +40,7 @@ import org.xwiki.test.junit5.mockito.InjectMockComponents; import org.xwiki.test.junit5.mockito.MockComponent; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.download.DataResource; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; import com.xwiki.admintools.internal.files.resources.LogsDataResource; @@ -85,7 +85,7 @@ class ImportantFilesManagerTest private CurrentServer currentServer; @MockComponent - private ServerIdentifier serverIdentifier; + private ServerInfo serverInfo; @MockComponent @Named("context") @@ -178,7 +178,7 @@ void downloadMultipleFilesInvalidRequest() throws Exception @Test void renderTemplate() throws Exception { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); // Mock the renderer. when(scriptContextManager.getScriptContext()).thenReturn(scriptContext); diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java index 663223b6..cc57ebec 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/LogsDataResourceTest.java @@ -51,7 +51,7 @@ import com.xpn.xwiki.XWiki; import com.xpn.xwiki.XWikiContext; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -91,7 +91,7 @@ class LogsDataResourceTest private CurrentServer currentServer; @MockComponent - private ServerIdentifier serverIdentifier; + private ServerInfo serverInfo; @MockComponent private Provider contextProvider; @@ -152,8 +152,8 @@ void getByteDataSuccess() throws Exception assertTrue(testFile.exists()); assertTrue(testFile.isFile()); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); readLines(44); assertArrayEquals(String.join("\n", logLines).getBytes(), logsDataResource.getByteData(params)); @@ -165,8 +165,8 @@ void getByteDataFileNotFound() File testFile = new File("server.2023-10-06.log"); assertFalse(testFile.exists()); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); IOException exception = assertThrows(IOException.class, () -> { logsDataResource.getByteData(null); }); @@ -187,8 +187,8 @@ void getByteDataServerNotFound() @Test void getByteDataIncorrectInput() { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); String invalidInput = "not a number"; Map params = Map.of("noLines", new String[] { "not a number" }); Exception exception = assertThrows(Exception.class, () -> logsDataResource.getByteData(params)); @@ -199,8 +199,8 @@ void getByteDataIncorrectInput() @Test void getByteDataNullInput() throws IOException { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); readLines(1000); @@ -210,8 +210,8 @@ void getByteDataNullInput() throws IOException @Test void getByteDataNullNoLines() throws IOException { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLastLogFilePath()).thenReturn(testFile.getAbsolutePath()); Map params = Map.of("noLines", new String[] { null }); readLines(1000); @@ -221,9 +221,9 @@ void getByteDataNullNoLines() throws IOException @Test void addZipEntrySuccessNoFilters() throws IOException { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); - when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); + when(serverInfo.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); logsDataResource.addZipEntry(zipOutputStream, null); verify(zipOutputStream, times(2)).closeEntry(); } @@ -231,9 +231,9 @@ void addZipEntrySuccessNoFilters() throws IOException @Test void addZipEntrySuccessWithFilters() throws IOException { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); - when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); + when(serverInfo.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); Map filters = new HashMap<>(); filters.put("from", new String[] { "06-10-2023" }); @@ -252,9 +252,9 @@ void addZipEntrySuccessWithFilters() throws IOException @Test void addZipEntryFilesOutOfFiltersRange() throws IOException { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); - when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); + when(serverInfo.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}-\\d{2}-\\d{2}")); when(xWiki.getXWikiPreference("dateformat", "dd-MM-yyyy", wikiContext)).thenReturn("dd yy MM"); Map filters = new HashMap<>(); @@ -268,9 +268,9 @@ void addZipEntryFilesOutOfFiltersRange() throws IOException @Test void addZipEntryDateParseError() { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); - when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\bserver\\b")); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); + when(serverInfo.getLogsPattern()).thenReturn(Pattern.compile("\\bserver\\b")); Map filters = new HashMap<>(); filters.put("from", new String[] { "2023-10-03" }); filters.put("to", new String[] { "2023-10-05" }); @@ -282,9 +282,9 @@ void addZipEntryDateParseError() @Test void addZipEntryPatternNotFound() throws IOException { - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); - when(serverIdentifier.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}_\\d{2}_\\d{2}")); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getLogsFolderPath()).thenReturn(logsDir.getAbsolutePath()); + when(serverInfo.getLogsPattern()).thenReturn(Pattern.compile("\\d{4}_\\d{2}_\\d{2}")); Map filters = new HashMap<>(); filters.put("from", new String[] { "2023-10-03" }); filters.put("to", new String[] { "2023-10-05" }); diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java index 618bec01..65a50f9f 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiConfigFileDataResourceTest.java @@ -43,7 +43,7 @@ import org.xwiki.test.junit5.mockito.InjectMockComponents; import org.xwiki.test.junit5.mockito.MockComponent; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.configuration.AdminToolsConfiguration; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; @@ -72,7 +72,7 @@ class XWikiConfigFileDataResourceTest private CurrentServer currentServer; @MockComponent - private ServerIdentifier serverIdentifier; + private ServerInfo serverInfo; @MockComponent @Named("default") @@ -129,8 +129,8 @@ void getIdentifier() void getByteData() throws Exception { when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(cfgDirPath); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(cfgDirPath); assertArrayEquals(readLines(), configFileDataResource.getByteData(null)); } @@ -143,8 +143,8 @@ void getByteDataFileNotFound() cfgDir2.deleteOnExit(); when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(cfgDir2.getAbsolutePath() + "/"); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(cfgDir2.getAbsolutePath() + "/"); Exception exception = assertThrows(Exception.class, () -> { configFileDataResource.getByteData(null); }); @@ -170,8 +170,8 @@ void getByteDataServerNotFound() throws Exception void addZipEntry() throws Exception { when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(cfgDirPath); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(cfgDirPath); configFileDataResource.addZipEntry(zipOutputStream, null); byte[] buff = readLines(); int buffLength = buff.length; @@ -186,8 +186,8 @@ void addZipEntryGetByteFail() throws Exception cfgDir2.deleteOnExit(); when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(cfgDir2.getAbsolutePath() + "/"); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(cfgDir2.getAbsolutePath() + "/"); configFileDataResource.addZipEntry(zipOutputStream, null); verify(zipOutputStream, never()).write(any(), eq(0), anyInt()); diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java index 3934ba96..372ccb1a 100644 --- a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/files/resources/XWikiPropertiesFileDataResourceTest.java @@ -43,7 +43,7 @@ import org.xwiki.test.junit5.mockito.InjectMockComponents; import org.xwiki.test.junit5.mockito.MockComponent; -import com.xwiki.admintools.ServerIdentifier; +import com.xwiki.admintools.ServerInfo; import com.xwiki.admintools.configuration.AdminToolsConfiguration; import com.xwiki.admintools.internal.data.identifiers.CurrentServer; @@ -72,7 +72,7 @@ class XWikiPropertiesFileDataResourceTest private CurrentServer currentServer; @MockComponent - private ServerIdentifier serverIdentifier; + private ServerInfo serverInfo; @MockComponent @Named("default") @@ -129,8 +129,8 @@ void getIdentifier() void getByteData() throws Exception { when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(propertiesDirPath); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(propertiesDirPath); assertArrayEquals(readLines(), propertiesFileDataResource.getByteData(null)); } @@ -143,8 +143,8 @@ void getByteDataFileNotFound() propertiesDir2.deleteOnExit(); when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(propertiesDir2.getAbsolutePath() + "/"); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(propertiesDir2.getAbsolutePath() + "/"); Exception exception = assertThrows(Exception.class, () -> { propertiesFileDataResource.getByteData(null); }); @@ -170,8 +170,8 @@ void getByteDataServerNotFound() throws Exception void addZipEntry() throws Exception { when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(propertiesDirPath); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(propertiesDirPath); propertiesFileDataResource.addZipEntry(zipOutputStream, null); byte[] buff = readLines(); int buffLength = buff.length; @@ -186,8 +186,8 @@ void addZipEntryGetByteFail() throws Exception propertiesDir2.deleteOnExit(); when(adminToolsConfiguration.getExcludedLines()).thenReturn(excludedLines); - when(currentServer.getCurrentServer()).thenReturn(serverIdentifier); - when(serverIdentifier.getXwikiCfgFolderPath()).thenReturn(propertiesDir2.getAbsolutePath() + "/"); + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(serverInfo.getXwikiCfgFolderPath()).thenReturn(propertiesDir2.getAbsolutePath() + "/"); propertiesFileDataResource.addZipEntry(zipOutputStream, null); verify(zipOutputStream, never()).write(any(), eq(0), anyInt()); diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/wikiUsage/InstanceUsageTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/wikiUsage/InstanceUsageTest.java new file mode 100644 index 00000000..06baf4a4 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/wikiUsage/InstanceUsageTest.java @@ -0,0 +1,156 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.wikiUsage; + +import java.util.List; + +import javax.script.ScriptContext; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.mockito.Mock; +import org.xwiki.script.ScriptContextManager; +import org.xwiki.template.TemplateManager; +import org.xwiki.test.LogLevel; +import org.xwiki.test.junit5.LogCaptureExtension; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; +import org.xwiki.wiki.descriptor.WikiDescriptor; +import org.xwiki.wiki.descriptor.WikiDescriptorManager; +import org.xwiki.wiki.manager.WikiManagerException; + +import com.xwiki.admintools.ServerInfo; +import com.xwiki.admintools.WikiSizeResult; +import com.xwiki.admintools.internal.data.identifiers.CurrentServer; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ComponentTest +class InstanceUsageTest +{ + private static final String TEMPLATE_NAME = "wikiSizeTemplate.vm"; + + @InjectMockComponents + private InstanceUsage instanceUsage; + + @MockComponent + private UsageDataProvider usageDataProvider; + + @MockComponent + private WikiDescriptorManager wikiDescriptorManager; + + @MockComponent + private CurrentServer currentServer; + + @RegisterExtension + private LogCaptureExtension logCapture = new LogCaptureExtension(LogLevel.WARN); + + @MockComponent + private TemplateManager templateManager; + + @MockComponent + private ScriptContextManager scriptContextManager; + + @Mock + private ServerInfo serverInfo; + + @Mock + private WikiDescriptor wikiDescriptor; + + @Mock + private ScriptContext scriptContext; + + @Mock + private WikiSizeResult wikiSizeResult; + + @BeforeEach + void setUp() + { + when(currentServer.getCurrentServer()).thenReturn(serverInfo); + when(scriptContextManager.getScriptContext()).thenReturn(scriptContext); + + when(usageDataProvider.getExtensionCount()).thenReturn(2); + when(usageDataProvider.getInstanceUsersCount()).thenReturn(400L); + } + + @Test + void renderTemplate() throws Exception + { + when(wikiDescriptorManager.getAll()).thenReturn(List.of(wikiDescriptor)); + when(usageDataProvider.getWikiSize(wikiDescriptor)).thenReturn(wikiSizeResult); + + when(templateManager.render(TEMPLATE_NAME)).thenReturn("success"); + + assertEquals("success", instanceUsage.renderTemplate()); + verify(scriptContext).setAttribute("found", true, ScriptContext.ENGINE_SCOPE); + verify(scriptContext).setAttribute(eq("instanceUsage"), anyList(), eq(ScriptContext.ENGINE_SCOPE)); + verify(scriptContext).setAttribute("extensionCount", 2, ScriptContext.ENGINE_SCOPE); + verify(scriptContext).setAttribute("totalUsers", 400L, ScriptContext.ENGINE_SCOPE); + assertEquals(0, logCapture.size()); + } + + @Test + void renderTemplateCurrentServerNotFound() throws Exception + { + when(currentServer.getCurrentServer()).thenReturn(null); + when(templateManager.render(TEMPLATE_NAME)).thenReturn("fail"); + assertEquals("fail", instanceUsage.renderTemplate()); + verify(scriptContext).setAttribute("found", false, ScriptContext.ENGINE_SCOPE); + assertEquals("Used server not found!", logCapture.getMessage(0)); + } + + @Test + void renderTemplateGetWikisSizeInfoError() throws Exception + { + when(wikiDescriptorManager.getAll()).thenThrow(new WikiManagerException("Failed to get wiki descriptors.")); + when(templateManager.render(TEMPLATE_NAME)).thenReturn("fail"); + assertEquals("fail", instanceUsage.renderTemplate()); + verify(scriptContext).setAttribute("found", true, ScriptContext.ENGINE_SCOPE); + verify(scriptContext).setAttribute(eq("instanceUsage"), anyList(), eq(ScriptContext.ENGINE_SCOPE)); + verify(scriptContext).setAttribute("extensionCount", 2, ScriptContext.ENGINE_SCOPE); + verify(scriptContext).setAttribute("totalUsers", 400L, ScriptContext.ENGINE_SCOPE); + assertEquals("There have been issues while gathering instance usage data. Root cause is: " + + "[WikiManagerException: Failed to get wiki descriptors.]", logCapture.getMessage(0)); + } + + @Test + void renderTemplateError() throws Exception + { + when(wikiDescriptorManager.getAll()).thenReturn(List.of(wikiDescriptor)); + + when(templateManager.render(TEMPLATE_NAME)).thenThrow(new Exception("Failed to render template.")); + + assertNull(instanceUsage.renderTemplate()); + verify(scriptContext).setAttribute("found", true, ScriptContext.ENGINE_SCOPE); + verify(scriptContext).setAttribute(eq("instanceUsage"), anyList(), eq(ScriptContext.ENGINE_SCOPE)); + verify(scriptContext).setAttribute("extensionCount", 2, ScriptContext.ENGINE_SCOPE); + verify(scriptContext).setAttribute("totalUsers", 400L, ScriptContext.ENGINE_SCOPE); + assertEquals( + "Failed to render [" + TEMPLATE_NAME + "] template. Root cause is: [Exception: Failed to render template.]", + logCapture.getMessage(0)); + } +} diff --git a/application-admintools-default/src/test/java/com/xwiki/admintools/internal/wikiUsage/UsageDataProviderTest.java b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/wikiUsage/UsageDataProviderTest.java new file mode 100644 index 00000000..1a628fb9 --- /dev/null +++ b/application-admintools-default/src/test/java/com/xwiki/admintools/internal/wikiUsage/UsageDataProviderTest.java @@ -0,0 +1,139 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xwiki.admintools.internal.wikiUsage; + +import java.util.List; + +import javax.inject.Named; + +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.xwiki.query.Query; +import org.xwiki.query.QueryException; +import org.xwiki.query.QueryFilter; +import org.xwiki.query.QueryManager; +import org.xwiki.template.TemplateManager; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; +import org.xwiki.wiki.descriptor.WikiDescriptor; +import org.xwiki.wiki.descriptor.WikiDescriptorManager; + +import com.xwiki.admintools.WikiSizeResult; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ComponentTest +class UsageDataProviderTest +{ + private static final String TEMPLATE_NAME = "wikiSizeTemplate.vm"; + + private static final String WIKI_ID = "wikiId"; + + @InjectMockComponents + private UsageDataProvider usageDataProvider; + + @MockComponent + private WikiDescriptorManager wikiDescriptorManager; + + @MockComponent + private QueryManager queryManager; + + @MockComponent + @Named("count") + private QueryFilter countFilter; + + @MockComponent + private TemplateManager templateManager; + + @Mock + private WikiDescriptor wikiDescriptor; + + @Mock + private Query usersQuery; + + @Mock + private Query docQuery; + + @Mock + private Query attSizeQuery; + + @Mock + private Query attCountQuery; + + @Test + void getWikiSizeInfo() throws Exception + { + when(wikiDescriptor.getId()).thenReturn(WIKI_ID); + when(wikiDescriptor.getPrettyName()).thenReturn("XWiki Wiki Name"); + + when(queryManager.createQuery(", BaseObject as obj, IntegerProperty as prop " + + "where doc.fullName = obj.name and obj.className = 'XWiki.XWikiUsers' and " + + "prop.id.id = obj.id and prop.id.name = 'active' and prop.value = '1'", "hql")).thenReturn(usersQuery); + when(usersQuery.addFilter(countFilter)).thenReturn(usersQuery); + when(usersQuery.setWiki(WIKI_ID)).thenReturn(usersQuery); + when(usersQuery.execute()).thenReturn(List.of(1234L)); + + when(queryManager.createQuery("", "xwql")).thenReturn(docQuery); + when(docQuery.setWiki(WIKI_ID)).thenReturn(docQuery); + when(docQuery.addFilter(countFilter)).thenReturn(docQuery); + when(docQuery.execute()).thenReturn(List.of(12345L)); + + when(queryManager.createQuery( + "select sum(attach.longSize) from XWikiAttachment attach", + "xwql")).thenReturn(attSizeQuery); + when(attSizeQuery.setWiki(WIKI_ID)).thenReturn(attSizeQuery); + when(attSizeQuery.execute()).thenReturn(List.of(123456789L)); + + when(queryManager.createQuery( + "select count(attach) from XWikiAttachment attach", + "xwql")).thenReturn(attCountQuery); + when(attCountQuery.setWiki(WIKI_ID)).thenReturn(attCountQuery); + when(attCountQuery.execute()).thenReturn(List.of(123456L)); + + when(templateManager.render(TEMPLATE_NAME)).thenReturn("success"); + + WikiSizeResult wiki = usageDataProvider.getWikiSize(wikiDescriptor); + + assertEquals(1234L, wiki.getUserCount()); + assertEquals(12345L, wiki.getDocumentsCount()); + assertEquals(123456L, wiki.getAttachmentsCount()); + assertEquals("117.7 MB", wiki.getAttachmentsSize()); + } + + @Test + void getWikiSizeInfoQueryError() throws Exception + { + when(wikiDescriptorManager.getAll()).thenReturn(List.of(wikiDescriptor)); + when(wikiDescriptor.getId()).thenReturn(WIKI_ID); + when(wikiDescriptor.getPrettyName()).thenReturn("XWiki Wiki Name"); + + when(queryManager.createQuery(", BaseObject as obj, IntegerProperty as prop " + + "where doc.fullName = obj.name and obj.className = 'XWiki.XWikiUsers' and " + + "prop.id.id = obj.id and prop.id.name = 'active' and prop.value = '1'", "hql")).thenReturn(usersQuery); + when(usersQuery.addFilter(countFilter)).thenReturn(usersQuery); + when(usersQuery.setWiki(WIKI_ID)).thenReturn(usersQuery); + when(usersQuery.execute()).thenThrow(new QueryException("user query error", usersQuery, new Exception())); + + assertThrows(QueryException.class, () -> usageDataProvider.getWikiSize(wikiDescriptor)); + } +} diff --git a/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml b/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml index 71d43a5e..624e68a3 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/Code/Translations.xml @@ -121,6 +121,17 @@ adminTools.dashboard.healthcheck.message.error=Critical issues were found, pleas adminTools.dashboard.healthcheck.result=Health check results adminTools.dashboard.healthcheck.linkLabel=help links +##Instance usage +adminTools.dashboard.instanceUsage.description=See the stats related to the usage of the instance. +adminTools.dashboard.instanceUsage.error=There have been issues while gathering info about the size of the Wikis. +adminTools.dashboard.instanceUsage.title=Instance usage +adminTools.dashboard.instanceUsage.total.extensions=There are {0} extensions installed. +adminTools.dashboard.instanceUsage.total.users=There are a total of {0} users registered in this XWiki instance. +adminTools.dashboard.instanceUsage.wiki.attachments=Number of attachments: {0} ({1}) +adminTools.dashboard.instanceUsage.wiki.documents=Number of documents: {0} +adminTools.dashboard.instanceUsage.wiki.name=Size info for Wiki {0} +adminTools.dashboard.instanceUsage.wiki.users=Number of users: {0} + ## Security adminTools.dashboard.security.activeEncoding=Active encoding adminTools.dashboard.security.configurationEncoding=Configuration encoding diff --git a/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml b/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml index 539f6793..fb800289 100644 --- a/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml +++ b/application-admintools-ui/src/main/resources/AdminTools/WebHome.xml @@ -244,6 +244,73 @@ {{html clean='false'}} #healthCheckUI() {{/html}} +{{/velocity}} + + + 2, 2 + + + + </property> + </object> + <object> + <name>AdminTools.WebHome</name> + <number>4</number> + <className>XWiki.GadgetClass</className> + <guid>82bfc6e3-4516-42a3-a85f-6a8a81d21120</guid> + <class> + <name>XWiki.GadgetClass</name> + <customClass/> + <customMapping/> + <defaultViewSheet/> + <defaultEditSheet/> + <defaultWeb/> + <nameField/> + <validationScript/> + <content> + <disabled>0</disabled> + <editor>---</editor> + <name>content</name> + <number>2</number> + <picker>0</picker> + <prettyName>content</prettyName> + <rows>5</rows> + <size>40</size> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <classType>com.xpn.xwiki.objects.classes.TextAreaClass</classType> + </content> + <position> + <disabled>0</disabled> + <name>position</name> + <number>3</number> + <picker>0</picker> + <prettyName>position</prettyName> + <size>30</size> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <classType>com.xpn.xwiki.objects.classes.StringClass</classType> + </position> + <title> + <disabled>0</disabled> + <name>title</name> + <number>1</number> + <picker>0</picker> + <prettyName>title</prettyName> + <size>30</size> + <unmodifiable>0</unmodifiable> + <validationMessage/> + <validationRegExp/> + <classType>com.xpn.xwiki.objects.classes.StringClass</classType> + + + + {{velocity}} +{{html}} + $services.admintools.getInstanceSizeSection() +{{/html}} {{/velocity}} @@ -364,7 +431,7 @@ .admin-tools-dashboard-item { background-color: $theme.pageBackgroundColor; border-color: $theme.pageContentBackgroundColor; - min-height: 35rem; + min-height: 40rem; padding: 1rem 1.1rem; } @@ -393,6 +460,11 @@ .health-check-wrapper button { margin-top: 2rem; +} + +.wikis-size-info-list { + max-height: 20rem; + overflow-y: auto; }