bf78e6a60713260058c62d2fe36fdd605caf7daa
[aai/sparky-be.git] / src / main / java / org / onap / aai / sparky / sync / SyncControllerService.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017-2018 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
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
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=========================================================
20  */
21 package org.onap.aai.sparky.sync;
22
23 import java.lang.Thread.UncaughtExceptionHandler;
24 import java.util.concurrent.ExecutorService;
25 import java.util.concurrent.Executors;
26 import java.util.concurrent.ScheduledExecutorService;
27 import java.util.concurrent.TimeUnit;
28
29 import org.onap.aai.cl.api.Logger;
30 import org.onap.aai.cl.eelf.LoggerFactory;
31 import org.onap.aai.sparky.logging.AaiUiMsgs;
32 import org.onap.aai.sparky.sync.SyncControllerImpl.SyncActions;
33 import org.onap.aai.sparky.sync.enumeration.OperationState;
34 import org.onap.aai.sparky.sync.enumeration.SynchronizerState;
35 import org.springframework.context.ApplicationListener;
36 import org.springframework.context.event.ApplicationContextEvent;
37
38 import com.google.common.util.concurrent.ThreadFactoryBuilder;
39
40 public class SyncControllerService implements ApplicationListener<ApplicationContextEvent> {
41
42   private SyncControllerRegistry syncControllerRegistry;
43   private ExecutorService runonceSyncExecutor;
44   private ScheduledExecutorService periodicSyncExecutor;
45   private boolean syncStarted;
46
47   private static final Logger LOG =
48       LoggerFactory.getInstance().getLogger(SyncControllerService.class);
49
50   private class SyncControllerTask implements Runnable {
51
52     private SyncController controller;
53
54     public SyncControllerTask(SyncController controller) {
55       this.controller = controller;
56     }
57
58     @Override
59     public void run() {
60
61       try {
62
63         if (controller.getState() == SynchronizerState.IDLE) {
64
65           /*
66            * This is a blocking-call, but would be nicer if it was async internally within the
67            * controller but at the moment, that's not the way it works.
68            */
69
70           if (controller.performAction(SyncActions.SYNCHRONIZE) != OperationState.OK) {
71
72             LOG.info(AaiUiMsgs.INFO_GENERIC,
73                 controller.getControllerName() + " is not idle, sync attempt has been skipped.");
74           }
75         } else {
76
77           LOG.info(AaiUiMsgs.INFO_GENERIC,
78               controller.getControllerName() + " is not idle, sync attempt has been skipped.");
79         }
80
81       } catch (Exception exception) {
82         LOG.error(AaiUiMsgs.ERROR_GENERIC,
83             "Error while attempting synchronization.  Error = " + exception.getMessage());
84       }
85
86     }
87
88   }
89
90   public SyncControllerService(SyncControllerRegistry syncControllerRegistry, int numRunOnceWorkers,
91       int numPeriodicWorkers) {
92     this.syncControllerRegistry = syncControllerRegistry;
93     this.syncStarted = false;
94
95     UncaughtExceptionHandler uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
96
97       @Override
98       public void uncaughtException(Thread thread, Throwable exc) {
99         LOG.error(AaiUiMsgs.ERROR_GENERIC, thread.getName() + ": " + exc);
100       }
101     };
102
103     runonceSyncExecutor = Executors.newFixedThreadPool(numRunOnceWorkers,
104         new ThreadFactoryBuilder().setNameFormat("RunonceSyncWorker-%d")
105             .setUncaughtExceptionHandler(uncaughtExceptionHandler).build());
106
107
108     periodicSyncExecutor = Executors.newScheduledThreadPool(numPeriodicWorkers,
109         new ThreadFactoryBuilder().setNameFormat("PeriodicSyncWorker-%d")
110             .setUncaughtExceptionHandler(uncaughtExceptionHandler).build());
111
112   }
113
114   public SyncControllerRegistry getSyncControllerRegistry() {
115     return syncControllerRegistry;
116   }
117
118   public void startSync() {
119
120     long syncInitialDelayInMs = 0;
121
122     for (SyncController controller : syncControllerRegistry.getControllers()) {
123
124       syncInitialDelayInMs = controller.getDelayInMs();
125
126       if (!controller.isPeriodicSyncEnabled()) {
127
128         if (controller.isRunOnceSyncEnabled()) {
129           LOG.info(AaiUiMsgs.INFO_GENERIC, controller.getControllerName() + " is enabled.");
130           runonceSyncExecutor.submit(new SyncControllerTask(controller));
131         } else {
132           LOG.info(AaiUiMsgs.INFO_GENERIC, controller.getControllerName() + " is disabled.");
133         }
134
135       } else {
136
137         /**
138          * Do both. We'll take one instance of the SyncController and wrap the object instance into
139          * two SyncControllerTasks. The responsibility for preventing a conflicting sync should live
140          * in the SyncController instance. If a sync is underway when the periodic sync kicks in,
141          * then it will be ignored by the SyncController which is already underway.
142          * 
143          * The SyncController instance itself would then also be stateful such that it would know
144          * the last time it ran, and the next time it is supposed to run, the number times a sync
145          * has executed, etc.
146          */
147
148         if (controller.isRunOnceSyncEnabled()) {
149           LOG.info(AaiUiMsgs.INFO_GENERIC,
150               controller.getControllerName() + " run-once sync is enabled.");
151           runonceSyncExecutor.submit(new SyncControllerTask(controller));
152         } else {
153           LOG.info(AaiUiMsgs.INFO_GENERIC,
154               controller.getControllerName() + " run-once sync is disabled.");
155         }
156
157         /*
158          * The controller knows it's configuredfrequency and we can just ask it to tell us what the
159          * delay and frequency needs to be, rather than trying to calculate the configured frequency
160          * per controller which "could" be different for each controller.
161          */
162
163         if (controller.isPeriodicSyncEnabled()) {
164
165           LOG.info(AaiUiMsgs.INFO_GENERIC,
166               controller.getControllerName() + " periodic sync is enabled and scheduled to start @ "
167                   + controller.getNextSyncTime());
168
169           periodicSyncExecutor.scheduleAtFixedRate(new SyncControllerTask(controller),
170               controller.getDelayInMs(), controller.getSyncFrequencyInMs(), TimeUnit.MILLISECONDS);
171
172         } else {
173
174           LOG.info(AaiUiMsgs.INFO_GENERIC,
175               controller.getControllerName() + " periodic sync is disabled.");
176
177         }
178
179       }
180
181     }
182
183   }
184
185   public void shutdown() {
186
187     if (runonceSyncExecutor != null) {
188       runonceSyncExecutor.shutdown();
189     }
190
191     if (periodicSyncExecutor != null) {
192       periodicSyncExecutor.shutdown();
193     }
194
195     if (syncControllerRegistry != null) {
196       for (SyncController controller : syncControllerRegistry.getControllers()) {
197         controller.shutdown();
198       }
199     }
200
201   }
202
203   @Override
204   public synchronized void onApplicationEvent(ApplicationContextEvent arg0) {
205
206     /*
207      * Start sync service processing when spring-context-initialization has finished
208      */
209     
210     if (!syncStarted) {
211       syncStarted = true;
212       startSync();
213     }
214
215   }
216
217
218 }