2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.sparky.synchronizer;
25 import com.google.common.util.concurrent.ThreadFactoryBuilder;
27 import java.lang.Thread.UncaughtExceptionHandler;
28 import java.text.SimpleDateFormat;
29 import java.util.ArrayList;
30 import java.util.Calendar;
31 import java.util.List;
33 import java.util.TimeZone;
34 import java.util.concurrent.Executors;
35 import java.util.concurrent.ScheduledExecutorService;
36 import java.util.concurrent.ThreadFactory;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.atomic.AtomicLong;
40 import org.openecomp.cl.api.Logger;
41 import org.openecomp.cl.eelf.LoggerFactory;
42 import org.openecomp.sparky.config.oxm.OxmEntityDescriptor;
43 import org.openecomp.sparky.config.oxm.OxmModelLoader;
44 import org.openecomp.sparky.dal.aai.ActiveInventoryAdapter;
45 import org.openecomp.sparky.dal.aai.config.ActiveInventoryConfig;
46 import org.openecomp.sparky.dal.aai.config.ActiveInventoryRestConfig;
47 import org.openecomp.sparky.dal.cache.EntityCache;
48 import org.openecomp.sparky.dal.cache.InMemoryEntityCache;
49 import org.openecomp.sparky.dal.cache.PersistentEntityCache;
50 import org.openecomp.sparky.dal.elasticsearch.ElasticSearchAdapter;
51 import org.openecomp.sparky.dal.elasticsearch.config.ElasticSearchConfig;
52 import org.openecomp.sparky.dal.rest.RestClientBuilder;
53 import org.openecomp.sparky.dal.rest.RestfulDataAccessor;
54 import org.openecomp.sparky.logging.AaiUiMsgs;
55 import org.openecomp.sparky.synchronizer.SyncController.SyncActions;
56 import org.openecomp.sparky.synchronizer.config.SynchronizerConfiguration;
57 import org.openecomp.sparky.synchronizer.config.SynchronizerConstants;
58 import org.openecomp.sparky.synchronizer.enumeration.SynchronizerState;
59 import org.openecomp.sparky.util.ErrorUtil;
60 import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
64 * The Class SyncHelper.
68 public class SyncHelper {
70 private final Logger LOG = LoggerFactory.getInstance().getLogger(SyncHelper.class);
71 private SyncController syncController = null;
72 private SyncController entityCounterHistorySummarizer = null;
74 private ScheduledExecutorService oneShotExecutor = Executors.newSingleThreadScheduledExecutor();
75 private ScheduledExecutorService periodicExecutor = null;
76 private ScheduledExecutorService historicalExecutor =
77 Executors.newSingleThreadScheduledExecutor();
79 private SynchronizerConfiguration syncConfig;
80 private ElasticSearchConfig esConfig;
81 private OxmModelLoader oxmModelLoader;
83 private Boolean initialSyncRunning = false;
84 private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
85 private AtomicLong timeNextSync = new AtomicLong();
86 Map<String, String> contextMap;
91 private class SyncTask implements Runnable {
93 private boolean isInitialSync;
96 * Instantiates a new sync task.
98 * @param initialSync the initial sync
100 public SyncTask(boolean initialSync) {
101 this.isInitialSync = initialSync;
107 * @see java.lang.Runnable#run()
111 long opStartTime = System.currentTimeMillis();
112 MDC.setContextMap(contextMap);
114 LOG.info(AaiUiMsgs.SEARCH_ENGINE_SYNC_STARTED, sdf.format(opStartTime)
115 .replaceAll(SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD));
119 if (syncController == null) {
120 LOG.error(AaiUiMsgs.SYNC_SKIPPED_SYNCCONTROLLER_NOT_INITIALIZED);
124 int taskFrequencyInDays = SynchronizerConfiguration.getConfig().getSyncTaskFrequencyInDay();
127 * Do nothing if the initial start-up sync hasn't finished yet, but the regular sync
128 * scheduler fired up a regular sync.
130 if (!initialSyncRunning) {
132 initialSyncRunning = true;
134 // update 'timeNextSync' for periodic sync
135 timeNextSync.getAndAdd(taskFrequencyInDays * SynchronizerConstants.MILLISEC_IN_A_DAY);
139 LOG.info(AaiUiMsgs.INFO_GENERIC, "SyncTask, starting syncrhonization");
141 syncController.performAction(SyncActions.SYNCHRONIZE);
143 while (syncController.getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
148 LOG.info(AaiUiMsgs.SKIP_PERIODIC_SYNC_AS_SYNC_DIDNT_FINISH, sdf.format(opStartTime)
149 .replaceAll(SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD));
154 long opEndTime = System.currentTimeMillis();
158 * Handle corner case when start-up sync operation overlapped with a scheduled
159 * sync-start-time. Note that the scheduled sync does nothing if 'initialSyncRunning' is
160 * TRUE. So the actual next-sync is one more sync-cycle away
162 long knownNextSyncTime = timeNextSync.get();
163 if (knownNextSyncTime != SynchronizerConstants.DELAY_NO_PERIODIC_SYNC_IN_MS
164 && opEndTime > knownNextSyncTime) {
165 timeNextSync.compareAndSet(knownNextSyncTime,
166 knownNextSyncTime + taskFrequencyInDays * SynchronizerConstants.MILLISEC_IN_A_DAY);
167 initialSyncRunning = false;
171 String durationMessage =
172 String.format(syncController.getControllerName() + " synchronization took '%d' ms.",
173 (opEndTime - opStartTime));
175 LOG.info(AaiUiMsgs.SYNC_DURATION, durationMessage);
177 // Provide log about the time for next synchronization
178 if (syncConfig.isConfigOkForPeriodicSync()
179 && timeNextSync.get() != SynchronizerConstants.DELAY_NO_PERIODIC_SYNC_IN_MS) {
180 TimeZone tz = TimeZone.getTimeZone(syncConfig.getSyncTaskStartTimeTimeZone());
182 if (opEndTime - opStartTime > taskFrequencyInDays
183 * SynchronizerConstants.MILLISEC_IN_A_DAY) {
184 String durationWasLongerMessage = String.format(
185 syncController.getControllerName()
186 + " synchronization took '%d' ms which is larger than"
187 + " synchronization interval of '%d' ms.",
188 (opEndTime - opStartTime),
189 taskFrequencyInDays * SynchronizerConstants.MILLISEC_IN_A_DAY);
191 LOG.info(AaiUiMsgs.SYNC_DURATION, durationWasLongerMessage);
194 LOG.info(AaiUiMsgs.SYNC_TO_BEGIN, syncController.getControllerName(),
195 sdf.format(timeNextSync).replaceAll(SynchronizerConstants.TIME_STD,
196 SynchronizerConstants.TIME_CONFIG_STD));
199 } catch (Exception exc) {
200 String message = "Caught an exception while attempt to synchronize elastic search "
201 + "with an error cause = " + ErrorUtil.extractStackTraceElements(5, exc);
202 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
210 * The Class HistoricalEntityCountSummaryTask.
212 private class HistoricalEntityCountSummaryTask implements Runnable {
215 * Instantiates a new historical entity count summary task.
217 public HistoricalEntityCountSummaryTask() {}
222 * @see java.lang.Runnable#run()
227 long opStartTime = System.currentTimeMillis();
228 MDC.setContextMap(contextMap);
229 LOG.info(AaiUiMsgs.HISTORICAL_ENTITY_COUNT_SUMMARIZER_STARTING, sdf.format(opStartTime)
230 .replaceAll(SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD));
233 if (entityCounterHistorySummarizer == null) {
234 LOG.error(AaiUiMsgs.HISTORICAL_ENTITY_COUNT_SUMMARIZER_NOT_STARTED);
238 LOG.info(AaiUiMsgs.INFO_GENERIC,
239 "EntityCounterHistorySummarizer, starting syncrhonization");
241 entityCounterHistorySummarizer.performAction(SyncActions.SYNCHRONIZE);
243 while (entityCounterHistorySummarizer
244 .getState() == SynchronizerState.PERFORMING_SYNCHRONIZATION) {
248 long opEndTime = System.currentTimeMillis();
250 LOG.info(AaiUiMsgs.HISTORICAL_SYNC_DURATION,
251 entityCounterHistorySummarizer.getControllerName(),
252 String.valueOf(opEndTime - opStartTime));
254 long taskFrequencyInMs =
255 syncConfig.getHistoricalEntitySummarizedFrequencyInMinutes() * 60 * 1000;
257 if (syncConfig.isHistoricalEntitySummarizerEnabled()) {
258 String time = sdf.format(System.currentTimeMillis() + taskFrequencyInMs)
259 .replaceAll(SynchronizerConstants.TIME_STD, SynchronizerConstants.TIME_CONFIG_STD);
261 LOG.info(AaiUiMsgs.HISTORICAL_SYNC_TO_BEGIN, time);
265 } catch (Exception exc) {
266 String message = "Caught an exception while attempting to populate entity country "
267 + "history elasticsearch table with an error cause = "
268 + ErrorUtil.extractStackTraceElements(5, exc);
269 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
277 * Gets the first sync time.
279 * @param calendar the calendar
280 * @param timeNow the time now
281 * @param taskFreqInDay the task freq in day
282 * @return the first sync time
284 public long getFirstSyncTime(Calendar calendar, long timeNow, int taskFreqInDay) {
285 if (taskFreqInDay == SynchronizerConstants.DELAY_NO_PERIODIC_SYNC_IN_MS) {
286 return SynchronizerConstants.DELAY_NO_PERIODIC_SYNC_IN_MS;
287 } else if (timeNow > calendar.getTimeInMillis()) {
288 calendar.add(Calendar.DAY_OF_MONTH, taskFreqInDay);
290 return calendar.getTimeInMillis();
294 * Boot strap and configure the moving pieces of the Sync Controller.
297 private void initializeSyncController() {
302 * TODO: it would be nice to have XML IoC / dependency injection kind of thing for these
303 * pieces maybe Spring?
307 * Sync Controller itself
310 syncController = new SyncController("entitySyncController");
313 * Create common elements
316 ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new RestClientBuilder());
317 ActiveInventoryRestConfig aaiRestConfig =
318 ActiveInventoryConfig.getConfig().getAaiRestConfig();
321 EntityCache cache = null;
323 if (aaiRestConfig.isCacheEnabled()) {
324 cache = new PersistentEntityCache(aaiRestConfig.getStorageFolderOverride(),
325 aaiRestConfig.getNumCacheWorkers());
327 cache = new InMemoryEntityCache();
330 RestClientBuilder clientBuilder = new RestClientBuilder();
332 aaiAdapter.setCacheEnabled(true);
333 aaiAdapter.setEntityCache(cache);
335 clientBuilder.setUseHttps(false);
337 RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
339 ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
340 ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider, esConfig);
343 * Register Index Validators
346 IndexIntegrityValidator entitySearchIndexValidator =
347 new IndexIntegrityValidator(nonCachingRestProvider, esConfig.getIndexName(),
348 esConfig.getType(), esConfig.getIpAddress(), esConfig.getHttpPort(),
349 esConfig.buildElasticSearchTableConfig());
351 syncController.registerIndexValidator(entitySearchIndexValidator);
353 // TODO: Insert IndexValidator for TopographicalEntityIndex
354 // we should have one, but one isn't 100% required as none of the fields are analyzed
357 * Register Synchronizers
360 SearchableEntitySynchronizer ses = new SearchableEntitySynchronizer(esConfig.getIndexName());
361 ses.setAaiDataProvider(aaiAdapter);
362 ses.setEsDataProvider(esAdapter);
363 syncController.registerEntitySynchronizer(ses);
365 CrossEntityReferenceSynchronizer cers = new CrossEntityReferenceSynchronizer(
366 esConfig.getIndexName(), ActiveInventoryConfig.getConfig());
367 cers.setAaiDataProvider(aaiAdapter);
368 cers.setEsDataProvider(esAdapter);
369 syncController.registerEntitySynchronizer(cers);
371 GeoSynchronizer geo = new GeoSynchronizer(esConfig.getTopographicalSearchIndex());
372 geo.setAaiDataProvider(aaiAdapter);
373 geo.setEsDataProvider(esAdapter);
374 syncController.registerEntitySynchronizer(geo);
376 if (syncConfig.isAutosuggestSynchronizationEnabled()) {
377 initAutoSuggestionSynchronizer(esConfig, aaiAdapter, esAdapter, nonCachingRestProvider);
378 initAggregationSynchronizer(esConfig, aaiAdapter, esAdapter, nonCachingRestProvider);
385 IndexCleaner searchableIndexCleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
386 esConfig.getIndexName(), esConfig.getType(), esConfig.getIpAddress(),
387 esConfig.getHttpPort(), syncConfig.getScrollContextTimeToLiveInMinutes(),
388 syncConfig.getNumScrollContextItemsToRetrievePerRequest());
390 syncController.registerIndexCleaner(searchableIndexCleaner);
392 IndexCleaner geoIndexCleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
393 esConfig.getTopographicalSearchIndex(), esConfig.getType(), esConfig.getIpAddress(),
394 esConfig.getHttpPort(), syncConfig.getScrollContextTimeToLiveInMinutes(),
395 syncConfig.getNumScrollContextItemsToRetrievePerRequest());
397 syncController.registerIndexCleaner(geoIndexCleaner);
400 } catch (Exception exc) {
401 String message = "Error: failed to sync with message = " + exc.getMessage();
402 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
408 * Inits the entity counter history summarizer.
410 private void initEntityCounterHistorySummarizer() {
412 LOG.info(AaiUiMsgs.INFO_GENERIC, "initEntityCounterHistorySummarizer");
415 entityCounterHistorySummarizer = new SyncController("entityCounterHistorySummarizer");
417 ActiveInventoryAdapter aaiAdapter = new ActiveInventoryAdapter(new RestClientBuilder());
418 aaiAdapter.setCacheEnabled(false);
420 RestClientBuilder clientBuilder = new RestClientBuilder();
421 clientBuilder.setUseHttps(false);
423 RestfulDataAccessor nonCachingRestProvider = new RestfulDataAccessor(clientBuilder);
424 ElasticSearchConfig esConfig = ElasticSearchConfig.getConfig();
425 ElasticSearchAdapter esAdapter = new ElasticSearchAdapter(nonCachingRestProvider, esConfig);
427 IndexIntegrityValidator entityCounterHistoryValidator =
428 new IndexIntegrityValidator(nonCachingRestProvider, esConfig.getEntityCountHistoryIndex(),
429 esConfig.getType(), esConfig.getIpAddress(), esConfig.getHttpPort(),
430 esConfig.buildElasticSearchEntityCountHistoryTableConfig());
432 entityCounterHistorySummarizer.registerIndexValidator(entityCounterHistoryValidator);
434 HistoricalEntitySummarizer historicalSummarizer =
435 new HistoricalEntitySummarizer(esConfig.getEntityCountHistoryIndex());
436 historicalSummarizer.setAaiDataProvider(aaiAdapter);
437 historicalSummarizer.setEsDataProvider(esAdapter);
438 entityCounterHistorySummarizer.registerEntitySynchronizer(historicalSummarizer);
440 } catch (Exception exc) {
441 String message = "Error: failed to sync with message = " + exc.getMessage();
442 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
446 private List<String> getAutosuggestableEntitiesFromOXM() {
447 Map<String, OxmEntityDescriptor> map = oxmModelLoader.getSuggestionSearchEntityDescriptors();
448 List<String> suggestableEntities = new ArrayList<String>();
450 for (String entity: map.keySet()){
451 suggestableEntities.add(entity);
453 return suggestableEntities;
457 * Initialize the AutosuggestionSynchronizer and
458 * AggregationSuggestionSynchronizer
463 * @param nonCachingRestProvider
465 private void initAutoSuggestionSynchronizer(ElasticSearchConfig esConfig,
466 ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
467 RestfulDataAccessor nonCachingRestProvider) {
468 LOG.info(AaiUiMsgs.INFO_GENERIC, "initAutoSuggestionSynchronizer");
470 // Initialize for entityautosuggestindex
472 IndexIntegrityValidator autoSuggestionIndexValidator =
473 new IndexIntegrityValidator(nonCachingRestProvider, esConfig.getAutosuggestIndexname(),
474 esConfig.getType(), esConfig.getIpAddress(), esConfig.getHttpPort(),
475 esConfig.buildAutosuggestionTableConfig());
477 syncController.registerIndexValidator(autoSuggestionIndexValidator);
479 AutosuggestionSynchronizer suggestionSynchronizer =
480 new AutosuggestionSynchronizer(esConfig.getAutosuggestIndexname());
481 suggestionSynchronizer.setAaiDataProvider(aaiAdapter);
482 suggestionSynchronizer.setEsDataProvider(esAdapter);
483 syncController.registerEntitySynchronizer(suggestionSynchronizer);
485 AggregationSuggestionSynchronizer aggregationSuggestionSynchronizer =
486 new AggregationSuggestionSynchronizer(esConfig.getAutosuggestIndexname());
487 aggregationSuggestionSynchronizer.setEsDataProvider(esAdapter);
488 syncController.registerEntitySynchronizer(aggregationSuggestionSynchronizer);
490 IndexCleaner autosuggestIndexCleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
491 esConfig.getAutosuggestIndexname(), esConfig.getType(), esConfig.getIpAddress(),
492 esConfig.getHttpPort(), syncConfig.getScrollContextTimeToLiveInMinutes(),
493 syncConfig.getNumScrollContextItemsToRetrievePerRequest());
495 syncController.registerIndexCleaner(autosuggestIndexCleaner);
496 } catch (Exception exc) {
497 String message = "Error: failed to sync with message = " + exc.getMessage();
498 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
503 * Initialize the AggregationSynchronizer
508 * @param nonCachingRestProvider
510 private void initAggregationSynchronizer(ElasticSearchConfig esConfig,
511 ActiveInventoryAdapter aaiAdapter, ElasticSearchAdapter esAdapter,
512 RestfulDataAccessor nonCachingRestProvider) {
513 LOG.info(AaiUiMsgs.INFO_GENERIC, "initAggregationSynchronizer");
515 List<String> aggregationEntities = getAutosuggestableEntitiesFromOXM();
517 // For each index: create an IndexValidator, a Synchronizer, and an IndexCleaner
518 for (String entity : aggregationEntities) {
520 String indexName = TierSupportUiConstants.getAggregationIndexName(entity);
522 IndexIntegrityValidator aggregationIndexValidator = new IndexIntegrityValidator(
523 nonCachingRestProvider, indexName, esConfig.getType(), esConfig.getIpAddress(),
524 esConfig.getHttpPort(), esConfig.buildAggregationTableConfig());
526 syncController.registerIndexValidator(aggregationIndexValidator);
529 * TODO: This per-entity-synchronizer approach will eventually result in AAI / ES overload
530 * because of the existing dedicated thread pools for ES + AAI operations within the
531 * synchronizer. If we had 50 types to sync then the thread pools within each Synchronizer
532 * would cause some heartburn as there would be hundreds of threads trying to talk to AAI.
533 * Given that we our running out of time, let's make sure we can get it functional and then
536 AggregationSynchronizer aggSynchronizer = new AggregationSynchronizer(entity, indexName);
537 aggSynchronizer.setAaiDataProvider(aaiAdapter);
538 aggSynchronizer.setEsDataProvider(esAdapter);
539 syncController.registerEntitySynchronizer(aggSynchronizer);
541 IndexCleaner entityDataIndexCleaner = new ElasticSearchIndexCleaner(nonCachingRestProvider,
542 indexName, esConfig.getType(), esConfig.getIpAddress(), esConfig.getHttpPort(),
543 syncConfig.getScrollContextTimeToLiveInMinutes(),
544 syncConfig.getNumScrollContextItemsToRetrievePerRequest());
546 syncController.registerIndexCleaner(entityDataIndexCleaner);
548 } catch (Exception exc) {
549 String message = "Error: failed to sync with message = " + exc.getMessage();
550 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
556 * Instantiates a new sync helper.
558 * @param loader the loader
560 public SyncHelper(OxmModelLoader loader) {
562 this.contextMap = MDC.getCopyOfContextMap();
563 this.syncConfig = SynchronizerConfiguration.getConfig();
564 this.esConfig = ElasticSearchConfig.getConfig();
565 this.oxmModelLoader = loader;
567 UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
570 public void uncaughtException(Thread thread, Throwable exc) {
571 LOG.error(AaiUiMsgs.ERROR_GENERIC, thread.getName() + ": " + exc);
575 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("SyncHelper-%d")
576 .setUncaughtExceptionHandler(uncaughtExceptionHandler).build();
578 periodicExecutor = Executors.newScheduledThreadPool(3, namedThreadFactory);
581 * We only want to initialize the synchronizer if sync has been configured to start
583 if (syncConfig.isConfigOkForStartupSync() || syncConfig.isConfigOkForPeriodicSync()) {
584 initializeSyncController();
587 if (syncConfig.isHistoricalEntitySummarizerEnabled()) {
588 initEntityCounterHistorySummarizer();
590 LOG.info(AaiUiMsgs.INFO_GENERIC, "history summarizer disabled");
594 // schedule startup synchronization
595 if (syncConfig.isConfigOkForStartupSync()) {
597 long taskInitialDelayInMs = syncConfig.getSyncTaskInitialDelayInMs();
598 if (taskInitialDelayInMs != SynchronizerConstants.DELAY_NO_STARTUP_SYNC_IN_MS) {
599 oneShotExecutor.schedule(new SyncTask(true), taskInitialDelayInMs, TimeUnit.MILLISECONDS);
600 LOG.info(AaiUiMsgs.INFO_GENERIC, "Search Engine startup synchronization is enabled.");
602 LOG.info(AaiUiMsgs.INFO_GENERIC, "Search Engine startup synchronization is disabled.");
606 // schedule periodic synchronization
607 if (syncConfig.isConfigOkForPeriodicSync()) {
609 TimeZone tz = TimeZone.getTimeZone(syncConfig.getSyncTaskStartTimeTimeZone());
610 Calendar calendar = Calendar.getInstance(tz);
613 calendar.set(Calendar.HOUR_OF_DAY, syncConfig.getSyncTaskStartTimeHr());
614 calendar.set(Calendar.MINUTE, syncConfig.getSyncTaskStartTimeMin());
615 calendar.set(Calendar.SECOND, syncConfig.getSyncTaskStartTimeSec());
617 long timeCurrent = calendar.getTimeInMillis();
618 int taskFrequencyInDay = syncConfig.getSyncTaskFrequencyInDay();
619 timeNextSync.getAndSet(getFirstSyncTime(calendar, timeCurrent, taskFrequencyInDay));
621 long delayUntilFirstRegSyncInMs = 0;
622 delayUntilFirstRegSyncInMs = timeNextSync.get() - timeCurrent;
624 // Do all calculation in milliseconds
625 long taskFreqencyInMs = taskFrequencyInDay * SynchronizerConstants.MILLISEC_IN_A_DAY;
627 if (taskFreqencyInMs != SynchronizerConstants.DELAY_NO_PERIODIC_SYNC_IN_MS) {
628 periodicExecutor.scheduleAtFixedRate(new SyncTask(false), delayUntilFirstRegSyncInMs,
629 taskFreqencyInMs, TimeUnit.MILLISECONDS);
630 LOG.info(AaiUiMsgs.INFO_GENERIC, "Search Engine periodic synchronization is enabled.");
631 // case: when - startup sync is misconfigured or is disabled
632 // - give a clue to user when is the next periodic sync
633 if (!syncConfig.isConfigOkForStartupSync()
634 || syncConfig.isConfigDisabledForInitialSync()) {
635 LOG.info(AaiUiMsgs.SYNC_TO_BEGIN, syncController.getControllerName(),
636 sdf.format(timeNextSync).replaceAll(SynchronizerConstants.TIME_STD,
637 SynchronizerConstants.TIME_CONFIG_STD));
640 LOG.info(AaiUiMsgs.INFO_GENERIC, "Search Engine periodic synchronization is disabled.");
644 // schedule periodic synchronization
645 if (syncConfig.isHistoricalEntitySummarizerEnabled()) {
646 scheduleHistoricalCounterSyncTask();
649 } catch (Exception exc) {
650 String message = "Caught an exception while starting up the SyncHelper. Error cause = \n"
651 + ErrorUtil.extractStackTraceElements(5, exc);
652 LOG.error(AaiUiMsgs.ERROR_GENERIC, message);
657 * Schedule historical counter sync task.
659 private void scheduleHistoricalCounterSyncTask() {
660 long taskFrequencyInMs =
661 syncConfig.getHistoricalEntitySummarizedFrequencyInMinutes() * 60 * 1000;
662 historicalExecutor.scheduleWithFixedDelay(new HistoricalEntityCountSummaryTask(), 0,
663 taskFrequencyInMs, TimeUnit.MILLISECONDS);
664 LOG.info(AaiUiMsgs.INFO_GENERIC,
665 "Historical Entity Count Summarizer synchronization is enabled.");
671 public void shutdown() {
673 if (oneShotExecutor != null) {
674 oneShotExecutor.shutdown();
677 if (periodicExecutor != null) {
678 periodicExecutor.shutdown();
681 if (historicalExecutor != null) {
682 historicalExecutor.shutdown();
685 if (syncController != null) {
686 syncController.shutdown();
689 if (entityCounterHistorySummarizer != null) {
690 entityCounterHistorySummarizer.shutdown();
695 public OxmModelLoader getOxmModelLoader() {
696 return oxmModelLoader;
699 public void setOxmModelLoader(OxmModelLoader oxmModelLoader) {
700 this.oxmModelLoader = oxmModelLoader;