Madan Jampani
Committed by Gerrit Code Review

Ensure ApplicationManager waits until features are installed/uninstalled

Change-Id: Ie86c7945d8707cac6ef869e0b28bb950744ea708
...@@ -47,6 +47,7 @@ import java.io.InputStream; ...@@ -47,6 +47,7 @@ import java.io.InputStream;
47 import java.util.Set; 47 import java.util.Set;
48 import java.util.concurrent.CountDownLatch; 48 import java.util.concurrent.CountDownLatch;
49 import java.util.concurrent.TimeUnit; 49 import java.util.concurrent.TimeUnit;
50 +import java.util.function.Consumer;
50 51
51 import static com.google.common.base.Preconditions.checkNotNull; 52 import static com.google.common.base.Preconditions.checkNotNull;
52 import static org.onosproject.app.ApplicationEvent.Type.APP_ACTIVATED; 53 import static org.onosproject.app.ApplicationEvent.Type.APP_ACTIVATED;
...@@ -83,7 +84,7 @@ public class ApplicationManager ...@@ -83,7 +84,7 @@ public class ApplicationManager
83 84
84 // Application supplied hooks for pre-activation processing. 85 // Application supplied hooks for pre-activation processing.
85 private final Multimap<String, Runnable> deactivateHooks = HashMultimap.create(); 86 private final Multimap<String, Runnable> deactivateHooks = HashMultimap.create();
86 - private final Cache<ApplicationId, CountDownLatch> pendingUninstalls = 87 + private final Cache<ApplicationId, CountDownLatch> pendingOperations =
87 CacheBuilder.newBuilder() 88 CacheBuilder.newBuilder()
88 .expireAfterWrite(DEFAULT_OPERATION_TIMEOUT_MILLIS * 2, TimeUnit.MILLISECONDS) 89 .expireAfterWrite(DEFAULT_OPERATION_TIMEOUT_MILLIS * 2, TimeUnit.MILLISECONDS)
89 .build(); 90 .build();
...@@ -160,15 +161,7 @@ public class ApplicationManager ...@@ -160,15 +161,7 @@ public class ApplicationManager
160 public void uninstall(ApplicationId appId) { 161 public void uninstall(ApplicationId appId) {
161 checkNotNull(appId, APP_ID_NULL); 162 checkNotNull(appId, APP_ID_NULL);
162 CountDownLatch latch = new CountDownLatch(1); 163 CountDownLatch latch = new CountDownLatch(1);
163 - try { 164 + updateStoreAndWaitForNotificationHandling(appId, store::remove);
164 - pendingUninstalls.put(appId, latch);
165 - store.remove(appId);
166 - } catch (Exception e) {
167 - pendingUninstalls.invalidate(appId);
168 - latch.countDown();
169 - log.warn("Unable to purge application directory for {}", appId.name());
170 - }
171 - Uninterruptibles.awaitUninterruptibly(latch, DEFAULT_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
172 } 165 }
173 166
174 @Override 167 @Override
...@@ -177,13 +170,13 @@ public class ApplicationManager ...@@ -177,13 +170,13 @@ public class ApplicationManager
177 if (!SecurityUtil.isAppSecured(appId)) { 170 if (!SecurityUtil.isAppSecured(appId)) {
178 return; 171 return;
179 } 172 }
180 - store.activate(appId); 173 + updateStoreAndWaitForNotificationHandling(appId, store::activate);
181 } 174 }
182 175
183 @Override 176 @Override
184 public void deactivate(ApplicationId appId) { 177 public void deactivate(ApplicationId appId) {
185 checkNotNull(appId, APP_ID_NULL); 178 checkNotNull(appId, APP_ID_NULL);
186 - store.deactivate(appId); 179 + updateStoreAndWaitForNotificationHandling(appId, store::deactivate);
187 } 180 }
188 181
189 @Override 182 @Override
...@@ -193,12 +186,26 @@ public class ApplicationManager ...@@ -193,12 +186,26 @@ public class ApplicationManager
193 store.setPermissions(appId, permissions); 186 store.setPermissions(appId, permissions);
194 } 187 }
195 188
189 + private void updateStoreAndWaitForNotificationHandling(ApplicationId appId,
190 + Consumer<ApplicationId> storeUpdateTask) {
191 + CountDownLatch latch = new CountDownLatch(1);
192 + try {
193 + pendingOperations.put(appId, latch);
194 + storeUpdateTask.accept(appId);
195 + } catch (Exception e) {
196 + pendingOperations.invalidate(appId);
197 + latch.countDown();
198 + log.warn("Failed to update store for {}", appId.name(), e);
199 + }
200 + Uninterruptibles.awaitUninterruptibly(latch, DEFAULT_OPERATION_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
201 + }
202 +
196 private class InternalStoreDelegate implements ApplicationStoreDelegate { 203 private class InternalStoreDelegate implements ApplicationStoreDelegate {
197 @Override 204 @Override
198 public void notify(ApplicationEvent event) { 205 public void notify(ApplicationEvent event) {
199 ApplicationEvent.Type type = event.type(); 206 ApplicationEvent.Type type = event.type();
200 Application app = event.subject(); 207 Application app = event.subject();
201 - CountDownLatch latch = pendingUninstalls.getIfPresent(app.id()); 208 + CountDownLatch latch = pendingOperations.getIfPresent(app.id());
202 try { 209 try {
203 if (type == APP_ACTIVATED) { 210 if (type == APP_ACTIVATED) {
204 if (installAppFeatures(app)) { 211 if (installAppFeatures(app)) {
...@@ -227,7 +234,7 @@ public class ApplicationManager ...@@ -227,7 +234,7 @@ public class ApplicationManager
227 } finally { 234 } finally {
228 if (latch != null) { 235 if (latch != null) {
229 latch.countDown(); 236 latch.countDown();
230 - pendingUninstalls.invalidate(app.id()); 237 + pendingOperations.invalidate(app.id());
231 } 238 }
232 } 239 }
233 } 240 }
......