diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/ExchangeObserverAdapter.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/ExchangeObserverAdapter.java new file mode 100644 index 0000000000..a3410a1bba --- /dev/null +++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/ExchangeObserverAdapter.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2017 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 + *******************************************************************************/ +package org.eclipse.leshan.server.californium.impl; + +import org.eclipse.californium.core.network.Exchange; +import org.eclipse.californium.core.network.ExchangeObserver; + +/** + * An abstract adapter class for reacting to exchange events. The methods in this class are empty. This class exists as + * convenience for creating exchange observer objects. + */ +// TODO should be part of californium ? +public class ExchangeObserverAdapter implements ExchangeObserver { + + @Override + public void completed(Exchange exchange) { + } + + @Override + public void contextEstablished(Exchange exchange) { + } +} diff --git a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/RegisterResource.java b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/RegisterResource.java index 54888342f4..1dea3715ff 100644 --- a/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/RegisterResource.java +++ b/leshan-server-cf/src/main/java/org/eclipse/leshan/server/californium/impl/RegisterResource.java @@ -42,6 +42,7 @@ import org.eclipse.leshan.core.response.RegisterResponse; import org.eclipse.leshan.core.response.UpdateResponse; import org.eclipse.leshan.server.client.RegistrationService; +import org.eclipse.leshan.server.impl.SendableResponse; import org.eclipse.leshan.server.registration.RegistrationHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -187,7 +188,18 @@ private void handleRegister(CoapExchange exchange, Request request) { // Handle request // ------------------------------- InetSocketAddress serverEndpoint = exchange.advanced().getEndpoint().getAddress(); - RegisterResponse response = registrationHandler.register(sender, registerRequest, serverEndpoint); + final SendableResponse sendableResponse = registrationHandler.register(sender, registerRequest, + serverEndpoint); + RegisterResponse response = sendableResponse.getResponse(); + + // Mark the response as sended when the exchange is complete + exchange.advanced().setObserver(new ExchangeObserverAdapter() { + @Override + public void completed(Exchange exchange) { + sendableResponse.sended(); + + } + }); // Create CoAP Response from LwM2m request // ------------------------------- @@ -223,7 +235,16 @@ private void handleUpdate(CoapExchange exchange, Request request, String registr UpdateRequest updateRequest = new UpdateRequest(registrationId, lifetime, smsNumber, binding, objectLinks); // Handle request - UpdateResponse updateResponse = registrationHandler.update(sender, updateRequest); + final SendableResponse sendableResponse = registrationHandler.update(sender, updateRequest); + UpdateResponse updateResponse = sendableResponse.getResponse(); + + // Mark the response as sended when the exchange is complete + exchange.advanced().setObserver(new ExchangeObserverAdapter() { + @Override + public void completed(Exchange exchange) { + sendableResponse.sended(); + } + }); // Create CoAP Response from LwM2m request exchange.respond(fromLwM2mCode(updateResponse.getCode()), updateResponse.getErrorMessage()); @@ -237,7 +258,17 @@ private void handleDeregister(CoapExchange exchange, String registrationId) { DeregisterRequest deregisterRequest = new DeregisterRequest(registrationId); // Handle request - DeregisterResponse deregisterResponse = registrationHandler.deregister(sender, deregisterRequest); + final SendableResponse sendableResponse = registrationHandler.deregister(sender, + deregisterRequest); + DeregisterResponse deregisterResponse = sendableResponse.getResponse(); + + // Mark the response as sended when the exchange is complete + exchange.advanced().setObserver(new ExchangeObserverAdapter() { + @Override + public void completed(Exchange exchange) { + sendableResponse.sended(); + } + }); // Create CoAP Response from LwM2m request exchange.respond(fromLwM2mCode(deregisterResponse.getCode()), deregisterResponse.getErrorMessage()); diff --git a/leshan-server-core/src/main/java/org/eclipse/leshan/server/impl/SendableResponse.java b/leshan-server-core/src/main/java/org/eclipse/leshan/server/impl/SendableResponse.java new file mode 100644 index 0000000000..45cd70201e --- /dev/null +++ b/leshan-server-core/src/main/java/org/eclipse/leshan/server/impl/SendableResponse.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2017 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 + *******************************************************************************/ +package org.eclipse.leshan.server.impl; + +import org.eclipse.leshan.core.response.LwM2mResponse; + +/** + * A Response wrapper which can be notify when the response is sent + */ +public class SendableResponse { + + private T response; + private Runnable sendedCallback; + + public SendableResponse(T response) { + this(response, null); + } + + public SendableResponse(T response, Runnable sendedCallback) { + this.response = response; + this.sendedCallback = sendedCallback; + } + + public T getResponse() { + return response; + } + + public void sended() { + if (sendedCallback != null) + sendedCallback.run(); + } +} diff --git a/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/RegistrationHandler.java b/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/RegistrationHandler.java index 8b7efd16db..01718b73e5 100644 --- a/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/RegistrationHandler.java +++ b/leshan-server-core/src/main/java/org/eclipse/leshan/server/registration/RegistrationHandler.java @@ -29,6 +29,7 @@ import org.eclipse.leshan.server.client.RegistrationService; import org.eclipse.leshan.server.client.RegistrationUpdate; import org.eclipse.leshan.server.impl.RegistrationServiceImpl; +import org.eclipse.leshan.server.impl.SendableResponse; import org.eclipse.leshan.server.security.Authorizer; import org.eclipse.leshan.util.RandomStringUtils; import org.slf4j.Logger; @@ -50,7 +51,7 @@ public RegistrationHandler(RegistrationServiceImpl registrationService, Authoriz this.authorizer = authorizer; } - public RegisterResponse register(Identity sender, RegisterRequest registerRequest, + public SendableResponse register(Identity sender, RegisterRequest registerRequest, InetSocketAddress serverEndpoint) { Registration.Builder builder = new Registration.Builder(RegistrationHandler.createRegistrationId(), @@ -62,82 +63,95 @@ public RegisterResponse register(Identity sender, RegisterRequest registerReques .smsNumber(registerRequest.getSmsNumber()).registrationDate(new Date()).lastUpdate(new Date()) .additionalRegistrationAttributes(registerRequest.getAdditionalAttributes()); - Registration registration = builder.build(); + final Registration registration = builder.build(); // We must check if the client is using the right identity. if (!authorizer.isAuthorized(registerRequest, registration, sender)) { - return RegisterResponse.forbidden(null); + return new SendableResponse<>(RegisterResponse.forbidden(null)); } // Add registration to the store - Deregistration deregistration = registrationService.getStore().addRegistration(registration); + final Deregistration deregistration = registrationService.getStore().addRegistration(registration); - // notify new registration and de-registration + // Create callback to notify new registration and de-registration LOG.debug("New registration: {}", registration); - if (deregistration != null) { - registrationService.fireUnregistered(deregistration.getRegistration()); - } - registrationService.fireRegistred(registration); + Runnable whenSended = new Runnable (){ + public void run() { + if (deregistration != null) { + registrationService.fireUnregistered(deregistration.getRegistration()); + } + registrationService.fireRegistred(registration); + }; + }; + - return RegisterResponse.success(registration.getId()); + return new SendableResponse<>(RegisterResponse.success(registration.getId()), whenSended); } - public UpdateResponse update(Identity sender, UpdateRequest updateRequest) { + public SendableResponse update(Identity sender, UpdateRequest updateRequest) { // We must check if the client is using the right identity. Registration registration = registrationService.getById(updateRequest.getRegistrationId()); if (registration == null) { - return UpdateResponse.notFound(); + return new SendableResponse<>(UpdateResponse.notFound()); } if (!authorizer.isAuthorized(updateRequest, registration, sender)) { // TODO replace by Forbidden if https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues/181 is // closed. - return UpdateResponse.badRequest("forbidden"); + return new SendableResponse<>(UpdateResponse.badRequest("forbidden")); } // Create update - RegistrationUpdate update = new RegistrationUpdate(updateRequest.getRegistrationId(), sender + final RegistrationUpdate update = new RegistrationUpdate(updateRequest.getRegistrationId(), sender .getPeerAddress().getAddress(), sender.getPeerAddress().getPort(), updateRequest.getLifeTimeInSec(), updateRequest.getSmsNumber(), updateRequest.getBindingMode(), updateRequest.getObjectLinks()); - // update registration - registration = registrationService.getStore().updateRegistration(update); - if (registration == null) { + // Update registration + final Registration registrationUpdated = registrationService.getStore().updateRegistration(update); + if (registrationUpdated == null) { LOG.debug("Invalid update : registration not found"); - return UpdateResponse.notFound(); + return new SendableResponse<>(UpdateResponse.notFound()); } else { LOG.debug("Updated registration {} by {}", registration, update); - // notify registration update - registrationService.fireUpdated(update, registration); - return UpdateResponse.success(); + // Create callback to notify registration update + Runnable whenSended = new Runnable() { + public void run() { + registrationService.fireUpdated(update, registrationUpdated); + }; + }; + return new SendableResponse<>(UpdateResponse.success(), whenSended); } } - public DeregisterResponse deregister(Identity sender, DeregisterRequest deregisterRequest) { + public SendableResponse deregister(Identity sender, DeregisterRequest deregisterRequest) { // We must check if the client is using the right identity. Registration registration = registrationService.getById(deregisterRequest.getRegistrationId()); if (registration == null) { - return DeregisterResponse.notFound(); + return new SendableResponse<>(DeregisterResponse.notFound()); } if (!authorizer.isAuthorized(deregisterRequest, registration, sender)) { // TODO replace by Forbidden if https://github.com/OpenMobileAlliance/OMA_LwM2M_for_Developers/issues/181 is // closed. - return DeregisterResponse.badRequest("forbidden"); + return new SendableResponse<>(DeregisterResponse.badRequest("forbidden")); } - Deregistration deregistration = registrationService.getStore() + final Deregistration deregistration = registrationService.getStore() .removeRegistration(deregisterRequest.getRegistrationId()); if (deregistration != null) { LOG.debug("Deregistered client : {}", deregistration.getRegistration()); - // notify new de-registration - registrationService.fireUnregistered(registration); - return DeregisterResponse.success(); + // Create callback to notify new de-registration + Runnable whenSended = new Runnable() { + public void run() { + registrationService.fireUnregistered(deregistration.getRegistration()); + }; + }; + return new SendableResponse<>(DeregisterResponse.success(), whenSended); } else { LOG.debug("Invalid deregistration : registration not found"); - return DeregisterResponse.notFound(); + return new SendableResponse<>(DeregisterResponse.notFound()); } }