private void removeIntent(IntentService intentService, Intent intent) { IntentListener listener = null; Key key = intent.key(); final CountDownLatch withdrawLatch, purgeLatch; if (purgeAfterRemove || sync) { // set up latch and listener to track uninstall progress withdrawLatch = new CountDownLatch(1); purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null; listener = (IntentEvent event) -> { if (Objects.equals(event.subject().key(), key)) { if (event.type() == IntentEvent.Type.WITHDRAWN || event.type() == IntentEvent.Type.FAILED) { withdrawLatch.countDown(); } else if (purgeAfterRemove && event.type() == IntentEvent.Type.PURGED) { purgeLatch.countDown(); } } }; intentService.addListener(listener); } else { purgeLatch = null; withdrawLatch = null; } // request the withdraw intentService.withdraw(intent); if (purgeAfterRemove || sync) { try { // wait for withdraw event withdrawLatch.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { print("Timed out waiting for intent {} withdraw", key); } // double check the state IntentState state = intentService.getIntentState(key); if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) { intentService.purge(intent); } if (sync) { // wait for purge event /* TODO Technically, the event comes before map.remove() is called. If we depend on sync and purge working together, we will need to address this. */ try { purgeLatch.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { print("Timed out waiting for intent {} purge", key); } } } if (listener != null) { // clean up the listener intentService.removeListener(listener); } }
/** * Uninstalls a single intent by Id. * * @param appId the Application ID * @param keyString the Intent key value to look up */ @DELETE @Path("{appId}/{key}") public void deleteIntentById( @PathParam("appId") String appId, @PathParam("key") String keyString) { final ApplicationId app = get(CoreService.class).getAppId(appId); Intent intent = get(IntentService.class).getIntent(Key.of(keyString, app)); IntentService service = get(IntentService.class); if (intent == null) { intent = service.getIntent(Key.of(Long.decode(keyString), app)); } if (intent == null) { // No such intent. REST standards recommend a positive status code // in this case. return; } Key key = intent.key(); // set up latch and listener to track uninstall progress CountDownLatch latch = new CountDownLatch(1); IntentListener listener = new DeleteListener(key, latch); service.addListener(listener); try { // request the withdraw service.withdraw(intent); try { latch.await(WITHDRAW_EVENT_TIMEOUT_SECONDS, TimeUnit.SECONDS); } catch (InterruptedException e) { log.info("REST Delete operation timed out waiting for intent {}", key); } // double check the state IntentState state = service.getIntentState(key); if (state == WITHDRAWN || state == FAILED) { service.purge(intent); } } finally { // clean up the listener service.removeListener(listener); } }