All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.leshan.server.californium.LeshanServer Maven / Gradle / Ivy

There is a newer version: 2.0.0-M15
Show newest version
/*******************************************************************************
 * Copyright (c) 2013-2015 Sierra Wireless and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 * 
 * The Eclipse Public License is available at
 *    http://www.eclipse.org/legal/epl-v10.html
 * and the Eclipse Distribution License is available at
 *    http://www.eclipse.org/org/documents/edl-v10.html.
 * 
 * Contributors:
 *     Sierra Wireless - initial API and implementation
 *     RISE SICS AB - added Queue Mode operation
 *******************************************************************************/
package org.eclipse.leshan.server.californium;

import java.net.InetSocketAddress;
import java.util.Collection;

import org.eclipse.californium.core.CoapResource;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.Endpoint;
import org.eclipse.californium.core.network.config.NetworkConfig;
import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.leshan.core.californium.CoapResponseCallback;
import org.eclipse.leshan.core.node.codec.CodecException;
import org.eclipse.leshan.core.node.codec.LwM2mNodeDecoder;
import org.eclipse.leshan.core.node.codec.LwM2mNodeEncoder;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.request.DownlinkRequest;
import org.eclipse.leshan.core.request.exception.ClientSleepingException;
import org.eclipse.leshan.core.request.exception.InvalidResponseException;
import org.eclipse.leshan.core.request.exception.RequestCanceledException;
import org.eclipse.leshan.core.request.exception.RequestRejectedException;
import org.eclipse.leshan.core.request.exception.SendFailedException;
import org.eclipse.leshan.core.request.exception.TimeoutException;
import org.eclipse.leshan.core.response.ErrorCallback;
import org.eclipse.leshan.core.response.LwM2mResponse;
import org.eclipse.leshan.core.response.ResponseCallback;
import org.eclipse.leshan.server.Destroyable;
import org.eclipse.leshan.server.Startable;
import org.eclipse.leshan.server.Stoppable;
import org.eclipse.leshan.server.californium.observation.ObservationServiceImpl;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.californium.registration.RegisterResource;
import org.eclipse.leshan.server.californium.request.CaliforniumLwM2mRequestSender;
import org.eclipse.leshan.server.californium.request.CaliforniumQueueModeRequestSender;
import org.eclipse.leshan.server.californium.request.CoapRequestSender;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.observation.ObservationService;
import org.eclipse.leshan.server.queue.ClientAwakeTimeProvider;
import org.eclipse.leshan.server.queue.PresenceListener;
import org.eclipse.leshan.server.queue.PresenceService;
import org.eclipse.leshan.server.queue.PresenceServiceImpl;
import org.eclipse.leshan.server.queue.PresenceStateListener;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.registration.RegistrationHandler;
import org.eclipse.leshan.server.registration.RegistrationIdProvider;
import org.eclipse.leshan.server.registration.RegistrationListener;
import org.eclipse.leshan.server.registration.RegistrationService;
import org.eclipse.leshan.server.registration.RegistrationServiceImpl;
import org.eclipse.leshan.server.registration.RegistrationStore;
import org.eclipse.leshan.server.registration.RegistrationUpdate;
import org.eclipse.leshan.server.request.LwM2mRequestSender;
import org.eclipse.leshan.server.security.Authorizer;
import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.SecurityInfo;
import org.eclipse.leshan.server.security.SecurityStore;
import org.eclipse.leshan.server.security.SecurityStoreListener;
import org.eclipse.leshan.util.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A Lightweight M2M server.
 * 

* This implementation starts a Californium {@link CoapServer} with a unsecured (for coap://) and secured endpoint (for * coaps://). This CoAP server defines a /rd resource as described in the LWM2M specification. *

* This class is the entry point to send synchronous and asynchronous requests to registered clients. *

* The {@link LeshanServerBuilder} should be the preferred way to build an instance of {@link LeshanServer}. */ public class LeshanServer { private static final Logger LOG = LoggerFactory.getLogger(LeshanServer.class); // We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to // send a Confirmable message to the time when an acknowledgement is no longer expected. private static final long DEFAULT_TIMEOUT = 2 * 60 * 1000l; // 2min in ms // CoAP/Californium attributes private final CoapAPI coapApi; private final CoapServer coapServer; private final CoapEndpoint unsecuredEndpoint; private final CoapEndpoint securedEndpoint; // LWM2M attributes private final RegistrationServiceImpl registrationService; private final CaliforniumRegistrationStore registrationStore; private final ObservationServiceImpl observationService; private final SecurityStore securityStore; private final LwM2mModelProvider modelProvider; private final PresenceServiceImpl presenceService; private final LwM2mRequestSender requestSender; /** * Initialize a server which will bind to the specified address and port. *

* {@link LeshanServerBuilder} is the priviledged way to create a {@link LeshanServer}. * * @param unsecuredEndpoint CoAP endpoint used for coap:// communication. * @param securedEndpoint CoAP endpoint used for coaps:// communication. * @param registrationStore the {@link Registration} store. * @param securityStore the {@link SecurityInfo} store. * @param authorizer define which devices is allow to register on this server. * @param modelProvider provides the objects description for each client. * @param decoder decoder used to decode response payload. * @param encoder encode used to encode request payload. * @param coapConfig the CoAP {@link NetworkConfig}. * @param noQueueMode true to disable presenceService. * @param awakeTimeProvider to set the client awake time if queue mode is used. * @param registrationIdProvider to provide registrationId using for location-path option values on response of * Register operation. */ public LeshanServer(CoapEndpoint unsecuredEndpoint, CoapEndpoint securedEndpoint, CaliforniumRegistrationStore registrationStore, SecurityStore securityStore, Authorizer authorizer, LwM2mModelProvider modelProvider, LwM2mNodeEncoder encoder, LwM2mNodeDecoder decoder, NetworkConfig coapConfig, boolean noQueueMode, ClientAwakeTimeProvider awakeTimeProvider, RegistrationIdProvider registrationIdProvider) { Validate.notNull(registrationStore, "registration store cannot be null"); Validate.notNull(authorizer, "authorizer cannot be null"); Validate.notNull(modelProvider, "modelProvider cannot be null"); Validate.notNull(encoder, "encoder cannot be null"); Validate.notNull(decoder, "decoder cannot be null"); Validate.notNull(coapConfig, "coapConfig cannot be null"); Validate.notNull(registrationIdProvider, "registrationIdProvider cannot be null"); // Create CoAP server coapServer = createCoapServer(coapConfig); // unsecured endpoint this.unsecuredEndpoint = unsecuredEndpoint; if (unsecuredEndpoint != null) { coapServer.addEndpoint(unsecuredEndpoint); } // secure endpoint this.securedEndpoint = securedEndpoint; if (securedEndpoint != null) { coapServer.addEndpoint(securedEndpoint); } // init services and stores this.registrationStore = registrationStore; registrationService = createRegistrationService(registrationStore); this.securityStore = securityStore; this.modelProvider = modelProvider; observationService = createObservationService(registrationStore, modelProvider, decoder, unsecuredEndpoint, securedEndpoint); if (noQueueMode) { presenceService = null; } else { presenceService = createPresenceService(registrationService, awakeTimeProvider); } // define /rd resource coapServer.add(createRegisterResource(registrationService, authorizer, registrationIdProvider)); // create request sender requestSender = createRequestSender(securedEndpoint, unsecuredEndpoint, registrationService, observationService, this.modelProvider, encoder, decoder, presenceService); // connection cleaner createConnectionCleaner(securityStore, securedEndpoint); coapApi = new CoapAPI(); } protected CoapServer createCoapServer(NetworkConfig coapConfig) { return new CoapServer(coapConfig) { @Override protected Resource createRoot() { return new RootResource(this); } }; } protected RegistrationServiceImpl createRegistrationService(RegistrationStore registrationStore) { return new RegistrationServiceImpl(registrationStore); } protected ObservationServiceImpl createObservationService(CaliforniumRegistrationStore registrationStore, LwM2mModelProvider modelProvider, LwM2mNodeDecoder decoder, CoapEndpoint unsecuredEndpoint, CoapEndpoint securedEndpoint) { ObservationServiceImpl observationService = new ObservationServiceImpl(registrationStore, modelProvider, decoder); if (unsecuredEndpoint != null) { unsecuredEndpoint.addNotificationListener(observationService); observationService.setNonSecureEndpoint(unsecuredEndpoint); } if (securedEndpoint != null) { securedEndpoint.addNotificationListener(observationService); observationService.setSecureEndpoint(securedEndpoint); } return observationService; } protected PresenceServiceImpl createPresenceService(RegistrationService registrationService, ClientAwakeTimeProvider awakeTimeProvider) { PresenceServiceImpl presenceService = new PresenceServiceImpl(awakeTimeProvider); registrationService.addListener(new PresenceStateListener(presenceService)); return presenceService; } protected CoapResource createRegisterResource(RegistrationServiceImpl registrationService, Authorizer authorizer, RegistrationIdProvider registrationIdProvider) { return new RegisterResource(new RegistrationHandler(registrationService, authorizer, registrationIdProvider)); } protected LwM2mRequestSender createRequestSender(Endpoint securedEndpoint, Endpoint unsecuredEndpoint, RegistrationServiceImpl registrationService, ObservationServiceImpl observationService, LwM2mModelProvider modelProvider, LwM2mNodeEncoder encoder, LwM2mNodeDecoder decoder, PresenceServiceImpl presenceService) { // if no queue mode, create a "simple" sender final LwM2mRequestSender requestSender; if (presenceService == null) requestSender = new CaliforniumLwM2mRequestSender(securedEndpoint, unsecuredEndpoint, observationService, modelProvider, encoder, decoder); else requestSender = new CaliforniumQueueModeRequestSender(presenceService, new CaliforniumLwM2mRequestSender( securedEndpoint, unsecuredEndpoint, observationService, modelProvider, encoder, decoder)); // Cancel observations on client unregistering registrationService.addListener(new RegistrationListener() { @Override public void updated(RegistrationUpdate update, Registration updatedRegistration, Registration previousReg) { if (!update.getAddress().equals(previousReg.getAddress()) || update.getPort() != previousReg.getPort()) { requestSender.cancelOngoingRequests(previousReg); } } @Override public void unregistered(Registration registration, Collection observations, boolean expired, Registration newReg) { requestSender.cancelOngoingRequests(registration); } @Override public void registered(Registration registration, Registration previousReg, Collection previousObsersations) { } }); return requestSender; } protected void createConnectionCleaner(SecurityStore securityStore, CoapEndpoint securedEndpoint) { if (securedEndpoint != null && securedEndpoint.getConnector() instanceof DTLSConnector && securityStore instanceof EditableSecurityStore) { final ConnectionCleaner connectionCleaner = new ConnectionCleaner( (DTLSConnector) securedEndpoint.getConnector()); ((EditableSecurityStore) securityStore).setListener(new SecurityStoreListener() { @Override public void securityInfoRemoved(boolean infosAreCompromised, SecurityInfo... infos) { if (infosAreCompromised) { connectionCleaner.cleanConnectionFor(infos); } } }); } } /** * Starts the server and binds it to the specified port. */ public void start() { // Start stores if (registrationStore instanceof Startable) { ((Startable) registrationStore).start(); } if (securityStore instanceof Startable) { ((Startable) securityStore).start(); } if (requestSender instanceof Startable) { ((Startable) requestSender).start(); } // Start server coapServer.start(); if (LOG.isInfoEnabled()) { LOG.info("LWM2M server started at {} {}", getUnsecuredAddress() == null ? "" : "coap://" + getUnsecuredAddress(), getSecuredAddress() == null ? "" : "coaps://" + getSecuredAddress()); } } /** * Stops the server and unbinds it from assigned ports (can be restarted). */ public void stop() { // Stop server coapServer.stop(); // Stop stores if (registrationStore instanceof Stoppable) { ((Stoppable) registrationStore).stop(); } if (securityStore instanceof Stoppable) { ((Stoppable) securityStore).stop(); } if (requestSender instanceof Stoppable) { ((Stoppable) requestSender).stop(); } LOG.info("LWM2M server stopped."); } /** * Destroys the server, unbinds from all ports and frees all system resources. *

* Server can not be restarted anymore. */ public void destroy() { // Destroy server coapServer.destroy(); // Destroy stores if (registrationStore instanceof Destroyable) { ((Destroyable) registrationStore).destroy(); } else if (registrationStore instanceof Stoppable) { ((Stoppable) registrationStore).stop(); } if (securityStore instanceof Destroyable) { ((Destroyable) securityStore).destroy(); } else if (securityStore instanceof Stoppable) { ((Stoppable) securityStore).stop(); } if (requestSender instanceof Destroyable) { ((Destroyable) requestSender).destroy(); } else if (requestSender instanceof Stoppable) { ((Stoppable) requestSender).stop(); } presenceService.destroy(); LOG.info("LWM2M server destroyed."); } /** * Get the {@link RegistrationService} to access to registered clients. *

* You can use this object for listening client registration lifecycle. */ public RegistrationService getRegistrationService() { return this.registrationService; } /** * Get the {@link ObservationService} to access current observations. *

* You can use this object for listening resource observation or cancel it. */ public ObservationService getObservationService() { return this.observationService; } /** * Get the {@link PresenceService} to get status of LWM2M clients connected with binding mode 'Q'. *

* You can use this object to add {@link PresenceListener} to get notified when a device comes online or offline. * */ public PresenceService getPresenceService() { return this.presenceService; } /** * Get the SecurityStore containing of security information. */ public SecurityStore getSecurityStore() { return this.securityStore; } /** * Get the provider in charge of retrieving the object definitions for each client. */ public LwM2mModelProvider getModelProvider() { return this.modelProvider; } /** * Send a Lightweight M2M request synchronously using a default 2min timeout. Will block until a response is * received from the remote server. *

* The synchronous way could block a thread during a long time so it is more recommended to use the asynchronous * way. *

* We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to send * a Confirmable message to the time when an acknowledgement is no longer expected. * * @param destination The {@link Registration} associate to the device we want to sent the request. * @param request The request to send to the client. * @param timeoutInMs The global timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @return the LWM2M response. The response can be null if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout). * * @throws CodecException if request payload can not be encoded. * @throws InterruptedException if the thread was interrupted. * @throws RequestRejectedException if the request is rejected by foreign peer. * @throws RequestCanceledException if the request is cancelled. * @throws SendFailedException if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer. * @throws InvalidResponseException if the response received is malformed. * @throws ClientSleepingException if client is currently sleeping. */ public T send(Registration destination, DownlinkRequest request) throws InterruptedException { return requestSender.send(destination, request, DEFAULT_TIMEOUT); } /** * Send a Lightweight M2M request synchronously. Will block until a response is received from the remote server. *

* The synchronous way could block a thread during a long time so it is more recommended to use the asynchronous * way. * * @param destination The {@link Registration} associate to the device we want to sent the request. * @param request The request to send to the client. * @param timeoutInMs The global timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @return the LWM2M response. The response can be null if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout). * * @throws CodecException if request payload can not be encoded. * @throws InterruptedException if the thread was interrupted. * @throws RequestRejectedException if the request is rejected by foreign peer. * @throws RequestCanceledException if the request is cancelled. * @throws SendFailedException if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer. * @throws InvalidResponseException if the response received is malformed. * @throws ClientSleepingException if client is currently sleeping. */ public T send(Registration destination, DownlinkRequest request, long timeout) throws InterruptedException { return requestSender.send(destination, request, timeout); } /** * Send a Lightweight M2M {@link DownlinkRequest} asynchronously to a LWM2M client using a default 2min timeout. *

* The Californium API does not ensure that message callback are exclusive. E.g. In some race condition, you can get * a onReponse call and a onCancel one. This method ensures that you will receive only one event. Meaning, you get * either 1 response or 1 error. *

* We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to send * a Confirmable message to the time when an acknowledgement is no longer expected. * * @param destination The {@link Registration} associate to the device we want to sent the request. * @param request The request to send to the client. * @param timeoutInMs The global timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @param responseCallback a callback called when a response is received (successful or error response). This * callback MUST NOT be null. * @param errorCallback a callback called when an error or exception occurred when response is received. It can be : *

    *
  • {@link RequestRejectedException} if the request is rejected by foreign peer.
  • *
  • {@link RequestCanceledException} if the request is cancelled.
  • *
  • {@link SendFailedException} if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer.
  • *
  • {@link InvalidResponseException} if the response received is malformed.
  • *
  • {@link ClientSleepingException} if client is currently sleeping.
  • *
  • {@link TimeoutException} if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout).
  • *
  • or any other RuntimeException for unexpected issue. *
* This callback MUST NOT be null. * @throws CodecException if request payload can not be encoded. */ public void send(Registration destination, DownlinkRequest request, ResponseCallback responseCallback, ErrorCallback errorCallback) { requestSender.send(destination, request, DEFAULT_TIMEOUT, responseCallback, errorCallback); } /** * Send a Lightweight M2M {@link DownlinkRequest} asynchronously to a LWM2M client. *

* The Californium API does not ensure that message callback are exclusive. E.g. In some race condition, you can get * a onReponse call and a onCancel one. This method ensures that you will receive only one event. Meaning, you get * either 1 response or 1 error. * * @param destination The {@link Registration} associate to the device we want to sent the request. * @param request The request to send to the client. * @param timeoutInMs The global timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @param responseCallback a callback called when a response is received (successful or error response). This * callback MUST NOT be null. * @param errorCallback a callback called when an error or exception occurred when response is received. It can be : *

    *
  • {@link RequestRejectedException} if the request is rejected by foreign peer.
  • *
  • {@link RequestCanceledException} if the request is cancelled.
  • *
  • {@link SendFailedException} if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer.
  • *
  • {@link InvalidResponseException} if the response received is malformed.
  • *
  • {@link ClientSleepingException} if client is currently sleeping.
  • *
  • {@link TimeoutException} if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout).
  • *
  • or any other RuntimeException for unexpected issue. *
* This callback MUST NOT be null. * @throws CodecException if request payload can not be encoded. */ public void send(Registration destination, DownlinkRequest request, long timeout, ResponseCallback responseCallback, ErrorCallback errorCallback) { requestSender.send(destination, request, timeout, responseCallback, errorCallback); } /** * @return the {@link InetSocketAddress} used for coap:// */ public InetSocketAddress getUnsecuredAddress() { if (unsecuredEndpoint != null) { return unsecuredEndpoint.getAddress(); } else { return null; } } /** * @return the {@link InetSocketAddress} used for coaps:// */ public InetSocketAddress getSecuredAddress() { if (securedEndpoint != null) { return securedEndpoint.getAddress(); } else { return null; } } /** * A CoAP API, generally needed when you want to mix LWM2M and CoAP protocol. */ public CoapAPI coap() { return coapApi; } public class CoapAPI { /** * @return the underlying {@link CoapServer} */ public CoapServer getServer() { return coapServer; } /** * @return the {@link CoapEndpoint} used for secured CoAP communication (coaps://) */ public CoapEndpoint getSecuredEndpoint() { return securedEndpoint; } /** * @return the {@link CoapEndpoint} used for unsecured CoAP communication (coap://) */ public CoapEndpoint getUnsecuredEndpoint() { return unsecuredEndpoint; } /** * Send a CoAP {@link Request} synchronously to a LWM2M client using a default 2min timeout. Will block until a * response is received from the remote client. *

* The synchronous way could block a thread during a long time so it is more recommended to use the asynchronous * way. *

* We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to * send a Confirmable message to the time when an acknowledgement is no longer expected. * * @param destination The registration linked to the LWM2M client to which the request must be sent. * @param coapRequest The request to send to the client. * @return the response or null if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout). * * @throws InterruptedException if the thread was interrupted. * @throws RequestRejectedException if the request is rejected by foreign peer. * @throws RequestCanceledException if the request is cancelled. * @throws SendFailedException if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer. * @throws ClientSleepingException if client is currently sleeping. */ public Response send(Registration destination, Request request) throws InterruptedException { // Ensure that delegated sender is able to send CoAP request if (!(requestSender instanceof CoapRequestSender)) { throw new UnsupportedOperationException("This sender does not support to send CoAP request"); } CoapRequestSender sender = (CoapRequestSender) requestSender; return sender.sendCoapRequest(destination, request, DEFAULT_TIMEOUT); } /** * Send a CoAP {@link Request} synchronously to a LWM2M client. Will block until a response is received from the * remote client. *

* The synchronous way could block a thread during a long time so it is more recommended to use the asynchronous * way. *

* We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to * send a Confirmable message to the time when an acknowledgement is no longer expected. * * @param destination The registration linked to the LWM2M client to which the request must be sent. * @param coapRequest The request to send to the client. * @param timeoutInMs The response timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @return the response or null if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout). * * @throws InterruptedException if the thread was interrupted. * @throws RequestRejectedException if the request is rejected by foreign peer. * @throws RequestCanceledException if the request is cancelled. * @throws SendFailedException if the request can not be sent. E.g. error at CoAP or DTLS/UDP layer. * @throws ClientSleepingException if client is currently sleeping. */ public Response send(Registration destination, Request request, long timeout) throws InterruptedException { // Ensure that delegated sender is able to send CoAP request if (!(requestSender instanceof CoapRequestSender)) { throw new UnsupportedOperationException("This sender does not support to send CoAP request"); } CoapRequestSender sender = (CoapRequestSender) requestSender; return sender.sendCoapRequest(destination, request, timeout); } /** * Sends a CoAP {@link Request} asynchronously to a LWM2M client using a default 2min timeout. *

* {@link ResponseCallback} and {@link ErrorCallback} are exclusively called. * * @param destination The registration linked to the LWM2M client to which the request must be sent. * @param request The request to send to the client. * @param timeoutInMs The response timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @param responseCallback a callback called when a response is received (successful or error response). This * callback MUST NOT be null. * @param errorCallback a callback called when an error or exception occurred when response is received. It can * be : *

    *
  • {@link RequestRejectedException} if the request is rejected by foreign peer.
  • *
  • {@link RequestCanceledException} if the request is cancelled.
  • *
  • {@link SendFailedException} if the request can not be sent. E.g. error at CoAP or DTLS/UDP * layer.
  • *
  • {@link ClientSleepingException} if client is currently sleeping.
  • *
  • {@link TimeoutException} if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout).
  • *
  • or any other RuntimeException for unexpected issue. *
* This callback MUST NOT be null. */ public void send(Registration destination, Request request, CoapResponseCallback responseCallback, ErrorCallback errorCallback) { // Ensure that delegated sender is able to send CoAP request if (!(requestSender instanceof CoapRequestSender)) { throw new UnsupportedOperationException("This sender does not support to send CoAP request"); } CoapRequestSender sender = (CoapRequestSender) requestSender; sender.sendCoapRequest(destination, request, DEFAULT_TIMEOUT, responseCallback, errorCallback); } /** * Sends a CoAP {@link Request} asynchronously to a LWM2M client. *

* {@link ResponseCallback} and {@link ErrorCallback} are exclusively called. * * @param destination The registration linked to the LWM2M client to which the request must be sent. * @param request The request to send to the client. * @param timeoutInMs The response timeout to wait in milliseconds (see * https://github.com/eclipse/leshan/wiki/Request-Timeout) * @param responseCallback a callback called when a response is received (successful or error response). This * callback MUST NOT be null. * @param errorCallback a callback called when an error or exception occurred when response is received. It can * be : *

    *
  • {@link RequestRejectedException} if the request is rejected by foreign peer.
  • *
  • {@link RequestCanceledException} if the request is cancelled.
  • *
  • {@link SendFailedException} if the request can not be sent. E.g. error at CoAP or DTLS/UDP * layer.
  • *
  • {@link ClientSleepingException} if client is currently sleeping.
  • *
  • {@link TimeoutException} if the timeout expires (see * https://github.com/eclipse/leshan/wiki/Request-Timeout).
  • *
  • or any other RuntimeException for unexpected issue. *
* This callback MUST NOT be null. */ public void send(Registration destination, Request request, long timeout, CoapResponseCallback responseCallback, ErrorCallback errorCallback) { // Ensure that delegated sender is able to send CoAP request if (!(requestSender instanceof CoapRequestSender)) { throw new UnsupportedOperationException("This sender does not support to send CoAP request"); } CoapRequestSender sender = (CoapRequestSender) requestSender; sender.sendCoapRequest(destination, request, timeout, responseCallback, errorCallback); } } }