From 0ec01992ec11f1546b38e79c5a4288de87d49f96 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 00:45:08 +0300 Subject: [PATCH 01/21] REPO-2626: Heartbeat: Add data collection to Community code - Initial (bare) implementation of the new Data Collectors - The corresponding spring beans were NOT added. --- .../heartbeat/HBBaseDataCollector.java | 48 ++++++ .../java/org/alfresco/heartbeat/HBData.java | 163 ++++++++++++++++++ .../heartbeat/HBDataCollectorServiceImpl.java | 68 ++++++++ .../repository/HBDataCollectorService.java | 39 +++++ 4 files changed, 318 insertions(+) create mode 100644 src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java create mode 100644 src/main/java/org/alfresco/heartbeat/HBData.java create mode 100644 src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java create mode 100644 src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java diff --git a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java new file mode 100644 index 0000000000..75a462ff27 --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java @@ -0,0 +1,48 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import java.util.List; + +import org.alfresco.service.cmr.repository.HBDataCollectorService; + +public abstract class HBBaseDataCollector +{ + private HBDataCollectorService hbDataCollectorService; + + + public void register() + { + hbDataCollectorService.registerCollector(this); + } + + public void setHBDataCollectorService(HBDataCollectorService hbDataCollectorService) + { + this.hbDataCollectorService = hbDataCollectorService; + } + + public abstract List collectData(); +} diff --git a/src/main/java/org/alfresco/heartbeat/HBData.java b/src/main/java/org/alfresco/heartbeat/HBData.java new file mode 100644 index 0000000000..997653ed9f --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/HBData.java @@ -0,0 +1,163 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * Created by mmuller on 07/07/2017. + */ +public class HBData +{ + public static String SCHEMA_VERSION = "1.0"; + + public static String SCHEMA_VERSION_KEY = "sv"; + public static String SYSTEM_ID_KEY = "sId"; + public static String COLLECTOR_ID_KEY = "cId"; + public static String COLLECTOR_VERSION_KEY = "cv"; + public static String TIMESTAMP_KEY = "t"; + public static String DATA_KEY = "d"; + + private String systemId; + private String collectorId; + private String collectorVersion; + private String timestamp; + private Map data; + + public HBData(String systemId, String collectorId, String collectorVersion, String timestamp) + { + this.systemId = systemId; + this.collectorId = collectorId; + this.collectorVersion = collectorVersion; + this.timestamp = timestamp; + } + + public HBData(String systemId, String collectorId, String collectorVersion, String timestamp, Map data) + { + this.systemId = systemId; + this.collectorId = collectorId; + this.collectorVersion = collectorVersion; + this.timestamp = timestamp; + this.data = data; + } + + public JSONObject getJSONObject() throws JSONException + { + // save data collector properties + // The LinkedHashMap was choose only because for demoing + Map keyValues = new LinkedHashMap(); + keyValues.put(SCHEMA_VERSION_KEY, SCHEMA_VERSION); + keyValues.put(SYSTEM_ID_KEY, this.systemId); + keyValues.put(COLLECTOR_ID_KEY, this.collectorId); + keyValues.put(COLLECTOR_VERSION_KEY, this.collectorVersion); + keyValues.put(TIMESTAMP_KEY, this.timestamp); + + // save collected data + JSONObject jsonObject = new JSONObject(keyValues); + jsonObject.put(DATA_KEY, new JSONObject(this.data)); + return jsonObject; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public String getCollectorId() + { + return collectorId; + } + + public void setCollectorId(String collectorId) + { + this.collectorId = collectorId; + } + + public String getCollectorVersion() + { + return collectorVersion; + } + + public void setCollectorVersion(String collectorVersion) + { + this.collectorVersion = collectorVersion; + } + + public String getTimestamp() + { + return timestamp; + } + + public void setTimestamp(String timestamp) + { + this.timestamp = timestamp; + } + + public Map getData() + { + return data; + } + + public void setData(Map data) + { + this.data = data; + } + + public static void main(String[] args) throws JSONException + { + Map data = new TreeMap(); + data.put("k1","v1"); + data.put("k2",new Integer(2)); + data.put("k3","v3"); + + // ISO-8601 same as JavaScript toISOString() + String timeStamp = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.sss'Z'").format(new Date()); + + HBData collectorData = new HBData("99db325c-13c4-4b74-8d1d-f4800b345c89", + "acs.repository.test", + "1.0", + timeStamp); + + collectorData.setData(data); + + String jsonString = collectorData.getJSONObject().toString(); + System.out.println(":O "); + System.out.println(jsonString); + } + +} diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java new file mode 100644 index 0000000000..faf89651d2 --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -0,0 +1,68 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import java.util.LinkedList; +import java.util.List; + +import org.alfresco.service.cmr.repository.HBDataCollectorService; + +public class HBDataCollectorServiceImpl implements HBDataCollectorService +{ + private List collectors = new LinkedList<>(); +// private HBDataSenderService dataSender; + private boolean enabled; + + @Override + public void registerCollector(HBBaseDataCollector collector) + { + this.collectors.add(collector); + } + + @Override + public void collectAndSendData() + { + for (HBBaseDataCollector collector : collectors) + { + List data = collector.collectData(); +// try +// { +// dataSender.sendData(data); +// } +// catch (Exception e) +// { +// // log exception; +// } + } + } + + @Override + public boolean isHBEnabled() + { + return enabled; + } + +} diff --git a/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java b/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java new file mode 100644 index 0000000000..a61eb257b1 --- /dev/null +++ b/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java @@ -0,0 +1,39 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.service.cmr.repository; + +import org.alfresco.heartbeat.HBBaseDataCollector; + +public interface HBDataCollectorService +{ + void registerCollector(HBBaseDataCollector collector); + + void collectAndSendData(); + + boolean isHBEnabled(); + + +} From 37464d825cfb3d5d8be2327876d7a30251068063 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 01:30:19 +0300 Subject: [PATCH 02/21] (Erik Knizat) REPO-2853 Move the Heartbeat class to Community and cleanup legacy code * Moved HeartBeat to community and refactored * Configured HBDataCollectorService with dummy data collectors in bootstrap-context but this configuration might be moved elsewhere. --- .../heartbeat/CommunityHBDataCollector.java | 59 ++++ .../heartbeat/HBBaseDataCollector.java | 8 +- .../java/org/alfresco/heartbeat/HBData.java | 6 + .../heartbeat/HBDataCollectorServiceImpl.java | 10 + .../org/alfresco/heartbeat/HeartBeat.java | 320 ++++++++++++++++++ .../descriptor/DescriptorServiceImpl.java | 57 ++-- .../resources/alfresco/bootstrap-context.xml | 15 +- 7 files changed, 445 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java create mode 100644 src/main/java/org/alfresco/heartbeat/HeartBeat.java diff --git a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java new file mode 100644 index 0000000000..c9e336d3d2 --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java @@ -0,0 +1,59 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.alfresco.service.cmr.repository.HBDataCollectorService; +import org.springframework.context.ApplicationContext; + +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +public class CommunityHBDataCollector extends HBBaseDataCollector { + + + + public CommunityHBDataCollector (HBDataCollectorService dataCollectorService) + { + super(dataCollectorService); + } + + + + + @Override + public List collectData() + { + + String timeStamp = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.sss'Z'").format(new Date()); + + // Collect some data + HBData data = new HBData("Community_sys_id","Community_collector_id","Community_collector_v", timeStamp); + + return Arrays.asList(data); + } +} diff --git a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java index 75a462ff27..d1dc52c24d 100644 --- a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java +++ b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java @@ -32,8 +32,12 @@ import org.alfresco.service.cmr.repository.HBDataCollectorService; 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); diff --git a/src/main/java/org/alfresco/heartbeat/HBData.java b/src/main/java/org/alfresco/heartbeat/HBData.java index 997653ed9f..dd7ea9f59f 100644 --- a/src/main/java/org/alfresco/heartbeat/HBData.java +++ b/src/main/java/org/alfresco/heartbeat/HBData.java @@ -138,6 +138,12 @@ public class HBData this.data = data; } + @Override + public String toString() + { + return "HBData(" + systemId + " " + collectorId + " " + collectorVersion + " " + timestamp +")"; + } + public static void main(String[] args) throws JSONException { Map data = new TreeMap(); diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index faf89651d2..bf5e1a6608 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -29,13 +29,21 @@ import java.util.LinkedList; import java.util.List; import org.alfresco.service.cmr.repository.HBDataCollectorService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.context.ApplicationContext; public class HBDataCollectorServiceImpl implements HBDataCollectorService { + + /** The logger. */ + private static final Log logger = LogFactory.getLog(HBDataCollectorServiceImpl.class); + private List collectors = new LinkedList<>(); // private HBDataSenderService dataSender; private boolean enabled; + @Override public void registerCollector(HBBaseDataCollector collector) { @@ -47,7 +55,9 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService { for (HBBaseDataCollector collector : collectors) { + List data = collector.collectData(); + // try // { // dataSender.sendData(data); diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java new file mode 100644 index 0000000000..a4c34c9a99 --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -0,0 +1,320 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.alfresco.repo.descriptor.DescriptorDAO; +import org.alfresco.repo.dictionary.CustomModelsInfo; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +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.LicenseDescriptor; +import org.alfresco.service.license.LicenseException; +import org.alfresco.service.license.LicenseService; +import org.alfresco.service.license.LicenseService.LicenseChangeHandler; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.traitextender.SpringExtensionBundle; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.json.JSONException; +import org.json.JSONObject; +import org.quartz.*; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.extensions.surf.util.Base64; + +import javax.sql.DataSource; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * This class communicates some very basic repository statistics to Alfresco on a regular basis. + * + * @author dward + */ +public class HeartBeat implements LicenseChangeHandler +{ + + private static final String LAMBDA_INGEST_URL = "https://0s910f9ijc.execute-api.eu-west-1.amazonaws.com/Stage/ingest"; + + /** The default enable state */ + private static final boolean DEFAULT_HEARTBEAT_ENABLED = true; + + /** The logger. */ + private static final Log logger = LogFactory.getLog(HeartBeat.class); + + private LicenseService licenseService; + + private Scheduler scheduler; + + /** URL to post heartbeat to. */ + private String heartBeatUrl; + + private boolean testMode = true; + + private final String JOB_NAME = "heartbeat"; + + /** Is the heartbeat enabled */ + private boolean enabled = DEFAULT_HEARTBEAT_ENABLED; + + private HBDataCollectorService dataCollectorService; + + + + /** + * Initialises the heart beat service. Note that dependencies are intentionally 'pulled' rather than injected + * because we don't want these to be reconfigured. + * + * @param context + * the context + */ + public HeartBeat(final ApplicationContext context) + { + this(context, true); + } + + /** + * Initialises the heart beat service, potentially in test mode. Note that dependencies are intentionally 'pulled' + * rather than injected because we don't want these to be reconfigured. + * + * -@param context + * the context + * -@param testMode + * are we running in test mode? If so we send data to local port 9999 rather than an alfresco server. We + * also use a special test encryption certificate and ping on a more frequent basis. + */ + public HeartBeat(final ApplicationContext context, final Boolean testModel) + { + logger.debug("Initialising HeartBeat"); + + + // I think these should be wired by spring instead for proper ioc.. + this.dataCollectorService = (HBDataCollectorService) context.getBean("hbDataCollectorService"); + this.scheduler = (Scheduler) context.getBean("schedulerFactory"); + + this.testMode = testModel; + + try + { + LicenseService licenseService = null; + try + { + licenseService = (LicenseService) context.getBean("licenseService"); + licenseService.registerOnLicenseChange(this); + } + catch (NoSuchBeanDefinitionException e) + { + logger.error("licenseService not found", e); + } + this.licenseService = licenseService; + + // We force the job to be scheduled regardless of the potential state of the licenses + scheduleJob(); + } + catch (final RuntimeException e) + { + throw e; + } + catch (final Exception e) + { + throw new RuntimeException(e); + } + } + + private synchronized void setHeartBeatUrl(String heartBeatUrl) + { + this.heartBeatUrl = heartBeatUrl; + } + + // Determine the URL to send the heartbeat to from the license if not set + private synchronized String getHeartBeatUrl() + { + if (heartBeatUrl == null) + { + // GC: Ignore the standard heartbeat URL and always use the AWS/Lambda URL +// LicenseDescriptor licenseDescriptor = licenseService.getLicense(); +// String url = (licenseDescriptor == null) ? null : licenseDescriptor.getHeartBeatUrl(); +// setHeartBeatUrl(url == null ? HeartBeat.DEFAULT_URL : url); + setHeartBeatUrl(LAMBDA_INGEST_URL); + } + + logger.debug("Returning heartBeatUrl: " + heartBeatUrl); + + return heartBeatUrl; + } + + /** + * @return true if the heartbeat is currently enabled + */ + public synchronized boolean isEnabled() + { + return enabled; + } + + + + /** + * Sends encrypted data over HTTP. + * + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws GeneralSecurityException + * an encryption related exception + */ + public void sendData() throws IOException, GeneralSecurityException + { + this.dataCollectorService.collectAndSendData(); + } + + /** + * Listens for license changes. If a license is change or removed, the heartbeat job is resheduled. + */ + public synchronized void onLicenseChange(LicenseDescriptor licenseDescriptor) + { + logger.debug("Update license called"); + + setHeartBeatUrl(licenseDescriptor.getHeartBeatUrl()); + boolean newEnabled = !licenseDescriptor.isHeartBeatDisabled(); + + if (newEnabled != enabled) + { + logger.debug("State change of heartbeat"); + this.enabled = newEnabled; + try + { + scheduleJob(); + } + catch (Exception e) + { + logger.error("Unable to schedule heart beat", e); + } + } + } + + /** + * License load failure resets the heartbeat back to the default state + */ + @Override + public synchronized void onLicenseFail() + { + boolean newEnabled = DEFAULT_HEARTBEAT_ENABLED; + + if (newEnabled != enabled) + { + logger.debug("State change of heartbeat"); + this.enabled = newEnabled; + try + { + scheduleJob(); + } + catch (Exception e) + { + logger.error("Unable to schedule heart beat", e); + } + } + } + + /** + * Start or stop the hertbeat job depending on whether the heartbeat is enabled or not + * @throws SchedulerException + */ + private synchronized void scheduleJob() throws SchedulerException + { + // Schedule the heart beat to run regularly + if(enabled) + { + logger.debug("heartbeat job scheduled"); + final JobDetail jobDetail = new JobDetail(JOB_NAME, Scheduler.DEFAULT_GROUP, HeartBeatJob.class); + jobDetail.getJobDataMap().put("heartBeat", this); + // Ensure the job wasn't already scheduled in an earlier retry of this transaction + final String triggerName = JOB_NAME + "Trigger"; + scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); + final Trigger trigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, new Date(), null, + //SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 4 * 60 * 60 * 1000); + SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 2 * 60 * 1000); + scheduler.scheduleJob(jobDetail, trigger); + } + else + { + logger.debug("heartbeat job unscheduled"); + final String triggerName = JOB_NAME + "Trigger"; + scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); + } + } + + /** + * The scheduler job responsible for triggering a heartbeat on a regular basis. + */ + public static class HeartBeatJob implements Job + { + public void execute(final JobExecutionContext jobexecutioncontext) throws JobExecutionException + { + final JobDataMap dataMap = jobexecutioncontext.getJobDetail().getJobDataMap(); + final HeartBeat heartBeat = (HeartBeat) dataMap.get("heartBeat"); + try + { + heartBeat.sendData(); + } + catch (final Exception e) + { + if (logger.isDebugEnabled()) + { + // Verbose logging + HeartBeat.logger.debug("Heartbeat job failure", e); + } + else + { + // Heartbeat errors are non-fatal and will show as single line warnings + HeartBeat.logger.warn(e.toString()); + throw new JobExecutionException(e); + } + } + } + } + + +} diff --git a/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java b/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java index a928c23416..20d3db6bcc 100644 --- a/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java +++ b/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java @@ -1,34 +1,35 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco 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 3 of the License, or - * (at your option) any later version. - * - * Alfresco 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 Alfresco. If not, see . - * #L% - */ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ package org.alfresco.repo.descriptor; import java.io.InputStream; import java.lang.reflect.Constructor; import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.heartbeat.HBBaseDataCollector; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -37,6 +38,7 @@ import org.alfresco.repo.usage.RepoUsageComponent; import org.alfresco.service.cmr.admin.RepoUsage; import org.alfresco.service.cmr.admin.RepoUsage.LicenseMode; import org.alfresco.service.cmr.admin.RepoUsage.UsageType; +import org.alfresco.service.cmr.repository.HBDataCollectorService; import org.alfresco.service.descriptor.Descriptor; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.service.license.LicenseDescriptor; @@ -303,9 +305,10 @@ public class DescriptorServiceImpl extends AbstractLifecycleBean ((ConfigurableApplicationContext) applicationContext).getBeanFactory().registerSingleton( "licenseService", licenseService); } - + // Load heart-beat special service (even if disabled at the moment) - heartBeat = constructSpecialService("org.alfresco.enterprise.heartbeat.HeartBeat"); + //heartBeat = constructSpecialService("org.alfresco.enterprise.heartbeat.HeartBeat"); + heartBeat = constructSpecialService("org.alfresco.heartbeat.HeartBeat"); // Now listen for future license changes licenseService.registerOnLicenseChange(this); diff --git a/src/main/resources/alfresco/bootstrap-context.xml b/src/main/resources/alfresco/bootstrap-context.xml index 451d23ab3b..5077a73f3f 100644 --- a/src/main/resources/alfresco/bootstrap-context.xml +++ b/src/main/resources/alfresco/bootstrap-context.xml @@ -269,7 +269,7 @@ - + @@ -287,6 +287,19 @@ + + + + + + + + + + + + + From ca14f063929b90a0248bb632bc6b578d385c5ab4 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 01:37:22 +0300 Subject: [PATCH 03/21] (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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 58f272d01ba17c685e2ec56d5512fb356a32cafd Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 01:46:53 +0300 Subject: [PATCH 04/21] REPO-2625 / REPO-2626: Use of the heartbeat data sender --- .../heartbeat/CommunityHBDataCollector.java | 56 ++++++++++--------- .../heartbeat/HBBaseDataCollector.java | 1 + .../heartbeat/HBDataCollectorServiceImpl.java | 28 +++++----- .../org/alfresco/heartbeat/HeartBeat.java | 56 ++++++------------- .../resources/alfresco/heartbeat-context.xml | 4 ++ 5 files changed, 67 insertions(+), 78 deletions(-) diff --git a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java index 213d7ec32c..f133546798 100644 --- a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java +++ b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java @@ -25,13 +25,25 @@ */ package org.alfresco.heartbeat; +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.alfresco.heartbeat.datasender.HBData; 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; @@ -39,18 +51,10 @@ 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.*; - -public class CommunityHBDataCollector extends HBBaseDataCollector { +public class CommunityHBDataCollector extends HBBaseDataCollector +{ /** The logger. */ private static final Log logger = LogFactory.getLog(CommunityHBDataCollector.class); @@ -78,35 +82,39 @@ public class CommunityHBDataCollector extends HBBaseDataCollector { /** Provides information about custom models */ private CustomModelService customModelService; - public void setCurrentRepoDescriptorDAO(DescriptorDAO currentRepoDescriptorDAO) { + public void setCurrentRepoDescriptorDAO(DescriptorDAO currentRepoDescriptorDAO) + { this.currentRepoDescriptorDAO = currentRepoDescriptorDAO; } - public void setServerDescriptorDAO(DescriptorDAO serverDescriptorDAO) { + public void setServerDescriptorDAO(DescriptorDAO serverDescriptorDAO) + { this.serverDescriptorDAO = serverDescriptorDAO; } - public void setAuthorityService(AuthorityService authorityService) { + public void setAuthorityService(AuthorityService authorityService) + { this.authorityService = authorityService; } - public void setRepoUsageComponent(RepoUsageComponent repoUsageComponent) { + public void setRepoUsageComponent(RepoUsageComponent repoUsageComponent) + { this.repoUsageComponent = repoUsageComponent; } - public void setTransactionService(TransactionService transactionService) { + public void setTransactionService(TransactionService transactionService) + { this.transactionService = transactionService; } - public void setCustomModelService(CustomModelService customModelService) { + 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<>(); RetryingTransactionHelper.RetryingTransactionCallback initCallback = new RetryingTransactionHelper.RetryingTransactionCallback() @@ -120,7 +128,6 @@ public class CommunityHBDataCollector extends HBBaseDataCollector { }; transactionService.getRetryingTransactionHelper().doInTransaction(initCallback, true); - // collect repository info data logger.debug("Preparing repository info data..."); Map infoValues = new HashMap(); @@ -133,7 +140,7 @@ public class CommunityHBDataCollector extends HBBaseDataCollector { this.currentRepoDescriptorDAO.getDescriptor().getId(), "acs.repository.info", "1.0", - timeStamp, + new Date(), infoValues); collectedData.add(infoData); @@ -148,7 +155,7 @@ public class CommunityHBDataCollector extends HBBaseDataCollector { this.currentRepoDescriptorDAO.getDescriptor().getId(), "acs.repository.usage.system", "1.0", - timeStamp, + new Date(), systemUsageValues); collectedData.add(systemUsageData); @@ -171,7 +178,7 @@ public class CommunityHBDataCollector extends HBBaseDataCollector { this.currentRepoDescriptorDAO.getDescriptor().getId(), "acs.repository.usage.model", "1.0", - timeStamp, + new Date(), modelUsageValues); collectedData.add(modelUsageData); @@ -209,14 +216,13 @@ public class CommunityHBDataCollector extends HBBaseDataCollector { this.currentRepoDescriptorDAO.getDescriptor().getId(), "acs.repository.license", "1.0", - timeStamp, + new Date(), 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) diff --git a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java index 46540c9dc6..dbff6352ac 100644 --- a/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java +++ b/src/main/java/org/alfresco/heartbeat/HBBaseDataCollector.java @@ -27,6 +27,7 @@ package org.alfresco.heartbeat; import java.util.List; +import org.alfresco.heartbeat.datasender.HBData; import org.alfresco.service.cmr.repository.HBDataCollectorService; public abstract class HBBaseDataCollector diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index bf5e1a6608..61836dac18 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -28,21 +28,25 @@ package org.alfresco.heartbeat; import java.util.LinkedList; import java.util.List; +import org.alfresco.heartbeat.datasender.HBData; +import org.alfresco.heartbeat.datasender.HBDataSenderService; import org.alfresco.service.cmr.repository.HBDataCollectorService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.context.ApplicationContext; public class HBDataCollectorServiceImpl implements HBDataCollectorService { - /** The logger. */ private static final Log logger = LogFactory.getLog(HBDataCollectorServiceImpl.class); private List collectors = new LinkedList<>(); -// private HBDataSenderService dataSender; + private HBDataSenderService hbDataSenderService; private boolean enabled; + public void setHbDataSenderService(HBDataSenderService hbDataSenderService) + { + this.hbDataSenderService = hbDataSenderService; + } @Override public void registerCollector(HBBaseDataCollector collector) @@ -55,17 +59,15 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService { for (HBBaseDataCollector collector : collectors) { - List data = collector.collectData(); - -// try -// { -// dataSender.sendData(data); -// } -// catch (Exception e) -// { -// // log exception; -// } + try + { + hbDataSenderService.sendData(data); + } + catch (Exception e) + { + // log exception; + } } } diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java index a4c34c9a99..853c8539b2 100644 --- a/src/main/java/org/alfresco/heartbeat/HeartBeat.java +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -25,51 +25,27 @@ */ package org.alfresco.heartbeat; -import org.alfresco.repo.descriptor.DescriptorDAO; -import org.alfresco.repo.dictionary.CustomModelsInfo; -import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; -import org.alfresco.repo.usage.RepoUsageComponent; -import org.alfresco.service.cmr.admin.RepoUsage; -import org.alfresco.service.cmr.dictionary.CustomModelService; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Date; + 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.LicenseDescriptor; -import org.alfresco.service.license.LicenseException; import org.alfresco.service.license.LicenseService; import org.alfresco.service.license.LicenseService.LicenseChangeHandler; -import org.alfresco.service.transaction.TransactionService; -import org.alfresco.traitextender.SpringExtensionBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.json.JSONException; -import org.json.JSONObject; -import org.quartz.*; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SimpleTrigger; +import org.quartz.Trigger; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; -import org.springframework.extensions.surf.util.Base64; - -import javax.sql.DataSource; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.lang.reflect.Method; -import java.net.HttpURLConnection; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.URL; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.cert.Certificate; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.text.SimpleDateFormat; -import java.util.*; /** * This class communicates some very basic repository statistics to Alfresco on a regular basis. @@ -205,13 +181,13 @@ public class HeartBeat implements LicenseChangeHandler * @throws GeneralSecurityException * an encryption related exception */ - public void sendData() throws IOException, GeneralSecurityException + public void collectAndSendData() throws IOException, GeneralSecurityException { this.dataCollectorService.collectAndSendData(); } /** - * Listens for license changes. If a license is change or removed, the heartbeat job is resheduled. + * Listens for license changes. If a license is change or removed, the heartbeat job is rescheduled. */ public synchronized void onLicenseChange(LicenseDescriptor licenseDescriptor) { @@ -297,7 +273,7 @@ public class HeartBeat implements LicenseChangeHandler final HeartBeat heartBeat = (HeartBeat) dataMap.get("heartBeat"); try { - heartBeat.sendData(); + heartBeat.collectAndSendData(); } catch (final Exception e) { diff --git a/src/main/resources/alfresco/heartbeat-context.xml b/src/main/resources/alfresco/heartbeat-context.xml index a951267d27..dd63dfed9a 100644 --- a/src/main/resources/alfresco/heartbeat-context.xml +++ b/src/main/resources/alfresco/heartbeat-context.xml @@ -3,8 +3,12 @@ + + + + From fc05980f98dd351083a4e225fda993da1bcde760 Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Mon, 4 Sep 2017 16:43:45 +0100 Subject: [PATCH 05/21] REPO-2850 Heartbeat: Add support for turning the data collection on/off based on the heartbeat.enabled global property * Add support for enabled property * Add support for hearbeat target url propery --- .../heartbeat/HBDataCollectorServiceImpl.java | 24 +- .../org/alfresco/heartbeat/HeartBeat.java | 581 +++++++++--------- .../repository/HBDataCollectorService.java | 6 +- .../resources/alfresco/heartbeat-context.xml | 60 +- .../resources/alfresco/repository.properties | 4 + 5 files changed, 347 insertions(+), 328 deletions(-) diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index 61836dac18..d2612d0cc5 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -41,7 +41,15 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService private List collectors = new LinkedList<>(); private HBDataSenderService hbDataSenderService; - private boolean enabled; + private boolean enabled = false; + /** The default enable state */ + private final boolean defaultHbState; + + public HBDataCollectorServiceImpl (boolean defaultHeartBeatState) + { + this.defaultHbState = defaultHeartBeatState; + this.enabled = defaultHeartBeatState; + } public void setHbDataSenderService(HBDataSenderService hbDataSenderService) { @@ -72,9 +80,21 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService } @Override - public boolean isHBEnabled() + public boolean getDefaultHbState() + { + return defaultHbState; + } + + @Override + public boolean isHbEnabled() { return enabled; } + @Override + public void setHbEnabled(boolean enabled) + { + this.enabled = enabled; + } + } diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java index 853c8539b2..673c9c1bb1 100644 --- a/src/main/java/org/alfresco/heartbeat/HeartBeat.java +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -1,296 +1,285 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco 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 3 of the License, or - * (at your option) any later version. - * - * Alfresco 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 Alfresco. If not, see . - * #L% - */ -package org.alfresco.heartbeat; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.util.Date; - -import org.alfresco.service.cmr.repository.HBDataCollectorService; -import org.alfresco.service.license.LicenseDescriptor; -import org.alfresco.service.license.LicenseService; -import org.alfresco.service.license.LicenseService.LicenseChangeHandler; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.quartz.Job; -import org.quartz.JobDataMap; -import org.quartz.JobDetail; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; -import org.quartz.Scheduler; -import org.quartz.SchedulerException; -import org.quartz.SimpleTrigger; -import org.quartz.Trigger; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.context.ApplicationContext; - -/** - * This class communicates some very basic repository statistics to Alfresco on a regular basis. - * - * @author dward - */ -public class HeartBeat implements LicenseChangeHandler -{ - - private static final String LAMBDA_INGEST_URL = "https://0s910f9ijc.execute-api.eu-west-1.amazonaws.com/Stage/ingest"; - - /** The default enable state */ - private static final boolean DEFAULT_HEARTBEAT_ENABLED = true; - - /** The logger. */ - private static final Log logger = LogFactory.getLog(HeartBeat.class); - - private LicenseService licenseService; - - private Scheduler scheduler; - - /** URL to post heartbeat to. */ - private String heartBeatUrl; - - private boolean testMode = true; - - private final String JOB_NAME = "heartbeat"; - - /** Is the heartbeat enabled */ - private boolean enabled = DEFAULT_HEARTBEAT_ENABLED; - - private HBDataCollectorService dataCollectorService; - - - - /** - * Initialises the heart beat service. Note that dependencies are intentionally 'pulled' rather than injected - * because we don't want these to be reconfigured. - * - * @param context - * the context - */ - public HeartBeat(final ApplicationContext context) - { - this(context, true); - } - - /** - * Initialises the heart beat service, potentially in test mode. Note that dependencies are intentionally 'pulled' - * rather than injected because we don't want these to be reconfigured. - * - * -@param context - * the context - * -@param testMode - * are we running in test mode? If so we send data to local port 9999 rather than an alfresco server. We - * also use a special test encryption certificate and ping on a more frequent basis. - */ - public HeartBeat(final ApplicationContext context, final Boolean testModel) - { - logger.debug("Initialising HeartBeat"); - - - // I think these should be wired by spring instead for proper ioc.. - this.dataCollectorService = (HBDataCollectorService) context.getBean("hbDataCollectorService"); - this.scheduler = (Scheduler) context.getBean("schedulerFactory"); - - this.testMode = testModel; - - try - { - LicenseService licenseService = null; - try - { - licenseService = (LicenseService) context.getBean("licenseService"); - licenseService.registerOnLicenseChange(this); - } - catch (NoSuchBeanDefinitionException e) - { - logger.error("licenseService not found", e); - } - this.licenseService = licenseService; - - // We force the job to be scheduled regardless of the potential state of the licenses - scheduleJob(); - } - catch (final RuntimeException e) - { - throw e; - } - catch (final Exception e) - { - throw new RuntimeException(e); - } - } - - private synchronized void setHeartBeatUrl(String heartBeatUrl) - { - this.heartBeatUrl = heartBeatUrl; - } - - // Determine the URL to send the heartbeat to from the license if not set - private synchronized String getHeartBeatUrl() - { - if (heartBeatUrl == null) - { - // GC: Ignore the standard heartbeat URL and always use the AWS/Lambda URL -// LicenseDescriptor licenseDescriptor = licenseService.getLicense(); -// String url = (licenseDescriptor == null) ? null : licenseDescriptor.getHeartBeatUrl(); -// setHeartBeatUrl(url == null ? HeartBeat.DEFAULT_URL : url); - setHeartBeatUrl(LAMBDA_INGEST_URL); - } - - logger.debug("Returning heartBeatUrl: " + heartBeatUrl); - - return heartBeatUrl; - } - - /** - * @return true if the heartbeat is currently enabled - */ - public synchronized boolean isEnabled() - { - return enabled; - } - - - - /** - * Sends encrypted data over HTTP. - * - * @throws IOException - * Signals that an I/O exception has occurred. - * @throws GeneralSecurityException - * an encryption related exception - */ - public void collectAndSendData() throws IOException, GeneralSecurityException - { - this.dataCollectorService.collectAndSendData(); - } - - /** - * Listens for license changes. If a license is change or removed, the heartbeat job is rescheduled. - */ - public synchronized void onLicenseChange(LicenseDescriptor licenseDescriptor) - { - logger.debug("Update license called"); - - setHeartBeatUrl(licenseDescriptor.getHeartBeatUrl()); - boolean newEnabled = !licenseDescriptor.isHeartBeatDisabled(); - - if (newEnabled != enabled) - { - logger.debug("State change of heartbeat"); - this.enabled = newEnabled; - try - { - scheduleJob(); - } - catch (Exception e) - { - logger.error("Unable to schedule heart beat", e); - } - } - } - - /** - * License load failure resets the heartbeat back to the default state - */ - @Override - public synchronized void onLicenseFail() - { - boolean newEnabled = DEFAULT_HEARTBEAT_ENABLED; - - if (newEnabled != enabled) - { - logger.debug("State change of heartbeat"); - this.enabled = newEnabled; - try - { - scheduleJob(); - } - catch (Exception e) - { - logger.error("Unable to schedule heart beat", e); - } - } - } - - /** - * Start or stop the hertbeat job depending on whether the heartbeat is enabled or not - * @throws SchedulerException - */ - private synchronized void scheduleJob() throws SchedulerException - { - // Schedule the heart beat to run regularly - if(enabled) - { - logger.debug("heartbeat job scheduled"); - final JobDetail jobDetail = new JobDetail(JOB_NAME, Scheduler.DEFAULT_GROUP, HeartBeatJob.class); - jobDetail.getJobDataMap().put("heartBeat", this); - // Ensure the job wasn't already scheduled in an earlier retry of this transaction - final String triggerName = JOB_NAME + "Trigger"; - scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); - final Trigger trigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, new Date(), null, - //SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 4 * 60 * 60 * 1000); - SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 2 * 60 * 1000); - scheduler.scheduleJob(jobDetail, trigger); - } - else - { - logger.debug("heartbeat job unscheduled"); - final String triggerName = JOB_NAME + "Trigger"; - scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); - } - } - - /** - * The scheduler job responsible for triggering a heartbeat on a regular basis. - */ - public static class HeartBeatJob implements Job - { - public void execute(final JobExecutionContext jobexecutioncontext) throws JobExecutionException - { - final JobDataMap dataMap = jobexecutioncontext.getJobDetail().getJobDataMap(); - final HeartBeat heartBeat = (HeartBeat) dataMap.get("heartBeat"); - try - { - heartBeat.collectAndSendData(); - } - catch (final Exception e) - { - if (logger.isDebugEnabled()) - { - // Verbose logging - HeartBeat.logger.debug("Heartbeat job failure", e); - } - else - { - // Heartbeat errors are non-fatal and will show as single line warnings - HeartBeat.logger.warn(e.toString()); - throw new JobExecutionException(e); - } - } - } - } - - -} +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Date; + +import org.alfresco.service.cmr.repository.HBDataCollectorService; +import org.alfresco.service.license.LicenseDescriptor; +import org.alfresco.service.license.LicenseService; +import org.alfresco.service.license.LicenseService.LicenseChangeHandler; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.quartz.Job; +import org.quartz.JobDataMap; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SimpleTrigger; +import org.quartz.Trigger; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; + +/** + * This class communicates some very basic repository statistics to Alfresco on a regular basis. + * + * @author dward + */ +public class HeartBeat implements LicenseChangeHandler +{ + + /** The logger. */ + private static final Log logger = LogFactory.getLog(HeartBeat.class); + + private LicenseService licenseService; + + private Scheduler scheduler; + + private boolean testMode = true; + + private final String JOB_NAME = "heartbeat"; + + private HBDataCollectorService dataCollectorService; + + + + /** + * Initialises the heart beat service. Note that dependencies are intentionally 'pulled' rather than injected + * because we don't want these to be reconfigured. + * + * @param context + * the context + */ + public HeartBeat(final ApplicationContext context) + { + this(context, true); + } + + /** + * Initialises the heart beat service, potentially in test mode. Note that dependencies are intentionally 'pulled' + * rather than injected because we don't want these to be reconfigured. + * + * -@param context + * the context + * -@param testMode + * are we running in test mode? If so we send data to local port 9999 rather than an alfresco server. We + * also use a special test encryption certificate and ping on a more frequent basis. + */ + public HeartBeat(final ApplicationContext context, final Boolean testModel) + { + logger.debug("Initialising HeartBeat"); + + + // I think these should be wired by spring instead for proper ioc.. + this.dataCollectorService = (HBDataCollectorService) context.getBean("hbDataCollectorService"); + this.scheduler = (Scheduler) context.getBean("schedulerFactory"); + + this.testMode = testModel; + + try + { + LicenseService licenseService = null; + try + { + licenseService = (LicenseService) context.getBean("licenseService"); + licenseService.registerOnLicenseChange(this); + } + catch (NoSuchBeanDefinitionException e) + { + logger.error("licenseService not found", e); + } + this.licenseService = licenseService; + + // We force the job to be scheduled regardless of the potential state of the licenses + scheduleJob(); + } + catch (final RuntimeException e) + { + throw e; + } + catch (final Exception e) + { + throw new RuntimeException(e); + } + } + +// private synchronized void setHeartBeatUrl(String heartBeatUrl) +// { +// this.heartBeatUrl = heartBeatUrl; +// } +// +// // Determine the URL to send the heartbeat to from the license if not set +// private synchronized String getHeartBeatUrl() +// { +// if (heartBeatUrl == null) +// { +// // GC: Ignore the standard heartbeat URL and always use the AWS/Lambda URL +//// LicenseDescriptor licenseDescriptor = licenseService.getLicense(); +//// String url = (licenseDescriptor == null) ? null : licenseDescriptor.getHeartBeatUrl(); +//// setHeartBeatUrl(url == null ? HeartBeat.DEFAULT_URL : url); +// setHeartBeatUrl(LAMBDA_INGEST_URL); +// } +// +// logger.debug("Returning heartBeatUrl: " + heartBeatUrl); +// +// return heartBeatUrl; +// } + + /** + * @return true if the heartbeat is currently enabled + */ + public synchronized boolean isEnabled() + { + return dataCollectorService.isHbEnabled(); + } + + + + /** + * Sends encrypted data over HTTP. + * + * @throws IOException + * Signals that an I/O exception has occurred. + * @throws GeneralSecurityException + * an encryption related exception + */ + public void collectAndSendData() throws IOException, GeneralSecurityException + { + this.dataCollectorService.collectAndSendData(); + } + + /** + * Listens for license changes. If a license is change or removed, the heartbeat job is rescheduled. + */ + public synchronized void onLicenseChange(LicenseDescriptor licenseDescriptor) + { + logger.debug("Update license called"); + + //setHeartBeatUrl(licenseDescriptor.getHeartBeatUrl()); + boolean newEnabled = !licenseDescriptor.isHeartBeatDisabled(); + + if (newEnabled != dataCollectorService.isHbEnabled()) + { + logger.debug("State change of heartbeat"); + dataCollectorService.setHbEnabled(newEnabled); + try + { + scheduleJob(); + } + catch (Exception e) + { + logger.error("Unable to schedule heart beat", e); + } + } + } + + /** + * License load failure resets the heartbeat back to the default state + */ + @Override + public synchronized void onLicenseFail() + { + boolean newEnabled = dataCollectorService.getDefaultHbState(); + + if (newEnabled != dataCollectorService.isHbEnabled()) + { + logger.debug("State change of heartbeat"); + dataCollectorService.setHbEnabled(newEnabled); + try + { + scheduleJob(); + } + catch (Exception e) + { + logger.error("Unable to schedule heart beat", e); + } + } + } + + /** + * Start or stop the hertbeat job depending on whether the heartbeat is enabled or not + * @throws SchedulerException + */ + private synchronized void scheduleJob() throws SchedulerException + { + // Schedule the heart beat to run regularly + if(dataCollectorService.isHbEnabled()) + { + logger.debug("heartbeat job scheduled"); + final JobDetail jobDetail = new JobDetail(JOB_NAME, Scheduler.DEFAULT_GROUP, HeartBeatJob.class); + jobDetail.getJobDataMap().put("heartBeat", this); + // Ensure the job wasn't already scheduled in an earlier retry of this transaction + final String triggerName = JOB_NAME + "Trigger"; + scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); + final Trigger trigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, new Date(), null, + //SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 4 * 60 * 60 * 1000); + SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 2 * 60 * 1000); + scheduler.scheduleJob(jobDetail, trigger); + } + else + { + logger.debug("heartbeat job unscheduled"); + final String triggerName = JOB_NAME + "Trigger"; + scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); + } + } + + /** + * The scheduler job responsible for triggering a heartbeat on a regular basis. + */ + public static class HeartBeatJob implements Job + { + public void execute(final JobExecutionContext jobexecutioncontext) throws JobExecutionException + { + final JobDataMap dataMap = jobexecutioncontext.getJobDetail().getJobDataMap(); + final HeartBeat heartBeat = (HeartBeat) dataMap.get("heartBeat"); + try + { + heartBeat.collectAndSendData(); + } + catch (final Exception e) + { + if (logger.isDebugEnabled()) + { + // Verbose logging + HeartBeat.logger.debug("Heartbeat job failure", e); + } + else + { + // Heartbeat errors are non-fatal and will show as single line warnings + HeartBeat.logger.warn(e.toString()); + throw new JobExecutionException(e); + } + } + } + } + + +} diff --git a/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java b/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java index a61eb257b1..26d57e9a6a 100644 --- a/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java +++ b/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java @@ -33,7 +33,11 @@ public interface HBDataCollectorService void collectAndSendData(); - boolean isHBEnabled(); + boolean isHbEnabled(); + + void setHbEnabled(boolean enabled); + + boolean getDefaultHbState(); } diff --git a/src/main/resources/alfresco/heartbeat-context.xml b/src/main/resources/alfresco/heartbeat-context.xml index dd63dfed9a..69e22e034f 100644 --- a/src/main/resources/alfresco/heartbeat-context.xml +++ b/src/main/resources/alfresco/heartbeat-context.xml @@ -1,29 +1,31 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/alfresco/repository.properties b/src/main/resources/alfresco/repository.properties index 1af3bf8546..e21f203bd9 100644 --- a/src/main/resources/alfresco/repository.properties +++ b/src/main/resources/alfresco/repository.properties @@ -1242,3 +1242,7 @@ system.email.sender.default=noreply@alfresco.com # reset password workflow will expire in an hour system.reset-password.endTimer=PT1H system.reset-password.sendEmailAsynchronously=true + +# HeartBeat +heartbeat.enabled=false +heartbeat.target.url=heartbeat.alfresco.com From c18d4cb4e65760cefbbd9d226cc593e18ec0d53c Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 01:55:56 +0300 Subject: [PATCH 06/21] (Erik Knizat) REPO-2853 Heartbeat: Move the Heartbeat class to Community and cleanup legacy code * Delete unused heartbeatpublic.keystore * Rename CommunityHBDataCollector.java to RepositoryDataCollector.java as per code review * Removed licence related data from RepositoryDataCollector.java * Remove unused commented out methods * Synchronise accessors for hb enabled flag --- .../heartbeat/HBDataCollectorServiceImpl.java | 4 +- .../org/alfresco/heartbeat/HeartBeat.java | 22 -- .../heartbeat/RepositoryDataCollector.java | 284 ++++++++++++++++++ .../resources/alfresco/heartbeat-context.xml | 4 +- 4 files changed, 288 insertions(+), 26 deletions(-) create mode 100644 src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index d2612d0cc5..2c2f934077 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -86,13 +86,13 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService } @Override - public boolean isHbEnabled() + public synchronized boolean isHbEnabled() { return enabled; } @Override - public void setHbEnabled(boolean enabled) + public synchronized void setHbEnabled(boolean enabled) { this.enabled = enabled; } diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java index 673c9c1bb1..891b8bbf32 100644 --- a/src/main/java/org/alfresco/heartbeat/HeartBeat.java +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -130,27 +130,6 @@ public class HeartBeat implements LicenseChangeHandler } } -// private synchronized void setHeartBeatUrl(String heartBeatUrl) -// { -// this.heartBeatUrl = heartBeatUrl; -// } -// -// // Determine the URL to send the heartbeat to from the license if not set -// private synchronized String getHeartBeatUrl() -// { -// if (heartBeatUrl == null) -// { -// // GC: Ignore the standard heartbeat URL and always use the AWS/Lambda URL -//// LicenseDescriptor licenseDescriptor = licenseService.getLicense(); -//// String url = (licenseDescriptor == null) ? null : licenseDescriptor.getHeartBeatUrl(); -//// setHeartBeatUrl(url == null ? HeartBeat.DEFAULT_URL : url); -// setHeartBeatUrl(LAMBDA_INGEST_URL); -// } -// -// logger.debug("Returning heartBeatUrl: " + heartBeatUrl); -// -// return heartBeatUrl; -// } /** * @return true if the heartbeat is currently enabled @@ -182,7 +161,6 @@ public class HeartBeat implements LicenseChangeHandler { logger.debug("Update license called"); - //setHeartBeatUrl(licenseDescriptor.getHeartBeatUrl()); boolean newEnabled = !licenseDescriptor.isHeartBeatDisabled(); if (newEnabled != dataCollectorService.isHbEnabled()) diff --git a/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java b/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java new file mode 100644 index 0000000000..0fc06cf75b --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java @@ -0,0 +1,284 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2017 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +import org.alfresco.heartbeat.datasender.HBData; +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.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.extensions.surf.util.Base64; + +public class RepositoryDataCollector extends HBBaseDataCollector +{ + + /** The logger. */ + private static final Log logger = LogFactory.getLog(RepositoryDataCollector.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; + + /** 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() + { + List collectedData = new LinkedList<>(); + + RetryingTransactionHelper.RetryingTransactionCallback initCallback = new RetryingTransactionHelper.RetryingTransactionCallback() + { + @Override + public Void execute() throws Throwable + { + lazyInit(); + return null; + } + }; + transactionService.getRetryingTransactionHelper().doInTransaction(initCallback, true); + + // 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", + new Date(), + 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", + new Date(), + 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", + new Date(), + modelUsageValues); + collectedData.add(modelUsageData); + + 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/resources/alfresco/heartbeat-context.xml b/src/main/resources/alfresco/heartbeat-context.xml index 69e22e034f..e106777a33 100644 --- a/src/main/resources/alfresco/heartbeat-context.xml +++ b/src/main/resources/alfresco/heartbeat-context.xml @@ -18,8 +18,8 @@ - - + + From 70a9a2dae39104a0fd5adff208459e525836267b Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Wed, 6 Sep 2017 13:09:15 +0100 Subject: [PATCH 07/21] REPO-2853: Clean up * Fix formatting * Add javadoc * Remove unused imports * Remove unused Heartbeat.isEnabled() --- .../heartbeat/HBDataCollectorServiceImpl.java | 25 ++++++++++++++-- .../org/alfresco/heartbeat/HeartBeat.java | 30 ++++--------------- .../heartbeat/RepositoryDataCollector.java | 3 -- .../descriptor/DescriptorServiceImpl.java | 2 -- 4 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index 2c2f934077..08332d6ceb 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -27,7 +27,6 @@ package org.alfresco.heartbeat; import java.util.LinkedList; import java.util.List; - import org.alfresco.heartbeat.datasender.HBData; import org.alfresco.heartbeat.datasender.HBDataSenderService; import org.alfresco.service.cmr.repository.HBDataCollectorService; @@ -39,12 +38,23 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService /** The logger. */ private static final Log logger = LogFactory.getLog(HBDataCollectorServiceImpl.class); + /** List of collectors registered with this service */ private List collectors = new LinkedList<>(); + + /** The service responsible for sending the collected data */ private HBDataSenderService hbDataSenderService; + + /** Current enabled state */ private boolean enabled = false; + /** The default enable state */ private final boolean defaultHbState; + /** + * + * @param defaultHeartBeatState the default enabled state of heartbeat + * + */ public HBDataCollectorServiceImpl (boolean defaultHeartBeatState) { this.defaultHbState = defaultHeartBeatState; @@ -56,12 +66,22 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService this.hbDataSenderService = hbDataSenderService; } + /** + * + * Register data collector with this service. + * The registered collectors will be called to provide heartbeat data. + * + * @param collector collector to register + */ @Override public void registerCollector(HBBaseDataCollector collector) { this.collectors.add(collector); } + /** + * Collects and sends data for all registered collectors using the provided sender service. + */ @Override public void collectAndSendData() { @@ -74,7 +94,8 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService } catch (Exception e) { - // log exception; + // Log exception + logger.error(e); } } } diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java index 891b8bbf32..88468fa896 100644 --- a/src/main/java/org/alfresco/heartbeat/HeartBeat.java +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -49,8 +49,9 @@ import org.springframework.context.ApplicationContext; /** * This class communicates some very basic repository statistics to Alfresco on a regular basis. + * The class is responsible for scheduling the HeartBeat job and reacting to licence change events. * - * @author dward + * @author dward, eknizat */ public class HeartBeat implements LicenseChangeHandler { @@ -68,8 +69,6 @@ public class HeartBeat implements LicenseChangeHandler private HBDataCollectorService dataCollectorService; - - /** * Initialises the heart beat service. Note that dependencies are intentionally 'pulled' rather than injected * because we don't want these to be reconfigured. @@ -79,7 +78,7 @@ public class HeartBeat implements LicenseChangeHandler */ public HeartBeat(final ApplicationContext context) { - this(context, true); + this(context, false); } /** @@ -96,8 +95,6 @@ public class HeartBeat implements LicenseChangeHandler { logger.debug("Initialising HeartBeat"); - - // I think these should be wired by spring instead for proper ioc.. this.dataCollectorService = (HBDataCollectorService) context.getBean("hbDataCollectorService"); this.scheduler = (Scheduler) context.getBean("schedulerFactory"); @@ -130,26 +127,11 @@ public class HeartBeat implements LicenseChangeHandler } } - /** - * @return true if the heartbeat is currently enabled - */ - public synchronized boolean isEnabled() - { - return dataCollectorService.isHbEnabled(); - } - - - - /** - * Sends encrypted data over HTTP. + * Delegates data collection and sending to HBDataCollectorService. * - * @throws IOException - * Signals that an I/O exception has occurred. - * @throws GeneralSecurityException - * an encryption related exception */ - public void collectAndSendData() throws IOException, GeneralSecurityException + public void collectAndSendData() { this.dataCollectorService.collectAndSendData(); } @@ -258,6 +240,4 @@ public class HeartBeat implements LicenseChangeHandler } } } - - } diff --git a/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java b/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java index 0fc06cf75b..4fc7e02d05 100644 --- a/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java +++ b/src/main/java/org/alfresco/heartbeat/RepositoryDataCollector.java @@ -36,7 +36,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.TreeMap; - import org.alfresco.heartbeat.datasender.HBData; import org.alfresco.repo.descriptor.DescriptorDAO; import org.alfresco.repo.dictionary.CustomModelsInfo; @@ -47,11 +46,9 @@ import org.alfresco.service.cmr.dictionary.CustomModelService; 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.extensions.surf.util.Base64; public class RepositoryDataCollector extends HBBaseDataCollector { diff --git a/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java b/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java index 7eeb1a21b1..8e519835b0 100644 --- a/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java +++ b/src/main/java/org/alfresco/repo/descriptor/DescriptorServiceImpl.java @@ -29,7 +29,6 @@ import java.io.InputStream; import java.lang.reflect.Constructor; import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.heartbeat.HBBaseDataCollector; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.transaction.RetryingTransactionHelper; @@ -38,7 +37,6 @@ import org.alfresco.repo.usage.RepoUsageComponent; import org.alfresco.service.cmr.admin.RepoUsage; import org.alfresco.service.cmr.admin.RepoUsage.LicenseMode; import org.alfresco.service.cmr.admin.RepoUsage.UsageType; -import org.alfresco.service.cmr.repository.HBDataCollectorService; import org.alfresco.service.descriptor.Descriptor; import org.alfresco.service.descriptor.DescriptorService; import org.alfresco.service.license.LicenseDescriptor; From ccaeda45dc016fc4e3fc747fcf0d03716e85e150 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 02:01:40 +0300 Subject: [PATCH 08/21] REPO-2625 / REPO-2854: Update HBDataSenderService definition --- .../heartbeat/HBDataCollectorServiceImpl.java | 4 ++ .../heartbeat/HBDataSenderServiceFactory.java | 57 +++++++++++++++++++ .../org/alfresco/heartbeat/HeartBeat.java | 42 +++++++++----- .../resources/alfresco/heartbeat-context.xml | 11 +++- 4 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 src/main/java/org/alfresco/heartbeat/HBDataSenderServiceFactory.java diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index 08332d6ceb..5a00916ff9 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -27,7 +27,9 @@ package org.alfresco.heartbeat; import java.util.LinkedList; import java.util.List; + import org.alfresco.heartbeat.datasender.HBData; +import org.alfresco.heartbeat.datasender.HBDataSenderServiceBuilder; import org.alfresco.heartbeat.datasender.HBDataSenderService; import org.alfresco.service.cmr.repository.HBDataCollectorService; import org.apache.commons.logging.Log; @@ -116,6 +118,8 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService public synchronized void setHbEnabled(boolean enabled) { this.enabled = enabled; + + this.hbDataSenderService = HBDataSenderServiceBuilder.builder().enable(enabled).update(hbDataSenderService); } } diff --git a/src/main/java/org/alfresco/heartbeat/HBDataSenderServiceFactory.java b/src/main/java/org/alfresco/heartbeat/HBDataSenderServiceFactory.java new file mode 100644 index 0000000000..bae13bd5ec --- /dev/null +++ b/src/main/java/org/alfresco/heartbeat/HBDataSenderServiceFactory.java @@ -0,0 +1,57 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.alfresco.heartbeat.datasender.HBDataSenderServiceBuilder; +import org.alfresco.heartbeat.datasender.HBDataSenderService; + +/** + * @author Ancuta Morarasu + * + */ +public class HBDataSenderServiceFactory +{ + private String target; + private boolean heartbeatEnabled; + + public void setTarget(String target) + { + this.target = target; + } + + public void setHeartbeatEnabled(boolean heartbeatEnabled) + { + this.heartbeatEnabled = heartbeatEnabled; + } + + public HBDataSenderService createInstance() + { + return HBDataSenderServiceBuilder.builder() + .withHeartbeatURL(target) + .enable(heartbeatEnabled) + .build(); + } +} diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java index 88468fa896..35b6ca16bf 100644 --- a/src/main/java/org/alfresco/heartbeat/HeartBeat.java +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -25,8 +25,6 @@ */ package org.alfresco.heartbeat; -import java.io.IOException; -import java.security.GeneralSecurityException; import java.util.Date; import org.alfresco.service.cmr.repository.HBDataCollectorService; @@ -56,7 +54,7 @@ import org.springframework.context.ApplicationContext; public class HeartBeat implements LicenseChangeHandler { - /** The logger. */ + /** The logger */ private static final Log logger = LogFactory.getLog(HeartBeat.class); private LicenseService licenseService; @@ -91,14 +89,17 @@ public class HeartBeat implements LicenseChangeHandler * are we running in test mode? If so we send data to local port 9999 rather than an alfresco server. We * also use a special test encryption certificate and ping on a more frequent basis. */ - public HeartBeat(final ApplicationContext context, final Boolean testModel) + public HeartBeat(final ApplicationContext context, final Boolean testMode) { - logger.debug("Initialising HeartBeat"); + if (logger.isDebugEnabled()) + { + logger.debug("Initialising HeartBeat"); + } this.dataCollectorService = (HBDataCollectorService) context.getBean("hbDataCollectorService"); this.scheduler = (Scheduler) context.getBean("schedulerFactory"); - this.testMode = testModel; + this.testMode = testMode; try { @@ -141,13 +142,19 @@ public class HeartBeat implements LicenseChangeHandler */ public synchronized void onLicenseChange(LicenseDescriptor licenseDescriptor) { - logger.debug("Update license called"); + if (logger.isDebugEnabled()) + { + logger.debug("Update license called"); + } boolean newEnabled = !licenseDescriptor.isHeartBeatDisabled(); if (newEnabled != dataCollectorService.isHbEnabled()) { - logger.debug("State change of heartbeat"); + if (logger.isDebugEnabled()) + { + logger.debug("State change of heartbeat"); + } dataCollectorService.setHbEnabled(newEnabled); try { @@ -170,7 +177,10 @@ public class HeartBeat implements LicenseChangeHandler if (newEnabled != dataCollectorService.isHbEnabled()) { - logger.debug("State change of heartbeat"); + if (logger.isDebugEnabled()) + { + logger.debug("State change of heartbeat"); + } dataCollectorService.setHbEnabled(newEnabled); try { @@ -190,13 +200,17 @@ public class HeartBeat implements LicenseChangeHandler private synchronized void scheduleJob() throws SchedulerException { // Schedule the heart beat to run regularly + final String triggerName = JOB_NAME + "Trigger"; if(dataCollectorService.isHbEnabled()) { - logger.debug("heartbeat job scheduled"); + if (logger.isDebugEnabled()) + { + logger.debug("heartbeat job scheduled"); + } final JobDetail jobDetail = new JobDetail(JOB_NAME, Scheduler.DEFAULT_GROUP, HeartBeatJob.class); jobDetail.getJobDataMap().put("heartBeat", this); + // Ensure the job wasn't already scheduled in an earlier retry of this transaction - final String triggerName = JOB_NAME + "Trigger"; scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); final Trigger trigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, new Date(), null, //SimpleTrigger.REPEAT_INDEFINITELY, testMode ? 1000 : 4 * 60 * 60 * 1000); @@ -205,8 +219,10 @@ public class HeartBeat implements LicenseChangeHandler } else { - logger.debug("heartbeat job unscheduled"); - final String triggerName = JOB_NAME + "Trigger"; + if (logger.isDebugEnabled()) + { + logger.debug("heartbeat job unscheduled"); + } scheduler.unscheduleJob(triggerName, Scheduler.DEFAULT_GROUP); } } diff --git a/src/main/resources/alfresco/heartbeat-context.xml b/src/main/resources/alfresco/heartbeat-context.xml index e106777a33..701df9a1dd 100644 --- a/src/main/resources/alfresco/heartbeat-context.xml +++ b/src/main/resources/alfresco/heartbeat-context.xml @@ -3,9 +3,14 @@ - - - + + + + + + + + From 6d4510043d28227fd0e9e7e9eed04fb3ffa80d53 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Mon, 11 Sep 2017 12:16:21 +0300 Subject: [PATCH 09/21] REPO-2625 / REPO-2626: Use of the heartbeat data sender. --- .../org/alfresco/heartbeat/HBDataCollectorServiceImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index 5a00916ff9..b9b32619e6 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -29,7 +29,6 @@ import java.util.LinkedList; import java.util.List; import org.alfresco.heartbeat.datasender.HBData; -import org.alfresco.heartbeat.datasender.HBDataSenderServiceBuilder; import org.alfresco.heartbeat.datasender.HBDataSenderService; import org.alfresco.service.cmr.repository.HBDataCollectorService; import org.apache.commons.logging.Log; @@ -119,7 +118,7 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService { this.enabled = enabled; - this.hbDataSenderService = HBDataSenderServiceBuilder.builder().enable(enabled).update(hbDataSenderService); + this.hbDataSenderService.enable(enabled); } } From a1dfc6fafeb5408fe9626156c8f91021a87b7422 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 02:16:43 +0300 Subject: [PATCH 10/21] REPO-2626 / REPO-2878: Cleanup after merge from /repo - feature/REPO-2614_send_legacy_hb_data --- pom.xml | 5 + .../heartbeat/CommunityHBDataCollector.java | 322 ------------------ .../java/org/alfresco/heartbeat/HBData.java | 169 --------- 3 files changed, 5 insertions(+), 491 deletions(-) delete mode 100644 src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java delete mode 100644 src/main/java/org/alfresco/heartbeat/HBData.java diff --git a/pom.xml b/pom.xml index 7154d23935..89a589bc11 100644 --- a/pom.xml +++ b/pom.xml @@ -96,6 +96,11 @@ alfresco-events 1.2.5 + + org.alfresco + alfresco-heartbeat-data-sender + 1.0.0-SNAPSHOT + com.sun.mail javax.mail diff --git a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java b/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java deleted file mode 100644 index f133546798..0000000000 --- a/src/main/java/org/alfresco/heartbeat/CommunityHBDataCollector.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2017 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco 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 3 of the License, or - * (at your option) any later version. - * - * Alfresco 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 Alfresco. If not, see . - * #L% - */ -package org.alfresco.heartbeat; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.security.GeneralSecurityException; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import org.alfresco.heartbeat.datasender.HBData; -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.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.extensions.surf.util.Base64; - -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; - - /** 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() - { - List collectedData = new LinkedList<>(); - - RetryingTransactionHelper.RetryingTransactionCallback initCallback = new RetryingTransactionHelper.RetryingTransactionCallback() - { - @Override - public Void execute() throws Throwable - { - lazyInit(); - return null; - } - }; - transactionService.getRetryingTransactionHelper().doInTransaction(initCallback, true); - - // 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", - new Date(), - 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", - new Date(), - 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", - new Date(), - 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", - new Date(), - 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/HBData.java b/src/main/java/org/alfresco/heartbeat/HBData.java deleted file mode 100644 index dd7ea9f59f..0000000000 --- a/src/main/java/org/alfresco/heartbeat/HBData.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2017 Alfresco Software Limited - * %% - * This file is part of the Alfresco software. - * If the software was purchased under a paid Alfresco license, the terms of - * the paid license agreement will prevail. Otherwise, the software is - * provided under the following open source license terms: - * - * Alfresco 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 3 of the License, or - * (at your option) any later version. - * - * Alfresco 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 Alfresco. If not, see . - * #L% - */ -package org.alfresco.heartbeat; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TreeMap; - -/** - * Created by mmuller on 07/07/2017. - */ -public class HBData -{ - public static String SCHEMA_VERSION = "1.0"; - - public static String SCHEMA_VERSION_KEY = "sv"; - public static String SYSTEM_ID_KEY = "sId"; - public static String COLLECTOR_ID_KEY = "cId"; - public static String COLLECTOR_VERSION_KEY = "cv"; - public static String TIMESTAMP_KEY = "t"; - public static String DATA_KEY = "d"; - - private String systemId; - private String collectorId; - private String collectorVersion; - private String timestamp; - private Map data; - - public HBData(String systemId, String collectorId, String collectorVersion, String timestamp) - { - this.systemId = systemId; - this.collectorId = collectorId; - this.collectorVersion = collectorVersion; - this.timestamp = timestamp; - } - - public HBData(String systemId, String collectorId, String collectorVersion, String timestamp, Map data) - { - this.systemId = systemId; - this.collectorId = collectorId; - this.collectorVersion = collectorVersion; - this.timestamp = timestamp; - this.data = data; - } - - public JSONObject getJSONObject() throws JSONException - { - // save data collector properties - // The LinkedHashMap was choose only because for demoing - Map keyValues = new LinkedHashMap(); - keyValues.put(SCHEMA_VERSION_KEY, SCHEMA_VERSION); - keyValues.put(SYSTEM_ID_KEY, this.systemId); - keyValues.put(COLLECTOR_ID_KEY, this.collectorId); - keyValues.put(COLLECTOR_VERSION_KEY, this.collectorVersion); - keyValues.put(TIMESTAMP_KEY, this.timestamp); - - // save collected data - JSONObject jsonObject = new JSONObject(keyValues); - jsonObject.put(DATA_KEY, new JSONObject(this.data)); - return jsonObject; - } - - public String getSystemId() - { - return systemId; - } - - public void setSystemId(String systemId) - { - this.systemId = systemId; - } - - public String getCollectorId() - { - return collectorId; - } - - public void setCollectorId(String collectorId) - { - this.collectorId = collectorId; - } - - public String getCollectorVersion() - { - return collectorVersion; - } - - public void setCollectorVersion(String collectorVersion) - { - this.collectorVersion = collectorVersion; - } - - public String getTimestamp() - { - return timestamp; - } - - public void setTimestamp(String timestamp) - { - this.timestamp = timestamp; - } - - public Map getData() - { - return data; - } - - public void setData(Map data) - { - this.data = data; - } - - @Override - public String toString() - { - return "HBData(" + systemId + " " + collectorId + " " + collectorVersion + " " + timestamp +")"; - } - - public static void main(String[] args) throws JSONException - { - Map data = new TreeMap(); - data.put("k1","v1"); - data.put("k2",new Integer(2)); - data.put("k3","v3"); - - // ISO-8601 same as JavaScript toISOString() - String timeStamp = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.sss'Z'").format(new Date()); - - HBData collectorData = new HBData("99db325c-13c4-4b74-8d1d-f4800b345c89", - "acs.repository.test", - "1.0", - timeStamp); - - collectorData.setData(data); - - String jsonString = collectorData.getJSONObject().toString(); - System.out.println(":O "); - System.out.println(jsonString); - } - -} From dc66151ec08e58c0729bb4f887108096142e7c35 Mon Sep 17 00:00:00 2001 From: Ancuta Morarasu Date: Tue, 12 Sep 2017 17:26:00 +0300 Subject: [PATCH 11/21] REPO-2626: [Heartbeat] Set alfresco-hearbeat-data-sender version to 1.0.0. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 89a589bc11..f1290e53d2 100644 --- a/pom.xml +++ b/pom.xml @@ -99,7 +99,7 @@ org.alfresco alfresco-heartbeat-data-sender - 1.0.0-SNAPSHOT + 1.0.0 com.sun.mail From 789d216fd25b0f06d8c87471065f74f23538146f Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Tue, 12 Sep 2017 18:56:54 +0100 Subject: [PATCH 12/21] REPO-2850 Heartbeat: Add support for turning the data collection on/off based on the heartbeat.enabled global property * Move the enabled state from HBDataCollectorServiceImpl to HearBeat class as it is only modified there. --- .../heartbeat/HBDataCollectorServiceImpl.java | 16 ++---------- .../org/alfresco/heartbeat/HeartBeat.java | 25 ++++++++++++++----- .../repository/HBDataCollectorService.java | 6 ++--- 3 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java index b9b32619e6..b131178eea 100644 --- a/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java +++ b/src/main/java/org/alfresco/heartbeat/HBDataCollectorServiceImpl.java @@ -45,9 +45,6 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService /** The service responsible for sending the collected data */ private HBDataSenderService hbDataSenderService; - /** Current enabled state */ - private boolean enabled = false; - /** The default enable state */ private final boolean defaultHbState; @@ -59,7 +56,6 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService public HBDataCollectorServiceImpl (boolean defaultHeartBeatState) { this.defaultHbState = defaultHeartBeatState; - this.enabled = defaultHeartBeatState; } public void setHbDataSenderService(HBDataSenderService hbDataSenderService) @@ -102,22 +98,14 @@ public class HBDataCollectorServiceImpl implements HBDataCollectorService } @Override - public boolean getDefaultHbState() + public boolean isEnabledByDefault() { return defaultHbState; } @Override - public synchronized boolean isHbEnabled() + public synchronized void enabled(boolean enabled) { - return enabled; - } - - @Override - public synchronized void setHbEnabled(boolean enabled) - { - this.enabled = enabled; - this.hbDataSenderService.enable(enabled); } diff --git a/src/main/java/org/alfresco/heartbeat/HeartBeat.java b/src/main/java/org/alfresco/heartbeat/HeartBeat.java index 35b6ca16bf..57dee13dcc 100644 --- a/src/main/java/org/alfresco/heartbeat/HeartBeat.java +++ b/src/main/java/org/alfresco/heartbeat/HeartBeat.java @@ -67,6 +67,9 @@ public class HeartBeat implements LicenseChangeHandler private HBDataCollectorService dataCollectorService; + /** Current enabled state */ + private boolean enabled = false; + /** * Initialises the heart beat service. Note that dependencies are intentionally 'pulled' rather than injected * because we don't want these to be reconfigured. @@ -101,6 +104,8 @@ public class HeartBeat implements LicenseChangeHandler this.testMode = testMode; + this.enabled = dataCollectorService.isEnabledByDefault(); + try { LicenseService licenseService = null; @@ -128,6 +133,12 @@ public class HeartBeat implements LicenseChangeHandler } } + + public synchronized boolean isEnabled() + { + return this.enabled; + } + /** * Delegates data collection and sending to HBDataCollectorService. * @@ -149,13 +160,14 @@ public class HeartBeat implements LicenseChangeHandler boolean newEnabled = !licenseDescriptor.isHeartBeatDisabled(); - if (newEnabled != dataCollectorService.isHbEnabled()) + if (newEnabled != this.enabled) { if (logger.isDebugEnabled()) { logger.debug("State change of heartbeat"); } - dataCollectorService.setHbEnabled(newEnabled); + this.enabled = newEnabled; + dataCollectorService.enabled(newEnabled); try { scheduleJob(); @@ -173,15 +185,16 @@ public class HeartBeat implements LicenseChangeHandler @Override public synchronized void onLicenseFail() { - boolean newEnabled = dataCollectorService.getDefaultHbState(); + boolean newEnabled = dataCollectorService.isEnabledByDefault(); - if (newEnabled != dataCollectorService.isHbEnabled()) + if (newEnabled != this.enabled) { if (logger.isDebugEnabled()) { logger.debug("State change of heartbeat"); } - dataCollectorService.setHbEnabled(newEnabled); + this.enabled = newEnabled; + dataCollectorService.enabled(newEnabled); try { scheduleJob(); @@ -201,7 +214,7 @@ public class HeartBeat implements LicenseChangeHandler { // Schedule the heart beat to run regularly final String triggerName = JOB_NAME + "Trigger"; - if(dataCollectorService.isHbEnabled()) + if(this.enabled) { if (logger.isDebugEnabled()) { diff --git a/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java b/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java index 26d57e9a6a..95631c4b2f 100644 --- a/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java +++ b/src/main/java/org/alfresco/service/cmr/repository/HBDataCollectorService.java @@ -32,12 +32,10 @@ public interface HBDataCollectorService void registerCollector(HBBaseDataCollector collector); void collectAndSendData(); - - boolean isHbEnabled(); - void setHbEnabled(boolean enabled); + void enabled(boolean enabled); - boolean getDefaultHbState(); + boolean isEnabledByDefault(); } From c763a85b96c2e4b69264fccb7f9a2d5ccfe9543b Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Tue, 12 Sep 2017 19:04:29 +0100 Subject: [PATCH 13/21] REPO-2852 Heartbeat: Add junit tests for the new service and collectors * Add unit tests for HeartBeat, HBDataCollectorService --- .../HBDataCollectorServiceImplTest.java | 127 +++++++++ .../org/alfresco/heartbeat/HeartBeatTest.java | 255 ++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java create mode 100644 src/test/java/org/alfresco/heartbeat/HeartBeatTest.java diff --git a/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java b/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java new file mode 100644 index 0000000000..4462a1eccf --- /dev/null +++ b/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java @@ -0,0 +1,127 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.alfresco.heartbeat.datasender.HBData; +import org.alfresco.heartbeat.datasender.HBDataSenderService; +import org.alfresco.service.cmr.repository.HBDataCollectorService; +import org.junit.Before; +import org.junit.Test; +import java.util.Arrays; +import java.util.List; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.internal.verification.VerificationModeFactory.times; + +/** + * @author eknizat + */ +public class HBDataCollectorServiceImplTest { + + private HBDataCollectorServiceImpl dataCollectorService; + private HBDataSenderService mockDataSenderService; + + @Before + public void setUp(){ + mockDataSenderService = mock(HBDataSenderService.class); + dataCollectorService = new HBDataCollectorServiceImpl(true); + dataCollectorService.setHbDataSenderService(mockDataSenderService); + } + + + + @Test + public void testInitialEnabledEqualsDefaultState() + { + HBDataCollectorService dataCollectorService = new HBDataCollectorServiceImpl(true); + assertTrue(dataCollectorService.isEnabledByDefault()); + + dataCollectorService = new HBDataCollectorServiceImpl(false); + assertFalse(dataCollectorService.isEnabledByDefault()); + } + + + @Test + public void testHBDataSenderServiceEnabledChange() + { + dataCollectorService.enabled(false); + verify(mockDataSenderService).enable(false); + + dataCollectorService.enabled(true); + verify(mockDataSenderService).enable(true); + + } + + @Test + public void testCollectAndSendData() + { + + // Set up dummy collector 1 + HBData c1Data = new HBData("sys", "c1","1.0",null); + HBBaseDataCollector c1 = new DummyCollector(c1Data); + c1.setHbDataCollectorService(dataCollectorService); + c1.register(); + // Set up dummy collector 2 + HBData c2Data = new HBData("sys", "c2","1.0",null); + HBBaseDataCollector c2 = new DummyCollector(c2Data); + c2.setHbDataCollectorService(dataCollectorService); + c2.register(); + // Set up dummy collector 3 + HBData c3Data = new HBData("sys", "c3","1.0",null); + HBBaseDataCollector c3 = new DummyCollector(c3Data); + c3.setHbDataCollectorService(dataCollectorService); + c3.register(); + + // Check that the collector service collects data from registered collectors and passes the data to data sender service + dataCollectorService.collectAndSendData(); + + // Check data is passed for each collector + verify(mockDataSenderService, times(3)).sendData(any(List.class)); + verify(mockDataSenderService).sendData(c1.collectData()); + verify(mockDataSenderService).sendData(c2.collectData()); + verify(mockDataSenderService).sendData(c3.collectData()); + } + + + class DummyCollector extends HBBaseDataCollector + { + private HBData data; + + public DummyCollector (HBData testData) + { + this.data = testData; + } + + @Override + public List collectData() { + return Arrays.asList(data); + } + } + +} diff --git a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java new file mode 100644 index 0000000000..5b5cfa0d16 --- /dev/null +++ b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java @@ -0,0 +1,255 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.alfresco.heartbeat.datasender.HBDataSenderService; +import org.alfresco.service.cmr.repository.HBDataCollectorService; +import org.alfresco.service.license.LicenseDescriptor; +import org.alfresco.service.license.LicenseService; +import org.junit.Before; +import org.junit.Test; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.util.Arrays; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class HeartBeatTest +{ + + /** + * 1. Constructor + * - Check that licenseService.registerOnLicenseChange + * + * 2. Job scheduling + * - enabled + * - disabled + * - unschedule job + * - schedule already scheduled job (maybe not actually needed) + * + * 3. On licence chane + * + * 4. On licence fail + * + * 4. Test HB Job inner class + */ + + + private static final String[] CONFIG_LOCATIONS = new String[] {"alfresco/scheduler-core-context.xml", "org/alfresco/util/test-scheduled-jobs-context.xml"}; + private ApplicationContext context; + + LicenseService mockLicenseService; + HBDataSenderService mockDataSenderService; + HBDataCollectorService mockDataCollectorService; + + @Before + public void setUp(){ + + // New context with scheduler + context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS); + + // Add services to context + mockLicenseService = mock(LicenseService.class); + mockDataCollectorService = mock(HBDataCollectorService.class); + ((ConfigurableApplicationContext) context).getBeanFactory().registerSingleton("licenseService",mockLicenseService); + ((ConfigurableApplicationContext) context).getBeanFactory().registerSingleton("hbDataCollectorService",mockDataCollectorService); + + mockDataSenderService = mock(HBDataSenderService.class); + + } + + @Test + public void testHBRegistersWithLicenceService() + { + + HeartBeat heartbeat = new HeartBeat(context,false); + + // Check that HearBeat registers itself with the licence service + verify(mockLicenseService).registerOnLicenseChange(heartbeat); + } + + @Test + public void testJobSchedulingWhenEnabled() + { + + // Enable heartbeat in data collector service ( as if set in prop file) + when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); + + HeartBeat heartbeat = new HeartBeat(context,true); + + // Check that the job is scheduled when heartbeat is enabled + assertTrue("Job was not scheduled but HB is enabled", isJobScheduled()); + } + + + @Test + public void testJobSchedulingWhenDisabled() + { + + // Disable heartbeat in data collector service ( as if set in prop file) + when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); + + HeartBeat heartbeat = new HeartBeat(context,true); + + // Check that the job is scheduled when heartbeat is disabled + assertFalse("Job was scheduled but HB is disabled", isJobScheduled()); + + } + + + /** + * Heartbeat enabled by default but disabled in licence on onLicenseChange + */ + @Test + public void testOnLicenseChangeOverridesDefaultEnabled() + { + + // Enable heartbeat in data collector service ( as if set in prop file) + when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); + + HeartBeat heartbeat = new HeartBeat(context,true); + + // heartbeat disabled in licence + LicenseDescriptor mockLicenseDescriptor = mock(LicenseDescriptor.class); + when(mockLicenseDescriptor.isHeartBeatDisabled()).thenReturn(true); + + assertTrue(heartbeat.isEnabled()); + assertTrue("Job should be scheduled at this point.",isJobScheduled()); + + heartbeat.onLicenseChange(mockLicenseDescriptor); + + // Check heartbeat is disabled and job unscheduled + assertFalse(heartbeat.isEnabled()); + assertFalse("Job should be unscheduled.",isJobScheduled()); + + } + + /** + * heartbeat disabled by default but enabled in licence + */ + @Test + public void testOnLicenseChangeOverridesDefaultDisabled() + { + // Disable heartbeat in data collector service ( as if set in prop file) + when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); + + HeartBeat heartbeat = new HeartBeat(context,true); + + // heartbeat enabled in licence + LicenseDescriptor mockLicenseDescriptor = mock(LicenseDescriptor.class); + when(mockLicenseDescriptor.isHeartBeatDisabled()).thenReturn(false); + + assertFalse(heartbeat.isEnabled()); + assertFalse("Job should not be scheduled at this point.",isJobScheduled()); + + heartbeat.onLicenseChange(mockLicenseDescriptor); + + // Check heartbeat is disabled and job unscheduled + assertTrue(heartbeat.isEnabled()); + assertTrue("Job should be scheduled.",isJobScheduled()); + } + + + @Test + public void testOnLicenceFailRevertsToEnabled() + { + + // Enable heartbeat in data collector service ( as if set in prop file) + when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); + + HeartBeat heartbeat = new HeartBeat(context,true); + + // heartbeat disabled in licence + LicenseDescriptor mockLicenseDescriptor = mock(LicenseDescriptor.class); + when(mockLicenseDescriptor.isHeartBeatDisabled()).thenReturn(true); + heartbeat.onLicenseChange(mockLicenseDescriptor); + + assertFalse(heartbeat.isEnabled()); + assertFalse("Job should not be scheduled at this point.",isJobScheduled()); + + // Revert back to default state + heartbeat.onLicenseFail(); + + // Check heartbeat is disabled and job unscheduled + assertTrue(heartbeat.isEnabled()); + assertTrue("Job should be unscheduled.",isJobScheduled()); + + + } + + + @Test + public void testOnLicenceFailRevertsToDisabled() + { + + // Disable heartbeat in data collector service ( as if set in prop file) + when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); + + HeartBeat heartbeat = new HeartBeat(context,true); + + // heartbeat enabled in licence + LicenseDescriptor mockLicenseDescriptor = mock(LicenseDescriptor.class); + when(mockLicenseDescriptor.isHeartBeatDisabled()).thenReturn(false); + heartbeat.onLicenseChange(mockLicenseDescriptor); + + assertTrue(heartbeat.isEnabled()); + assertTrue("Job should be scheduled at this point.",isJobScheduled()); + + // Revert back to default state + heartbeat.onLicenseFail(); + + // Check heartbeat is disabled and job unscheduled + assertFalse(heartbeat.isEnabled()); + assertFalse("Job should be unscheduled.",isJobScheduled()); + + } + + + private boolean isJobScheduled() + { + Scheduler scheduler = (Scheduler) context.getBean("schedulerFactory"); + String[] jobs = {}; + try { + jobs = scheduler.getJobNames( Scheduler.DEFAULT_GROUP); + } catch (SchedulerException e) { + e.printStackTrace(); + fail("Exception before assertion."); + } + + return Arrays.asList(jobs).contains("heartbeat"); + } + +} From 5ebca10fa1c3d5374639ee3ecfad98c522408898 Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Tue, 12 Sep 2017 19:07:53 +0100 Subject: [PATCH 14/21] Format code --- .../HBDataCollectorServiceImplTest.java | 6 ++++-- .../org/alfresco/heartbeat/HeartBeatTest.java | 21 ++----------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java b/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java index 4462a1eccf..8d8098cb07 100644 --- a/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java +++ b/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java @@ -42,13 +42,15 @@ import static org.mockito.internal.verification.VerificationModeFactory.times; /** * @author eknizat */ -public class HBDataCollectorServiceImplTest { +public class HBDataCollectorServiceImplTest +{ private HBDataCollectorServiceImpl dataCollectorService; private HBDataSenderService mockDataSenderService; @Before - public void setUp(){ + public void setUp() + { mockDataSenderService = mock(HBDataSenderService.class); dataCollectorService = new HBDataCollectorServiceImpl(true); dataCollectorService.setHbDataSenderService(mockDataSenderService); diff --git a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java index 5b5cfa0d16..1f206089f8 100644 --- a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java +++ b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java @@ -42,7 +42,6 @@ import java.util.Arrays; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -50,23 +49,6 @@ import static org.mockito.Mockito.when; public class HeartBeatTest { - /** - * 1. Constructor - * - Check that licenseService.registerOnLicenseChange - * - * 2. Job scheduling - * - enabled - * - disabled - * - unschedule job - * - schedule already scheduled job (maybe not actually needed) - * - * 3. On licence chane - * - * 4. On licence fail - * - * 4. Test HB Job inner class - */ - private static final String[] CONFIG_LOCATIONS = new String[] {"alfresco/scheduler-core-context.xml", "org/alfresco/util/test-scheduled-jobs-context.xml"}; private ApplicationContext context; @@ -76,7 +58,8 @@ public class HeartBeatTest HBDataCollectorService mockDataCollectorService; @Before - public void setUp(){ + public void setUp() + { // New context with scheduler context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS); From 02a5b1b2fc57cf0f9d8abc03249fba55ba0bfddf Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Wed, 13 Sep 2017 17:08:30 +0100 Subject: [PATCH 15/21] Refactor code * Split heartbeat-context into 2 * Move new heartbeat-repo-collector-context out of application-context-core --- .../alfresco/application-context-core.xml | 2 +- .../application-context-highlevel.xml | 1 + .../{ => heartbeat}/heartbeat-context.xml | 10 ----- .../heartbeat-repo-collector-context.xml | 16 ++++++++ .../HBDataCollectorServiceImplTest.java | 2 - .../org/alfresco/heartbeat/HeartBeatTest.java | 37 ++++++------------- 6 files changed, 29 insertions(+), 39 deletions(-) rename src/main/resources/alfresco/{ => heartbeat}/heartbeat-context.xml (61%) create mode 100644 src/main/resources/alfresco/heartbeat/heartbeat-repo-collector-context.xml diff --git a/src/main/resources/alfresco/application-context-core.xml b/src/main/resources/alfresco/application-context-core.xml index c58b1c9749..259a181c03 100644 --- a/src/main/resources/alfresco/application-context-core.xml +++ b/src/main/resources/alfresco/application-context-core.xml @@ -52,5 +52,5 @@ - + diff --git a/src/main/resources/alfresco/application-context-highlevel.xml b/src/main/resources/alfresco/application-context-highlevel.xml index 8273b7ee91..a949204a9c 100644 --- a/src/main/resources/alfresco/application-context-highlevel.xml +++ b/src/main/resources/alfresco/application-context-highlevel.xml @@ -43,4 +43,5 @@ + diff --git a/src/main/resources/alfresco/heartbeat-context.xml b/src/main/resources/alfresco/heartbeat/heartbeat-context.xml similarity index 61% rename from src/main/resources/alfresco/heartbeat-context.xml rename to src/main/resources/alfresco/heartbeat/heartbeat-context.xml index 701df9a1dd..9c96d66bd4 100644 --- a/src/main/resources/alfresco/heartbeat-context.xml +++ b/src/main/resources/alfresco/heartbeat/heartbeat-context.xml @@ -23,14 +23,4 @@ - - - - - - - - - - diff --git a/src/main/resources/alfresco/heartbeat/heartbeat-repo-collector-context.xml b/src/main/resources/alfresco/heartbeat/heartbeat-repo-collector-context.xml new file mode 100644 index 0000000000..67ea957994 --- /dev/null +++ b/src/main/resources/alfresco/heartbeat/heartbeat-repo-collector-context.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java b/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java index 8d8098cb07..d658dc4a71 100644 --- a/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java +++ b/src/test/java/org/alfresco/heartbeat/HBDataCollectorServiceImplTest.java @@ -77,13 +77,11 @@ public class HBDataCollectorServiceImplTest dataCollectorService.enabled(true); verify(mockDataSenderService).enable(true); - } @Test public void testCollectAndSendData() { - // Set up dummy collector 1 HBData c1Data = new HBData("sys", "c1","1.0",null); HBBaseDataCollector c1 = new DummyCollector(c1Data); diff --git a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java index 1f206089f8..c7b908e818 100644 --- a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java +++ b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java @@ -36,9 +36,7 @@ import org.quartz.SchedulerException; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; - import java.util.Arrays; - import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -46,11 +44,15 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +/** + * @author eknizat + */ public class HeartBeatTest { - - private static final String[] CONFIG_LOCATIONS = new String[] {"alfresco/scheduler-core-context.xml", "org/alfresco/util/test-scheduled-jobs-context.xml"}; + private static final String[] CONFIG_LOCATIONS = new String[] { + "classpath:alfresco/scheduler-core-context.xml", + "classpath:org/alfresco/heartbeat/test-heartbeat-context.xml"}; private ApplicationContext context; LicenseService mockLicenseService; @@ -60,7 +62,6 @@ public class HeartBeatTest @Before public void setUp() { - // New context with scheduler context = new ClassPathXmlApplicationContext(CONFIG_LOCATIONS); @@ -71,13 +72,11 @@ public class HeartBeatTest ((ConfigurableApplicationContext) context).getBeanFactory().registerSingleton("hbDataCollectorService",mockDataCollectorService); mockDataSenderService = mock(HBDataSenderService.class); - } @Test public void testHBRegistersWithLicenceService() { - HeartBeat heartbeat = new HeartBeat(context,false); // Check that HearBeat registers itself with the licence service @@ -87,7 +86,6 @@ public class HeartBeatTest @Test public void testJobSchedulingWhenEnabled() { - // Enable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); @@ -97,29 +95,24 @@ public class HeartBeatTest assertTrue("Job was not scheduled but HB is enabled", isJobScheduled()); } - @Test public void testJobSchedulingWhenDisabled() { - // Disable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); HeartBeat heartbeat = new HeartBeat(context,true); - // Check that the job is scheduled when heartbeat is disabled + // Check that the job is not scheduled when heartbeat is disabled assertFalse("Job was scheduled but HB is disabled", isJobScheduled()); - } - /** * Heartbeat enabled by default but disabled in licence on onLicenseChange */ @Test public void testOnLicenseChangeOverridesDefaultEnabled() { - // Enable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); @@ -137,7 +130,6 @@ public class HeartBeatTest // Check heartbeat is disabled and job unscheduled assertFalse(heartbeat.isEnabled()); assertFalse("Job should be unscheduled.",isJobScheduled()); - } /** @@ -165,11 +157,9 @@ public class HeartBeatTest assertTrue("Job should be scheduled.",isJobScheduled()); } - @Test public void testOnLicenceFailRevertsToEnabled() { - // Enable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); @@ -189,15 +179,11 @@ public class HeartBeatTest // Check heartbeat is disabled and job unscheduled assertTrue(heartbeat.isEnabled()); assertTrue("Job should be unscheduled.",isJobScheduled()); - - } - @Test public void testOnLicenceFailRevertsToDisabled() { - // Disable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); @@ -217,22 +203,21 @@ public class HeartBeatTest // Check heartbeat is disabled and job unscheduled assertFalse(heartbeat.isEnabled()); assertFalse("Job should be unscheduled.",isJobScheduled()); - } - private boolean isJobScheduled() { Scheduler scheduler = (Scheduler) context.getBean("schedulerFactory"); String[] jobs = {}; - try { + try + { jobs = scheduler.getJobNames( Scheduler.DEFAULT_GROUP); - } catch (SchedulerException e) { + } catch (SchedulerException e) + { e.printStackTrace(); fail("Exception before assertion."); } return Arrays.asList(jobs).contains("heartbeat"); } - } From a51b5f10a1b67647ff3ebc9f64d052b689c06677 Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Wed, 13 Sep 2017 17:19:16 +0100 Subject: [PATCH 16/21] REPO-2852 Heartbeat: Add junit tests for the new service and collectors * Add unit tests for RepositoryDataCollector --- .../RepositoryDataCollectorTest.java | 156 ++++++++++++++++++ .../heartbeat/test-heartbeat-context.xml | 29 ++++ 2 files changed, 185 insertions(+) create mode 100644 src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java create mode 100644 src/test/resources/org/alfresco/heartbeat/test-heartbeat-context.xml diff --git a/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java b/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java new file mode 100644 index 0000000000..37c5f88002 --- /dev/null +++ b/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java @@ -0,0 +1,156 @@ +/* + * #%L + * Alfresco Repository + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco 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 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Alfresco. If not, see . + * #L% + */ +package org.alfresco.heartbeat; + +import org.alfresco.heartbeat.datasender.HBData; +import org.alfresco.repo.descriptor.DescriptorDAO; +import org.alfresco.repo.dictionary.CustomModelsInfo; +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.descriptor.Descriptor; +import org.alfresco.service.transaction.TransactionService; +import org.alfresco.util.ApplicationContextHelper; +import org.junit.Before; +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import java.util.List; +import java.util.Map; +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * @author eknizat + */ +public class RepositoryDataCollectorTest +{ + + private ApplicationContext context; + private RepositoryDataCollector repoCollector; + private List collectedData; + + @Before + public void setUp() + { + context = ApplicationContextHelper.getApplicationContext(); + + TransactionService transactionService = (TransactionService) context.getBean("transactionService"); + HBDataCollectorService mockCollectorService = mock(HBDataCollectorService.class); + AuthorityService authorityService = mock(AuthorityService.class); + + Descriptor mockDescriptor = mock(Descriptor.class); + when(mockDescriptor.getId()).thenReturn("mock_id"); + DescriptorDAO descriptorDAO = mock(DescriptorDAO.class); + when(descriptorDAO.getDescriptor()).thenReturn(mockDescriptor); + + RepoUsage mockRepoUsage = mock(RepoUsage.class); + RepoUsageComponent repoUsageComponent = mock(RepoUsageComponent.class); + when(repoUsageComponent.getUsage()).thenReturn(mockRepoUsage); + + CustomModelsInfo mockCustomModelsInfo = mock(CustomModelsInfo.class); + CustomModelService customModelService = mock(CustomModelService.class); + when(customModelService.getCustomModelsInfo()).thenReturn(mockCustomModelsInfo); + + repoCollector = new RepositoryDataCollector(); + repoCollector.setAuthorityService(authorityService); + repoCollector.setCurrentRepoDescriptorDAO(descriptorDAO); + repoCollector.setCustomModelService(customModelService); + repoCollector.setRepoUsageComponent(repoUsageComponent); + repoCollector.setServerDescriptorDAO(descriptorDAO); + repoCollector.setTransactionService(transactionService); + repoCollector.setHbDataCollectorService(mockCollectorService); + collectedData = repoCollector.collectData(); + } + + @Test + public void testHBDataFields() + { + for(HBData data : this.collectedData) + { + System.out.println(data.getCollectorId()); + assertNotNull(data.getCollectorId()); + assertNotNull(data.getCollectorVersion()); + assertNotNull(data.getSchemaVersion()); + assertNotNull(data.getSystemId()); + assertNotNull(data.getTimestamp()); + } + + } + + @Test + public void testInfoDataIsCollected() + { + HBData repoInfo = grabDataByCollectorId("acs.repository.info"); + assertNotNull("Repository info data missing.", repoInfo); + + Map data = repoInfo.getData(); + assertTrue(data.containsKey("repoName")); + assertTrue(data.containsKey("edition")); + assertTrue(data.containsKey("versionMajor")); + assertTrue(data.containsKey("versionMinor")); + assertTrue(data.containsKey("schema")); + } + + @Test + public void testSystemUsageDataIsCollected() + { + HBData systemUsage = grabDataByCollectorId("acs.repository.usage.system"); + assertNotNull("Repository usage data missing.", systemUsage); + + Map data = systemUsage.getData(); + assertTrue(data.containsKey("memFree")); + assertTrue(data.containsKey("memMax")); + assertTrue(data.containsKey("memTotal")); + } + + @Test + public void testModelUsageDataIsCollected() + { + HBData modelUsage = grabDataByCollectorId("acs.repository.usage.model"); + assertNotNull("Model usage data missing.", modelUsage); + + Map data = modelUsage.getData(); + assertTrue(data.containsKey("numOfActiveModels")); + assertTrue(data.containsKey("numOfActiveTypes")); + assertTrue(data.containsKey("numOfActiveAspects")); + + } + + private HBData grabDataByCollectorId(String collectorId) + { + for (HBData d : this.collectedData) + { + if(d.getCollectorId()!=null && d.getCollectorId().equals(collectorId)) + { + return d; + } + } + return null; + } +} diff --git a/src/test/resources/org/alfresco/heartbeat/test-heartbeat-context.xml b/src/test/resources/org/alfresco/heartbeat/test-heartbeat-context.xml new file mode 100644 index 0000000000..b3eb65d2d1 --- /dev/null +++ b/src/test/resources/org/alfresco/heartbeat/test-heartbeat-context.xml @@ -0,0 +1,29 @@ + + + + + + + + + true + + + org.alfresco.repo.scheduler.AlfrescoSchedulerFactory + + + + + + + + + DefaultScheduler + + + + false + + + + From 08fb7f53d24b30d075e6b4212d8c6da50114dac2 Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Thu, 14 Sep 2017 09:53:18 +0000 Subject: [PATCH 17/21] [maven-release-plugin] prepare release alfresco-repository-HB20-1 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 804c0f5cd5..5f56378101 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 alfresco-repository Alfresco Repository - 6.1-SNAPSHOT + HB20-1 jar @@ -15,7 +15,7 @@ scm:git:git@github.com:Alfresco/alfresco-repository.git scm:git:git@github.com:Alfresco/alfresco-repository.git https://github.com/Alfresco/alfresco-repository - HEAD + alfresco-repository-HB20-1 From 1ec8a00a72beda5bb939d4ce7c8ecff74f4fb54e Mon Sep 17 00:00:00 2001 From: alfresco-build Date: Thu, 14 Sep 2017 09:53:23 +0000 Subject: [PATCH 18/21] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 5f56378101..89106232b4 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 alfresco-repository Alfresco Repository - HB20-1 + HB20-2-SNAPSHOT jar @@ -15,7 +15,7 @@ scm:git:git@github.com:Alfresco/alfresco-repository.git scm:git:git@github.com:Alfresco/alfresco-repository.git https://github.com/Alfresco/alfresco-repository - alfresco-repository-HB20-1 + HEAD From cf4f02b19ca49d4bd324900f85229c945c39cd32 Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Thu, 14 Sep 2017 15:31:45 +0100 Subject: [PATCH 19/21] REPO-2852 Heartbeat: Add junit tests for the new service and collectors *Add test to AllRepositoryTestsCatalogue --- src/test/java/org/alfresco/AllRepositoryTestsCatalogue.java | 6 ++++++ .../org/alfresco/heartbeat/RepositoryDataCollectorTest.java | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/alfresco/AllRepositoryTestsCatalogue.java b/src/test/java/org/alfresco/AllRepositoryTestsCatalogue.java index a0bcbea78f..fbf8ea4c49 100644 --- a/src/test/java/org/alfresco/AllRepositoryTestsCatalogue.java +++ b/src/test/java/org/alfresco/AllRepositoryTestsCatalogue.java @@ -25,6 +25,7 @@ */ package org.alfresco; +import org.alfresco.heartbeat.*; import org.alfresco.repo.action.ActionConditionDefinitionImplTest; import org.alfresco.repo.action.ActionConditionImplTest; import org.alfresco.repo.action.ActionDefinitionImplTest; @@ -417,6 +418,7 @@ public class AllRepositoryTestsCatalogue suite.addTestSuite(ADMLuceneCategoryTest.class); suite.addTestSuite(ADMLuceneTest.class); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.blog.BlogServiceImplTest.class)); + suite.addTest(new JUnit4TestAdapter(RepositoryDataCollectorTest.class)); } // [classpath:alfresco/application-context.xml, classpath:cache-test/cache-test-context.xml] @@ -587,6 +589,9 @@ public class AllRepositoryTestsCatalogue // [alfresco/scheduler-core-context.xml, org/alfresco/util/test-scheduled-jobs-context.xml] suite.addTest(new JUnit4TestAdapter(org.alfresco.util.CronTriggerBeanTest.class)); + + // [alfresco/scheduler-core-context.xml, org/alfresco/heartbeat/test-heartbeat-context.xml] + suite.addTest(new JUnit4TestAdapter(HeartBeatTest.class)); } // no context - true JUNIT tests @@ -716,5 +721,6 @@ public class AllRepositoryTestsCatalogue suite.addTestSuite(WorklfowObjectFactoryTest.class); suite.addTestSuite(WorkflowSuiteContextShutdownTest.class); suite.addTest(new JUnit4TestAdapter(org.alfresco.repo.search.impl.lucene.analysis.PathTokenFilterTest.class)); + suite.addTest(new JUnit4TestAdapter(HBDataCollectorServiceImplTest.class)); } } diff --git a/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java b/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java index 37c5f88002..8c576f54a3 100644 --- a/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java +++ b/src/test/java/org/alfresco/heartbeat/RepositoryDataCollectorTest.java @@ -93,7 +93,6 @@ public class RepositoryDataCollectorTest { for(HBData data : this.collectedData) { - System.out.println(data.getCollectorId()); assertNotNull(data.getCollectorId()); assertNotNull(data.getCollectorVersion()); assertNotNull(data.getSchemaVersion()); From eda2ac2b6fed5272082c9ddb08bd9c0f60b5d3b9 Mon Sep 17 00:00:00 2001 From: Erik Knizat Date: Fri, 15 Sep 2017 13:45:30 +0100 Subject: [PATCH 20/21] REPO-2852 Heartbeat: Add junit tests for the new service and collectors * Code review changes - added throws Exception to method signatures --- .../org/alfresco/heartbeat/HeartBeatTest.java | 33 +++++++------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java index c7b908e818..9c8d8d0ebd 100644 --- a/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java +++ b/src/test/java/org/alfresco/heartbeat/HeartBeatTest.java @@ -70,8 +70,6 @@ public class HeartBeatTest mockDataCollectorService = mock(HBDataCollectorService.class); ((ConfigurableApplicationContext) context).getBeanFactory().registerSingleton("licenseService",mockLicenseService); ((ConfigurableApplicationContext) context).getBeanFactory().registerSingleton("hbDataCollectorService",mockDataCollectorService); - - mockDataSenderService = mock(HBDataSenderService.class); } @Test @@ -84,7 +82,7 @@ public class HeartBeatTest } @Test - public void testJobSchedulingWhenEnabled() + public void testJobSchedulingWhenEnabled() throws Exception { // Enable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); @@ -96,7 +94,7 @@ public class HeartBeatTest } @Test - public void testJobSchedulingWhenDisabled() + public void testJobSchedulingWhenDisabled() throws Exception { // Disable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); @@ -111,7 +109,7 @@ public class HeartBeatTest * Heartbeat enabled by default but disabled in licence on onLicenseChange */ @Test - public void testOnLicenseChangeOverridesDefaultEnabled() + public void testOnLicenseChangeOverridesDefaultEnabled() throws Exception { // Enable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); @@ -136,7 +134,7 @@ public class HeartBeatTest * heartbeat disabled by default but enabled in licence */ @Test - public void testOnLicenseChangeOverridesDefaultDisabled() + public void testOnLicenseChangeOverridesDefaultDisabled() throws Exception { // Disable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); @@ -152,13 +150,13 @@ public class HeartBeatTest heartbeat.onLicenseChange(mockLicenseDescriptor); - // Check heartbeat is disabled and job unscheduled + // Check heartbeat is enabled and job unscheduled assertTrue(heartbeat.isEnabled()); assertTrue("Job should be scheduled.",isJobScheduled()); } @Test - public void testOnLicenceFailRevertsToEnabled() + public void testOnLicenceFailRevertsToEnabled() throws Exception { // Enable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(true); @@ -176,13 +174,13 @@ public class HeartBeatTest // Revert back to default state heartbeat.onLicenseFail(); - // Check heartbeat is disabled and job unscheduled + // Check heartbeat is enabled and job unscheduled assertTrue(heartbeat.isEnabled()); assertTrue("Job should be unscheduled.",isJobScheduled()); } @Test - public void testOnLicenceFailRevertsToDisabled() + public void testOnLicenceFailRevertsToDisabled() throws Exception { // Disable heartbeat in data collector service ( as if set in prop file) when(mockDataCollectorService.isEnabledByDefault()).thenReturn(false); @@ -205,19 +203,10 @@ public class HeartBeatTest assertFalse("Job should be unscheduled.",isJobScheduled()); } - private boolean isJobScheduled() + private boolean isJobScheduled() throws Exception { Scheduler scheduler = (Scheduler) context.getBean("schedulerFactory"); - String[] jobs = {}; - try - { - jobs = scheduler.getJobNames( Scheduler.DEFAULT_GROUP); - } catch (SchedulerException e) - { - e.printStackTrace(); - fail("Exception before assertion."); - } - + String[] jobs = scheduler.getJobNames( Scheduler.DEFAULT_GROUP); return Arrays.asList(jobs).contains("heartbeat"); } -} +} \ No newline at end of file From 994e3468f92ddbeefb68cc738541815913ada78b Mon Sep 17 00:00:00 2001 From: eknizat <2erik2@live.co.uk> Date: Tue, 19 Sep 2017 17:29:18 +0100 Subject: [PATCH 21/21] Update pom.xml Keep version 6.1-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 89106232b4..804c0f5cd5 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 alfresco-repository Alfresco Repository - HB20-2-SNAPSHOT + 6.1-SNAPSHOT jar