/** * Subscribe to a given USK. Callback will be notified when it is updated. Note that this does not * imply that the USK will be checked on a regular basis, unless runBackgroundFetch=true. */ public void subscribe( USK origUSK, USKCallback cb, boolean runBackgroundFetch, boolean ignoreUSKDatehints, RequestClient client) { if (logMINOR) Logger.minor(this, "Subscribing to " + origUSK + " for " + cb); if (client.persistent()) throw new UnsupportedOperationException("USKManager subscriptions cannot be persistent"); USKFetcher sched = null; long ed = origUSK.suggestedEdition; if (ed < 0) { Logger.error(this, "Subscribing to USK with negative edition number: " + ed); ed = -ed; } long curEd; curEd = lookupLatestSlot(origUSK); long goodEd; goodEd = lookupKnownGood(origUSK); synchronized (this) { USK clear = origUSK.clearCopy(); USKCallback[] callbacks = subscribersByClearUSK.get(clear); if (callbacks == null) { callbacks = new USKCallback[] {cb}; } else { boolean mustAdd = true; for (USKCallback callback : callbacks) { if (callback == cb) { // Already subscribed. // But it may still be waiting for the callback. if (!(curEd > ed || goodEd > ed)) return; mustAdd = false; } } if (mustAdd) { callbacks = Arrays.copyOf(callbacks, callbacks.length + 1); callbacks[callbacks.length - 1] = cb; } } subscribersByClearUSK.put(clear, callbacks); if (runBackgroundFetch) { USKFetcher f = backgroundFetchersByClearUSK.get(clear); if (f == null) { f = new USKFetcher( origUSK, this, ignoreUSKDatehints ? backgroundFetchContextIgnoreDBR : backgroundFetchContext, new USKFetcherWrapper(origUSK, RequestStarter.UPDATE_PRIORITY_CLASS, client), 3, true, false, false); sched = f; backgroundFetchersByClearUSK.put(clear, f); } f.addSubscriber(cb, origUSK.suggestedEdition); } } if (goodEd > ed) cb.onFoundEdition( goodEd, origUSK.copy(curEd), null, context, false, (short) -1, null, true, curEd > ed); else if (curEd > ed) cb.onFoundEdition( curEd, origUSK.copy(curEd), null, context, false, (short) -1, null, false, false); final USKFetcher fetcher = sched; if (fetcher != null) { executor.execute( new Runnable() { @Override public void run() { if (logMINOR) Logger.minor(this, "Starting " + fetcher); fetcher.schedule(null, context); } }, "USKManager.schedule for " + fetcher); } }