com.arm.mbed.cloud.sdk.connect.subscription.NotificationHandlersStore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mbed-cloud-sdk Show documentation
Show all versions of mbed-cloud-sdk Show documentation
The Pelion Cloud SDK (formerly known as Mbed Cloud SDK) provides a simplified interface to the Pelion Cloud APIs by exposing functionality using conventions and paradigms familiar to Java developers.
package com.arm.mbed.cloud.sdk.connect.subscription;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import com.arm.mbed.cloud.sdk.annotations.Internal;
import com.arm.mbed.cloud.sdk.annotations.Nullable;
import com.arm.mbed.cloud.sdk.annotations.Preamble;
import com.arm.mbed.cloud.sdk.common.AbstractModule;
import com.arm.mbed.cloud.sdk.common.Callback;
import com.arm.mbed.cloud.sdk.common.CloudCaller;
import com.arm.mbed.cloud.sdk.common.CloudCaller.CallFeedback;
import com.arm.mbed.cloud.sdk.common.CloudRequest.CloudCall;
import com.arm.mbed.cloud.sdk.common.GenericAdapter;
import com.arm.mbed.cloud.sdk.common.GenericAdapter.Mapper;
import com.arm.mbed.cloud.sdk.common.MbedCloudException;
import com.arm.mbed.cloud.sdk.common.SdkLogger;
import com.arm.mbed.cloud.sdk.common.TimePeriod;
import com.arm.mbed.cloud.sdk.connect.model.EndPoints;
import com.arm.mbed.cloud.sdk.connect.model.Resource;
import com.arm.mbed.cloud.sdk.lowlevel.pelionclouddevicemanagement.model.NotificationMessage;
import com.arm.mbed.cloud.sdk.subscribe.CloudSubscriptionManager;
import com.arm.mbed.cloud.sdk.subscribe.NotificationCallback;
import com.arm.mbed.cloud.sdk.subscribe.NotificationMessageValue;
import com.arm.mbed.cloud.sdk.subscribe.SubscriptionType;
import com.arm.mbed.cloud.sdk.subscribe.adapters.AsynchronousResponseNotificationAdapter;
import com.arm.mbed.cloud.sdk.subscribe.adapters.DeviceStateNotificationAdapter;
import com.arm.mbed.cloud.sdk.subscribe.adapters.ResourceValueNotificationAdapter;
import com.arm.mbed.cloud.sdk.subscribe.model.AsynchronousResponseObserver;
import com.arm.mbed.cloud.sdk.subscribe.model.FirstValue;
import com.arm.mbed.cloud.sdk.subscribe.model.ResourceValueNotification;
import com.arm.mbed.cloud.sdk.subscribe.store.SubscriptionObserversStore;
import retrofit2.Call;
@Preamble(description = "Internal store for notification handlers")
@Internal
public class NotificationHandlersStore implements Closeable {
private static final int IDLE_TIME_BETWEEN_NOTIFICATION_PULL_CALLS = 50;
private static final TimePeriod REQUEST_TIMEOUT = new TimePeriod(50);
private final AbstractModule module;
private final ExecutorService pullThreads;
private Future> pullHandle;
private final EndPoints endpoint;
private final ExecutorService customSubscriptionHandlingExecutor;
private final SubscriptionObserversStore observerStore;
/**
* Notification store constructor.
*
* @param module
* API module
* @param pullingThread
* thread pool
* @param endpoint
* endpoint
* @param subscriptionHandlingExecutor
* subscription handling executor
*/
public NotificationHandlersStore(AbstractModule module, ExecutorService pullingThread,
ExecutorService subscriptionHandlingExecutor, EndPoints endpoint) {
super();
this.pullThreads = pullingThread;
this.endpoint = createNotificationPull(endpoint);
this.module = module;
pullHandle = null;
customSubscriptionHandlingExecutor = subscriptionHandlingExecutor;
final boolean unsubscribeOnExit = module == null ? false
: module.getConnectionOption() == null ? true
: !module.getConnectionOption()
.isSkipCleanup();
observerStore = new SubscriptionObserversStore((customSubscriptionHandlingExecutor == null) ? Schedulers.computation()
: Schedulers.from(customSubscriptionHandlingExecutor),
new ResourceSubscriber(module, FirstValue.getDefault()),
new ResourceUnsubscriber(module, FirstValue.getDefault()),
unsubscribeOnExit ? new ResourceUnsubscriberAll(module,
FirstValue.getDefault())
: null);
}
private EndPoints createNotificationPull(EndPoints endpoint2) {
if (endpoint2 == null) {
return null;
}
final EndPoints clone = endpoint2.clone();
clone.setRequestTimeout(REQUEST_TIMEOUT);
return clone;
}
public CloudSubscriptionManager getSubscriptionManager() {
return observerStore;
}
/**
* Starts notification listener.
*/
public void startNotificationListener() {
if (isPullingActive()) {
logInfo("Notification pull is already working.");
return;
}
final Runnable pollingSingleAction = createPollingSingleAction();
pullHandle = null;
if (pullThreads instanceof ScheduledExecutorService) {
pullHandle = ((ScheduledExecutorService) pullThreads).scheduleWithFixedDelay(pollingSingleAction, 0,
IDLE_TIME_BETWEEN_NOTIFICATION_PULL_CALLS,
TimeUnit.MILLISECONDS);
} else {
pullHandle = pullThreads.submit(new Runnable() {
@Override
public void run() {
while (true) {
pollingSingleAction.run();
try {
// Sleeping between calls
Thread.sleep(IDLE_TIME_BETWEEN_NOTIFICATION_PULL_CALLS);
} catch (InterruptedException exception) {
logPullError(exception);
}
}
}
});
}
}
/**
* Stops notification listener.
*/
public void stopNotificationListener() {
if (pullHandle != null && !(pullHandle.isDone() || pullHandle.isCancelled())) {
pullHandle.cancel(true);
}
pullHandle = null;
}
/**
* States whether pulling is currently on going.
*
* @return true if pulling is active. false otherwise.
*/
public boolean isPullingActive() {
return pullHandle != null;
}
/**
* Shuts down the store and the thread pool it uses.
*/
public void shutdown() {
logDebug("Shutting down polling thread");
if (pullThreads != null) {
pullThreads.shutdown();
}
logDebug("Clearing notification handler store");
try {
clearStores();
} catch (Exception exception) {
logError("Failed clearing notification handler store", exception);
}
logDebug("Shutting down notification threads");
if (customSubscriptionHandlingExecutor != null) {
customSubscriptionHandlingExecutor.shutdown();
}
// shutting down schedulers can have side effects
// logDebug("Shutting down notification schedulers");
// try {
// Schedulers.shutdown();
// } catch (Exception exception) {
// logError("Failed shutting down notification schedulers", exception);
// }
}
protected void logDebug(String message) {
final SdkLogger logger = module == null ? null : module.getLogger();
if (logger != null) {
logger.logDebug(message);
}
}
protected void logError(String message, Exception exception) {
final SdkLogger logger = module == null ? null : module.getLogger();
if (logger != null) {
logger.logError(message, exception);
}
}
protected void logInfo(String message) {
final SdkLogger logger = module == null ? null : module.getLogger();
if (logger != null) {
logger.logInfo(message);
}
}
/**
* Registers resource subscription callback.
*
* @param resource
* resource to register the callback for.
* @param onNotification
* callback to execute on notification.
* @param onFailure
* callback to execute on error.
*/
public void registerSubscriptionCallback(Resource resource, Callback