Since Lightstreamer Server 7.1 the Java In-Process Adapter SDK (SDK version 7.2.0) features the possibility to forcibly interrupt a client subscription from the Metadata Adapter.
This may be needed, for instance, when the authorization granted to a client for a subscription request is meant to be limited in time.
In practice, from Metadata Adapter code, after authorizing a subscription request from the
notifyNewTablescallback, you can keep the
TableInfo object received; then, later, you can invoke
forceUnsubscription on this object to close the subscription.
This behaves as though the unsubscription was requested by the client. The client is also notified of the unsubscription as though it had been requested by itself.
The following snippet of Metadata Adapter code exemplifies how you can enforce termination for a subscription that, for instance, has lasted for more than five minutes.
[SYNTAX="JAVA"]
......................
private final Map<String, TableInfo> concurrentSubscrSet = new ConcurrentHashMap<>();
private static final ScheduledExecutorService expirationChecker = Executors.newScheduledThreadPool(1);
private final int expiryTimeMinutes = 5;
private static String getSubscrKey(String sessionID, TableInfo table) {
return sessionID + "." + table.getWinIndex();
// NOTE: a subscription is uniquely identified, within its session, by the "win index";
// we oversimplify the example here, by joining the two to get a key,
// as neither session IDs nor win indexes contain dots.
}
@Override
public boolean wantsTablesNotification(String user) {
return true;
}
@Override
public void notifyNewTables(String user, String sessionID, TableInfo[] tables)
throws CreditsException, NotificationException {
if (tables.length != 1) {
throw new NotificationException("Unexpected old-style subscription request: unsupported");
}
String subscrKey = getSubscrKey(sessionID, tables[0]);
concurrentSubscrSet.put(subscrKey, tables[0]);
expirationChecker.schedule(() -> {
TableInfo stillActiveTable = concurrentSubscrSet.get(subscrKey);
if (stillActiveTable != null) {
stillActiveTable.forceUnsubscription();
}
}, expiryTimeMinutes, TimeUnit.MINUTES);
}
@Override
public void notifyTablesClose(String sessionID, TableInfo[] tables) throws NotificationException {
assert tables.length == 1;
String subscrKey = getSubscrKey(sessionID, tables[0]);
concurrentSubscrSet.remove(subscrKey);
}
......................
[/SYNTAX]
Note that implementing
notifyNewTablesto accept the subscription is a necessary preconditions. Hence implementing
wantsTablesNotification and returning
true is also necessary.
Also note that subscriptions are performed in "tables", i.e. groups of items for which the same field schema is specified.
As a consequence, enforced unsubscriptions are also performed on such tables as a whole, exactly like client unsubscription requests.
If enforced unsubscriptions with the scope of single items are needed in your application, ensure that the client subscribes to such items singularly (and check in
notifyNewTables that this condition is met, by refusing any attempt to do otherwise).
As for the Remote Adapter SDKs, this feature has been ported to the Java Remote and Generic Adapter SDKs, but this requires Server version 7.3 or later; it has not been ported to the other Remote Adapter SDKs yet.