From ca14f063929b90a0248bb632bc6b578d385c5ab4 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 01:37:22 +0300 Subject: [PATCH] (Erik Knizat) REPO-2853 Move the Heartbeat class to Community and cleanup legacy code * Move HeartBeat bean definitions to new hearbeat-context.xml * Removed bean definition for the EnterpriseHBDataCollector.java * Refactored code based on code review * Added real data collection to CommunityHBDataCollector.java --- .../heartbeat/CommunityHBDataCollector.java | 275 +++++++++++++++++- .../heartbeat/HBBaseDataCollector.java | 7 +- .../descriptor/DescriptorServiceImpl.java | 1 - .../alfresco/application-context-core.xml | 1 + .../resources/alfresco/bootstrap-context.xml | 13 - .../resources/alfresco/heartbeat-context.xml | 25 ++ 6 files changed, 293 insertions(+), 29 deletions(-) create mode 100644 src/main/resources/alfresco/heartbeat-context.xml diff --git a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java index c9e336d3d2..213d7ec32c 100644 --- a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java +++ b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java @@ -25,35 +25,292 @@ */ package org.alfresco.heartbeat; +import org.alfresco.repo.descriptor.DescriptorDAO; +import org.alfresco.repo.dictionary.CustomModelsInfo; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.usage.RepoUsageComponent; +import org.alfresco.service.cmr.admin.RepoUsage; +import org.alfresco.service.cmr.dictionary.CustomModelService; import org.alfresco.service.cmr.repository.HBDataCollectorService; +import org.alfresco.service.cmr.security.AuthorityService; +import org.alfresco.service.cmr.security.AuthorityType; +import org.alfresco.service.descriptor.Descriptor; +import org.alfresco.service.license.LicenseException; +import org.alfresco.service.transaction.TransactionService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; +import org.springframework.extensions.surf.util.Base64; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.*; public class CommunityHBDataCollector extends HBBaseDataCollector { + /** The logger. */ + private static final Log logger = LogFactory.getLog(CommunityHBDataCollector.class); + /** + * The parameters that we expect to remain static throughout the lifetime of the repository. There is no need to + * continuously update these. + */ + private Map staticParameters; - public CommunityHBDataCollector (HBDataCollectorService dataCollectorService) - { - super(dataCollectorService); + /** The transaction service. */ + private TransactionService transactionService; + + /** DAO for current repository descriptor. */ + private DescriptorDAO currentRepoDescriptorDAO; + + /** DAO for current descriptor. */ + private DescriptorDAO serverDescriptorDAO; + + /** The authority service. */ + private AuthorityService authorityService; + + private RepoUsageComponent repoUsageComponent; + + /** Provides information about custom models */ + private CustomModelService customModelService; + + public void setCurrentRepoDescriptorDAO(DescriptorDAO currentRepoDescriptorDAO) { + this.currentRepoDescriptorDAO = currentRepoDescriptorDAO; } + public void setServerDescriptorDAO(DescriptorDAO serverDescriptorDAO) { + this.serverDescriptorDAO = serverDescriptorDAO; + } + public void setAuthorityService(AuthorityService authorityService) { + this.authorityService = authorityService; + } + public void setRepoUsageComponent(RepoUsageComponent repoUsageComponent) { + this.repoUsageComponent = repoUsageComponent; + } + + public void setTransactionService(TransactionService transactionService) { + this.transactionService = transactionService; + } + + public void setCustomModelService(CustomModelService customModelService) { + this.customModelService = customModelService; + } @Override public List collectData() { String timeStamp = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.sss'Z'").format(new Date()); + List collectedData = new LinkedList<>(); - // Collect some data - HBData data = new HBData("Community_sys_id","Community_collector_id","Community_collector_v", timeStamp); + RetryingTransactionHelper.RetryingTransactionCallback initCallback = new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + lazyInit(); + return null; + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(initCallback, true); - return Arrays.asList(data); + + // collect repository info data + logger.debug("Preparing repository info data..."); + Map infoValues = new HashMap(); + infoValues.put("repoName", this.staticParameters.get("repoName")); + infoValues.put("edition", this.staticParameters.get("edition")); + infoValues.put("versionMajor", this.staticParameters.get("versionMajor")); + infoValues.put("versionMinor", this.staticParameters.get("versionMinor")); + infoValues.put("schema", this.staticParameters.get("schema")); + HBData infoData = new HBData( + this.currentRepoDescriptorDAO.getDescriptor().getId(), + "acs.repository.info", + "1.0", + timeStamp, + infoValues); + collectedData.add(infoData); + + // collect repository usage (system) data + logger.debug("Preparing repository usage (system) data..."); + Runtime runtime = Runtime.getRuntime(); + Map systemUsageValues = new HashMap(); + systemUsageValues.put("memFree", runtime.freeMemory()); + systemUsageValues.put("memMax", runtime.maxMemory()); + systemUsageValues.put("memTotal", runtime.totalMemory()); + HBData systemUsageData = new HBData( + this.currentRepoDescriptorDAO.getDescriptor().getId(), + "acs.repository.usage.system", + "1.0", + timeStamp, + systemUsageValues); + collectedData.add(systemUsageData); + + // collect repository usage (model) data + logger.debug("Preparing repository usage (model) data..."); + final CustomModelsInfo customModelsInfo = transactionService.getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionHelper.RetryingTransactionCallback() + { + public CustomModelsInfo execute() + { + return customModelService.getCustomModelsInfo(); + } + }, true); + + Map modelUsageValues = new HashMap(); + modelUsageValues.put("numOfActiveModels", new Integer(customModelsInfo.getNumberOfActiveModels())); + modelUsageValues.put("numOfActiveTypes", new Integer(customModelsInfo.getNumberOfActiveTypes())); + modelUsageValues.put("numOfActiveAspects", new Integer(customModelsInfo.getNumberOfActiveAspects())); + HBData modelUsageData = new HBData( + this.currentRepoDescriptorDAO.getDescriptor().getId(), + "acs.repository.usage.model", + "1.0", + timeStamp, + modelUsageValues); + collectedData.add(modelUsageData); + + // collect repository license data + logger.debug("Preparing repository license data..."); + String licenseKey = transactionService.getRetryingTransactionHelper().doInTransaction( + new RetryingTransactionHelper.RetryingTransactionCallback() + { + public String execute() + { + try + { + byte[] licenseKey = currentRepoDescriptorDAO.getLicenseKey(); + return licenseKey == null ? null : org.springframework.extensions.surf.util.Base64.encodeBytes(licenseKey, Base64.DONT_BREAK_LINES); + } + catch (LicenseException e) + { + // Swallow Licence Exception Here + // Don't log error: It'll be reported later and the logging fails + return null; + } + } + }, true); + Map licenseValues = new HashMap(); + if (licenseKey != null) + { + licenseValues.put("licenseKey", licenseKey); + } + Long licenseMaxUsers = repoUsageComponent.getRestrictions().getUsers(); + if (licenseMaxUsers != null) + { + licenseValues.put("licenseMaxUsers", licenseMaxUsers); + } + HBData licenseData = new HBData( + this.currentRepoDescriptorDAO.getDescriptor().getId(), + "acs.repository.license", + "1.0", + timeStamp, + licenseValues); + collectedData.add(licenseData); + + return collectedData; + } + + + /** + * Initializes static parameters on first invocation. Avoid doing it on construction due to bootstrap dependencies + * (e.g. patch service must have run) + * + * @throws GeneralSecurityException + * @throws IOException + */ + private synchronized void lazyInit() throws GeneralSecurityException, IOException + { + if (this.staticParameters == null) + { + this.staticParameters = new TreeMap(); + + // Load up the static parameters + final String ip = getLocalIps(); + this.staticParameters.put("ip", ip); + final String uid; + final Descriptor currentRepoDescriptor = this.currentRepoDescriptorDAO.getDescriptor(); + if (currentRepoDescriptor != null) + { + uid = currentRepoDescriptor.getId(); + this.staticParameters.put("uid", uid); + } + else + { + uid = "Unknown"; + } + + final Descriptor serverDescriptor = this.serverDescriptorDAO.getDescriptor(); + this.staticParameters.put("repoName", serverDescriptor.getName()); + this.staticParameters.put("edition", serverDescriptor.getEdition()); + this.staticParameters.put("versionMajor", serverDescriptor.getVersionMajor()); + this.staticParameters.put("versionMinor", serverDescriptor.getVersionMinor()); + this.staticParameters.put("schema", new Integer(serverDescriptor.getSchema())); + this.staticParameters.put("numUsers", new Integer(this.authorityService.getAllAuthoritiesInZone( + AuthorityService.ZONE_APP_DEFAULT, AuthorityType.USER).size())); + this.staticParameters.put("numGroups", new Integer(this.authorityService.getAllAuthoritiesInZone( + AuthorityService.ZONE_APP_DEFAULT, AuthorityType.GROUP).size())); + + if(repoUsageComponent != null) + { + RepoUsage usage = repoUsageComponent.getUsage(); + + if (usage.getUsers() != null) + { + this.staticParameters.put("licenseUsers", new Long((usage.getUsers()))); + } + } + + } + } + + /** + * Attempts to get all the local IP addresses of this machine in order to distinguish it from other nodes in the + * same network. The machine may use a static IP address in conjunction with a loopback adapter (e.g. to support + * Oracle on Windows), so the IP of the default network interface may not be enough to uniquely identify this + * machine. + * + * @return the local IP addresses, separated by the '/' character + */ + private String getLocalIps() + { + final StringBuilder ip = new StringBuilder(1024); + boolean first = true; + try + { + final Enumeration i = NetworkInterface.getNetworkInterfaces(); + while (i.hasMoreElements()) + { + final NetworkInterface n = i.nextElement(); + final Enumeration j = n.getInetAddresses(); + while (j.hasMoreElements()) + { + InetAddress a = j.nextElement(); + if (a.isLoopbackAddress()) + { + continue; + } + if (first) + { + first = false; + } + else + { + ip.append('/'); + } + ip.append(a.getHostAddress()); + } + } + } + catch (final Exception e) + { + // Ignore + } + return first ? "127.0.0.1" : ip.toString(); } } diff --git a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java index d1dc52c24d..46540c9dc6 100644 --- a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java +++ b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java @@ -33,17 +33,12 @@ public abstract class HBBaseDataCollector { private HBDataCollectorService hbDataCollectorService; - public HBBaseDataCollector( HBDataCollectorService dataCollectorService ) { - this.hbDataCollectorService = dataCollectorService; - this.register(); // I'v moved the registering here assuming every collector will do the same? - } - public void register() { hbDataCollectorService.registerCollector(this); } - public void setHBDataCollectorService(HBDataCollectorService hbDataCollectorService) + public void setHbDataCollectorService(HBDataCollectorService hbDataCollectorService) { this.hbDataCollectorService = hbDataCollectorService; } diff --git a/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java b/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java index 20d3db6bcc..7eeb1a21b1 100644 --- a/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java +++ b/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java @@ -307,7 +307,6 @@ public class DescriptorServiceImpl extends AbstractLifecycleBean } // Load heart-beat special service (even if disabled at the moment) - //heartBeat = constructSpecialService("org.alfresco.enterprise.heartbeat.HeartBeat"); heartBeat = constructSpecialService("org.alfresco.heartbeat.HeartBeat"); // Now listen for future license changes diff --git a/src/main/resources/alfresco/application-context-core.xml b/src/main/resources/alfresco/application-context-core.xml index ddac5f146c..c58b1c9749 100644 --- a/src/main/resources/alfresco/application-context-core.xml +++ b/src/main/resources/alfresco/application-context-core.xml @@ -52,4 +52,5 @@ + diff --git a/src/main/resources/alfresco/bootstrap-context.xml b/src/main/resources/alfresco/bootstrap-context.xml index 5077a73f3f..4ef5367571 100644 --- a/src/main/resources/alfresco/bootstrap-context.xml +++ b/src/main/resources/alfresco/bootstrap-context.xml @@ -287,19 +287,6 @@ - - - - - - - - - - - - - diff --git a/src/main/resources/alfresco/heartbeat-context.xml b/src/main/resources/alfresco/heartbeat-context.xml new file mode 100644 index 0000000000..a951267d27 --- /dev/null +++ b/src/main/resources/alfresco/heartbeat-context.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +