private void updateTrackedResources(ApplicationId appId, boolean track) { if (intentService == null) { log.warn("Intent service is not bound yet"); return; } intentService .getIntents() .forEach( intent -> { if (intent.appId().equals(appId)) { Key key = intent.key(); Collection<NetworkResource> resources = Lists.newArrayList(); intentService .getInstallableIntents(key) .stream() .map(installable -> installable.resources()) .forEach(resources::addAll); if (track) { addTrackedResources(key, resources); } else { removeTrackedResources(key, resources); } } }); }
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); } }
@Deactivate public void deactivate() { store.unsetDelegate(delegate); eventDispatcher.removeSink(VirtualNetworkEvent.class); intentService.removeListener(intentListener); log.info("Stopped"); }
@Activate public void activate() { store.setDelegate(delegate); eventDispatcher.addSink(VirtualNetworkEvent.class, listenerRegistry); intentService.addListener(intentListener); log.info("Started"); }
/** * Checks both that the number of intents in submitted in the intent framework it's equal to the * number of intents expected and that all intents are equivalent. * * @param intents the list of intents expected */ private void checkIntents(List<Intent> intents) { assertEquals(intents.size(), intentService.getIntentCount()); for (Intent intentOne : intents) { boolean found = false; for (Intent intentTwo : intentService.getIntents()) { if (intentOne.key().equals(intentTwo.key())) { found = true; assertTrue( format("Comparing %s and %s", intentOne, intentTwo), IntentUtils.intentsAreEqual(intentOne, intentTwo)); break; } } assertTrue(found); } }
/** * Creates an intent from a POST of a JSON string and attempts to apply it. * * @param stream input JSON * @return status of the request - CREATED if the JSON is correct, BAD_REQUEST if the JSON is * invalid */ @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public Response createIntent(InputStream stream) { try { IntentService service = get(IntentService.class); ObjectNode root = (ObjectNode) mapper().readTree(stream); Intent intent = codec(Intent.class).decode(root, this); service.submit(intent); UriBuilder locationBuilder = uriInfo .getBaseUriBuilder() .path("intents") .path(Short.toString(intent.appId().id())) .path(Long.toString(intent.id().fingerprint())); return Response.created(locationBuilder.build()).build(); } catch (IOException ioe) { throw new IllegalArgumentException(ioe); } }
@Override protected void execute() { IntentService intentService = get(IntentService.class); CoreService coreService = get(CoreService.class); ApplicationId appId = appId(); if (!isNullOrEmpty(applicationIdString)) { appId = coreService.getAppId(applicationIdString); if (appId == null) { print("Cannot find application Id %s", applicationIdString); return; } } if (isNullOrEmpty(keyString)) { for (Intent intent : intentService.getIntents()) { if (intent.appId().equals(appId)) { removeIntent(intentService, intent); } } } else { final Key key; if (keyString.startsWith("0x")) { // The intent uses a LongKey keyString = keyString.replaceFirst("0x", ""); key = Key.of(new BigInteger(keyString, 16).longValue(), appId); } else { // The intent uses a StringKey key = Key.of(keyString, appId); } Intent intent = intentService.getIntent(key); if (intent != null) { removeIntent(intentService, intent); } } }
/** * 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); } }
protected void doIntentUpdate() { updateScheduled.set(false); if (intentService == null) { log.warn("Intent service is not bound yet"); return; } try { // FIXME very inefficient for (IntentData intentData : intentService.getIntentData()) { try { trackIntent(intentData); } catch (NullPointerException npe) { log.warn("intent error {}", intentData.key(), npe); } } } catch (Exception e) { log.warn("Exception caught during update task", e); } }
@Override public void trackIntent(IntentData intentData) { // NOTE: This will be called for intents that are being added to the store // locally (i.e. every intent update) Key key = intentData.key(); Intent intent = intentData.intent(); boolean isLocal = intentService.isLocal(key); boolean isInstalled = intentData.state() == INSTALLING || intentData.state() == INSTALLED; List<Intent> installables = intentData.installables(); if (log.isTraceEnabled()) { log.trace( "intent {}, old: {}, new: {}, installableCount: {}, resourceCount: {}", key, intentsByDevice.values().contains(key), isLocal && isInstalled, installables.size(), intent.resources().size() + installables.stream().mapToLong(i -> i.resources().size()).sum()); } if (isNullOrEmpty(installables) && intentData.state() == INSTALLED) { log.warn("Intent {} is INSTALLED with no installables", key); } // FIXME Intents will be added 3 times (once directly using addTracked, // then when installing and when installed) if (isLocal && isInstalled) { addTrackedResources(key, intent.resources()); for (Intent installable : installables) { addTrackedResources(key, installable.resources()); } // FIXME check all resources against current topo service(s); recompile if necessary } else { removeTrackedResources(key, intent.resources()); for (Intent installable : installables) { removeTrackedResources(key, installable.resources()); } } }
@Override public void withdraw(Intent intent) { intentService.withdraw(intent); }
@Override public void submit(Intent intent) { intentService.submit(intent); }