Commit ade09738eb458ad99c99e9fd72028ca6795e727f

Authored by nickAS21
Committed by Andrew Shvayka
1 parent c230e3fd

Lwm2m: back: add key to profile - refactoring-light start2

@@ -249,6 +249,11 @@ public class LwM2MTransportHandler { @@ -249,6 +249,11 @@ public class LwM2MTransportHandler {
249 profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientUpdateValueAfterConnect").getAsBoolean(); 249 profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientUpdateValueAfterConnect").getAsBoolean();
250 } 250 }
251 251
  252 + public static boolean getClientOnlyObserveAfterConnect (LwM2MClientProfile profile) {
  253 + return profile.getPostClientLwM2mSettings().getAsJsonObject().has("clientOnlyObserveAfterConnect") &&
  254 + profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientOnlyObserveAfterConnect").getAsBoolean();
  255 + }
  256 +
252 private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) { 257 private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) {
253 return (objectMsg != null && 258 return (objectMsg != null &&
254 !objectMsg.isJsonNull() && 259 !objectMsg.isJsonNull() &&
@@ -226,7 +226,7 @@ public class LwM2MTransportRequest { @@ -226,7 +226,7 @@ public class LwM2MTransportRequest {
226 String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg No SendRequest to Client", target); 226 String msg = String.format(LOG_LW2M_ERROR + ": sendRequest: Resource path - %s msg No SendRequest to Client", target);
227 service.sentLogsToThingsboard(msg, registration); 227 service.sentLogsToThingsboard(msg, registration);
228 log.error("[{}] - [{}] No SendRequest", target); 228 log.error("[{}] - [{}] No SendRequest", target);
229 - this.handleResponseError(registration, target, lwM2MClient, true); 229 +// this.handleResponseError(registration, target, lwM2MClient, true);
230 230
231 } 231 }
232 } 232 }
@@ -262,9 +262,9 @@ public class LwM2MTransportRequest { @@ -262,9 +262,9 @@ public class LwM2MTransportRequest {
262 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); 262 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());
263 service.sentLogsToThingsboard(msg, registration); 263 service.sentLogsToThingsboard(msg, registration);
264 log.error("[{}] - [{}] [{}] error SendRequest", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); 264 log.error("[{}] - [{}] [{}] error SendRequest", ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
265 - if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) {  
266 - this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate);  
267 - } 265 +// if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) {
  266 +// this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate);
  267 +// }
268 } 268 }
269 269
270 }, e -> { 270 }, e -> {
@@ -272,9 +272,9 @@ public class LwM2MTransportRequest { @@ -272,9 +272,9 @@ public class LwM2MTransportRequest {
272 request.getPath().toString(), e.toString()); 272 request.getPath().toString(), e.toString());
273 service.sentLogsToThingsboard(msg, registration); 273 service.sentLogsToThingsboard(msg, registration);
274 log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); 274 log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString());
275 - if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) {  
276 - this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate);  
277 - } 275 +// if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest() && isDelayedUpdate) {
  276 +// this.handleResponseError(registration, request.getPath().toString(), lwM2MClient, isDelayedUpdate);
  277 +// }
278 }); 278 });
279 } 279 }
280 280
@@ -317,16 +317,16 @@ public class LwM2MTransportRequest { @@ -317,16 +317,16 @@ public class LwM2MTransportRequest {
317 } 317 }
318 }); 318 });
319 } 319 }
320 -  
321 - private void handleResponseError(Registration registration, final String path, LwM2MClient lwM2MClient, boolean isDelayedUpdate) {  
322 - executorResponseError.submit(() -> {  
323 - try {  
324 - if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(path);  
325 - } catch (RuntimeException t) {  
326 - log.error("[{}] endpoint [{}] path [{}] RuntimeException Unable to after send response.", registration.getEndpoint(), path, t);  
327 - }  
328 - });  
329 - } 320 +//
  321 +// private void handleResponseError(Registration registration, final String path, LwM2MClient lwM2MClient, boolean isDelayedUpdate) {
  322 +// executorResponseError.submit(() -> {
  323 +// try {
  324 +// if (isDelayedUpdate) lwM2MClient.onSuccessOrErrorDelayedRequests(path);
  325 +// } catch (RuntimeException t) {
  326 +// log.error("[{}] endpoint [{}] path [{}] RuntimeException Unable to after send response.", registration.getEndpoint(), path, t);
  327 +// }
  328 +// });
  329 +// }
330 330
331 /** 331 /**
332 * processing a response from a client 332 * processing a response from a client
@@ -336,26 +336,10 @@ public class LwM2MTransportRequest { @@ -336,26 +336,10 @@ public class LwM2MTransportRequest {
336 * @param lwM2MClient - 336 * @param lwM2MClient -
337 */ 337 */
338 private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient, boolean isDelayedUpdate) { 338 private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient, boolean isDelayedUpdate) {
339 - if (response instanceof ObserveResponse) { 339 + if (response instanceof ObserveResponse || response instanceof ReadResponse) {
340 service.onObservationResponse(registration, path, (ReadResponse) response); 340 service.onObservationResponse(registration, path, (ReadResponse) response);
341 } else if (response instanceof CancelObservationResponse) { 341 } else if (response instanceof CancelObservationResponse) {
342 log.info("[{}] Path [{}] CancelObservationResponse 3_Send", path, response); 342 log.info("[{}] Path [{}] CancelObservationResponse 3_Send", path, response);
343 - } else if (response instanceof ReadResponse) {  
344 - /**  
345 - * Use only at the first start after registration  
346 - * Fill with data -> Model client  
347 - */  
348 - if (lwM2MClient != null) {  
349 - if (lwM2MClient.getPendingRequests().size() > 0) {  
350 - lwM2MClient.onSuccessHandler(path, response);  
351 - }  
352 - }  
353 - /**  
354 - * Use after registration on request  
355 - */  
356 - else {  
357 - service.onObservationResponse(registration, path, (ReadResponse) response);  
358 - }  
359 } else if (response instanceof DeleteResponse) { 343 } else if (response instanceof DeleteResponse) {
360 log.info("[{}] Path [{}] DeleteResponse 5_Send", path, response); 344 log.info("[{}] Path [{}] DeleteResponse 5_Send", path, response);
361 } else if (response instanceof DiscoverResponse) { 345 } else if (response instanceof DiscoverResponse) {
@@ -366,7 +350,7 @@ public class LwM2MTransportRequest { @@ -366,7 +350,7 @@ public class LwM2MTransportRequest {
366 log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", path, response); 350 log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", path, response);
367 } else if (response instanceof WriteResponse) { 351 } else if (response instanceof WriteResponse) {
368 log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", path, response); 352 log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", path, response);
369 - service.onAttributeUpdateOk(registration, path, (WriteRequest) request, isDelayedUpdate); 353 + service.onWriteResponseOk(registration, path, (WriteRequest) request, isDelayedUpdate);
370 } 354 }
371 } 355 }
372 } 356 }
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.transport.lwm2m.server; 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
  18 +import com.fasterxml.jackson.databind.ObjectMapper;
18 import com.google.gson.Gson; 19 import com.google.gson.Gson;
19 import com.google.gson.JsonArray; 20 import com.google.gson.JsonArray;
20 import com.google.gson.JsonElement; 21 import com.google.gson.JsonElement;
@@ -42,10 +43,9 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException; @@ -42,10 +43,9 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException;
42 import org.thingsboard.server.common.transport.adaptor.JsonConverter; 43 import org.thingsboard.server.common.transport.adaptor.JsonConverter;
43 import org.thingsboard.server.common.transport.service.DefaultTransportService; 44 import org.thingsboard.server.common.transport.service.DefaultTransportService;
44 import org.thingsboard.server.gen.transport.TransportProtos; 45 import org.thingsboard.server.gen.transport.TransportProtos;
  46 +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
45 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; 47 import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
46 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; 48 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
47 -import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;  
48 -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;  
49 import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; 49 import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient;
50 import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientProfile; 50 import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientProfile;
51 import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; 51 import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
@@ -54,6 +54,7 @@ import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurit @@ -54,6 +54,7 @@ import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurit
54 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 54 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
55 55
56 import javax.annotation.PostConstruct; 56 import javax.annotation.PostConstruct;
  57 +import java.io.IOException;
57 import java.util.ArrayList; 58 import java.util.ArrayList;
58 import java.util.Arrays; 59 import java.util.Arrays;
59 import java.util.Collection; 60 import java.util.Collection;
@@ -152,6 +153,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -152,6 +153,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
152 lwM2MClient.setSessionUuid(UUID.randomUUID()); 153 lwM2MClient.setSessionUuid(UUID.randomUUID());
153 this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); 154 this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration);
154 LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId()); 155 LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId());
  156 + this.putDelayedUpdateResourcesThingsboard(lwM2MClient);
155 this.setLwM2mFromClientValue(lwServer, registration, lwM2MClient, lwM2MClientProfile); 157 this.setLwM2mFromClientValue(lwServer, registration, lwM2MClient, lwM2MClientProfile);
156 SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); 158 SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
157 if (sessionInfo != null) { 159 if (sessionInfo != null) {
@@ -163,9 +165,9 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -163,9 +165,9 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
163 transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); 165 transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
164 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); 166 transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
165 this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); 167 this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration);
166 - if (LwM2MTransportHandler.getClientUpdateValueAfterConnect(lwM2MClientProfile)) {  
167 - this.putDelayedUpdateResourcesThingsboard(lwM2MClient);  
168 - } 168 +// if (LwM2MTransportHandler.getClientUpdateValueAfterConnect(lwM2MClientProfile)) {
  169 +// this.putDelayedUpdateResourcesThingsboard(lwM2MClient);
  170 +// }
169 } else { 171 } else {
170 log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); 172 log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
171 } 173 }
@@ -237,448 +239,271 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -237,448 +239,271 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
237 //TODO: associate endpointId with device information. 239 //TODO: associate endpointId with device information.
238 } 240 }
239 241
240 - /**  
241 - * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay,  
242 - * * if you need to do long time processing use a dedicated thread pool.  
243 - *  
244 - * @param registration -  
245 - */  
246 - protected void onAwakeDev(Registration registration) {  
247 - log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());  
248 - //TODO: associate endpointId with device information. 242 + @Override
  243 + public void setCancelObservations(LeshanServer lwServer, Registration registration) {
  244 + if (registration != null) {
  245 + Set<Observation> observations = lwServer.getObservationService().getObservations(registration);
  246 + observations.forEach(observation -> this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString()));
  247 + }
249 } 248 }
250 249
251 /** 250 /**
252 - * This method is used to sync with sessions  
253 - * Removes a profile if not used in sessions 251 + * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());
  252 + * At server side this will not remove the observation from the observation store, to do it you need to use
  253 + * {@code ObservationService#cancelObservation()}
254 */ 254 */
255 - private void syncSessionsAndProfiles() {  
256 - Map<UUID, LwM2MClientProfile> profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet()  
257 - .stream()  
258 - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));  
259 - profilesClone.forEach((k, v) -> {  
260 - String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet()  
261 - .stream()  
262 - .filter(e -> e.getValue().getProfileUuid().equals(k))  
263 - .findFirst()  
264 - .map(Map.Entry::getKey) // return the key of the matching entry if found  
265 - .orElse("");  
266 - if (registrationId.isEmpty()) {  
267 - lwM2mInMemorySecurityStore.getProfiles().remove(k);  
268 - }  
269 - }); 255 + @Override
  256 + public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) {
  257 + lwServer.getObservationService().cancelObservations(registration, path);
270 } 258 }
271 259
272 /** 260 /**
273 - * #0 Add new ObjectModel to context  
274 - * Create new LwM2MClient for current session -> setModelClient...  
275 - * if need all value after registration:  
276 - * #1.1 Add all ObjectLinks (instance) to control the process of executing requests to the client  
277 - * to get the client model with current values  
278 - * if not need all value after registration (only observe)  
279 - * #1.2 Get observe  
280 - * #2 Get the client model with current values. Analyze the response in -> lwM2MTransportRequest.sendResponse 261 + * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource
281 * 262 *
282 - * @param lwServer - LeshanServer  
283 * @param registration - Registration LwM2M Client 263 * @param registration - Registration LwM2M Client
284 - * @param lwM2MClient - object with All parameters off client 264 + * @param path - observe
  265 + * @param response - observe
285 */ 266 */
286 - private void setLwM2mFromClientValue(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, LwM2MClientProfile lwM2MClientProfile) {  
287 - // #1.1  
288 - // get all instances in client  
289 - Set<String> clientInstances = this.getAllInstancesInClient(registration);  
290 - if (clientInstances != null && LwM2MTransportHandler.getClientUpdateValueAfterConnect(lwM2MClientProfile)) {  
291 - lwM2MClient.getPendingRequests().addAll(clientInstances);  
292 - // #2  
293 - clientInstances.forEach(path -> {  
294 - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),  
295 - lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false);  
296 - });  
297 - } else {  
298 - // #1.2  
299 - this.onSentObserveToClient(lwServer, registration);  
300 - }  
301 -  
302 - }  
303 -  
304 - // get all instances in client  
305 - private Set<String> getAllInstancesInClient(Registration registration) {  
306 - Set<String> clientInstances = ConcurrentHashMap.newKeySet();  
307 - Arrays.stream(registration.getObjectLinks()).forEach(url -> {  
308 - LwM2mPath pathIds = new LwM2mPath(url.getUrl());  
309 - if (pathIds.isObjectInstance() && !pathIds.isResource()) {  
310 - clientInstances.add(url.getUrl()); 267 + @Override
  268 + public void onObservationResponse(Registration registration, String path, ReadResponse response) {
  269 + if (response.getContent() != null) {
  270 + if (response.getContent() instanceof LwM2mObject) {
  271 + LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();
  272 + this.updateObjectResourceValue(registration, lwM2mObject, path);
  273 + } else if (response.getContent() instanceof LwM2mObjectInstance) {
  274 + LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();
  275 + this.updateObjectInstanceResourceValue(registration, lwM2mObjectInstance, path);
  276 + } else if (response.getContent() instanceof LwM2mResource) {
  277 + LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();
  278 + this.updateResourcesValue(registration, lwM2mResource, path);
311 } 279 }
312 - });  
313 - return (clientInstances.size() > 0) ? clientInstances : null;  
314 - }  
315 -  
316 - /**  
317 - * @param registration - Registration LwM2M Client  
318 - * @return - sessionInfo after access connect client  
319 - */  
320 - private SessionInfoProto getValidateSessionInfo(Registration registration) {  
321 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null);  
322 - return getNewSessionInfoProto(lwM2MClient);  
323 - 280 + }
324 } 281 }
325 282
326 /** 283 /**
327 - * @param registrationId -  
328 - * @return - 284 + * Update - sent request in change value resources in Client
  285 + * Path to resources from profile equal keyName or from ModelObject equal name
  286 + * Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)
  287 + * Delete - nothing *
  288 + *
  289 + * @param msg -
329 */ 290 */
330 - private SessionInfoProto getValidateSessionInfo(String registrationId) {  
331 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId);  
332 - return getNewSessionInfoProto(lwM2MClient);  
333 - }  
334 -  
335 - private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) {  
336 - if (lwM2MClient != null) {  
337 - ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse();  
338 - if (msg == null || msg.getDeviceInfo() == null) {  
339 - log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED);  
340 - this.closeClientSession(lwM2MClient.getRegistration());  
341 - return null;  
342 - } else {  
343 - return SessionInfoProto.newBuilder()  
344 - .setNodeId(this.context.getNodeId())  
345 - .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits())  
346 - .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits())  
347 - .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())  
348 - .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())  
349 - .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())  
350 - .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())  
351 - .setDeviceName(msg.getDeviceInfo().getDeviceName())  
352 - .setDeviceType(msg.getDeviceInfo().getDeviceType())  
353 - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())  
354 - .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB())  
355 - .build();  
356 - } 291 + @Override
  292 + public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
  293 + if (msg.getSharedUpdatedCount() > 0) {
  294 + JsonElement el = JsonConverter.toJson(msg);
  295 + el.getAsJsonObject().entrySet().forEach(de -> {
  296 + String path = this.getPathAttributeUpdate(sessionInfo, de.getKey());
  297 + String value = de.getValue().getAsString();
  298 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue();
  299 + LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
  300 + ResourceModel resourceModel = context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path));
  301 + if (!path.isEmpty() && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) {
  302 + if (resourceModel != null && resourceModel.operations.isWritable()) {
  303 + lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
  304 + ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(),
  305 + false);
  306 + } else {
  307 + log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value);
  308 + String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value);
  309 + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
  310 + }
  311 + } else {
  312 + log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value);
  313 + String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value);
  314 + this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration());
  315 + }
  316 + });
  317 + } else if (msg.getSharedDeletedCount() > 0) {
  318 + log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
357 } 319 }
358 - return null;  
359 } 320 }
360 321
361 /** 322 /**
362 - * Add attribute/telemetry information from Client and credentials/Profile to client model and start observe  
363 - * !!! if the resource has an observation, but no telemetry or attribute - the observation will not use  
364 - * #1 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection  
365 - * #2 Start observe  
366 - *  
367 - * @param lwM2MClient - LwM2M Client 323 + * @param sessionInfo -
  324 + * @param deviceProfile -
368 */ 325 */
369 -  
370 - public void updatesAndSentModelParameter(LwM2MClient lwM2MClient) {  
371 - // #1  
372 - this.updateAttrTelemetry(lwM2MClient.getRegistration(), true, null);  
373 - // #2  
374 - this.onSentObserveToClient(lwM2MClient.getLwServer(), lwM2MClient.getRegistration());  
375 - 326 + @Override
  327 + public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
  328 + Set<String> registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet()
  329 + .stream()
  330 + .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId()))
  331 + .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new));
  332 + if (registrationIds.size() > 0) {
  333 + this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile);
  334 + }
376 } 335 }
377 336
378 /** 337 /**
379 - * If there is a difference in values between the current resource values and the shared attribute values  
380 - * when the client connects to the server  
381 - * #1 get attributes name from profile include name resources in ModelObject if resource isWritable  
382 - * #2.1 #1 size > 0 => send Request getAttributes to thingsboard  
383 - * #2.2 #1 size == 0 => continue normal process  
384 - *  
385 - * @param lwM2MClient - LwM2M Client 338 + * @param sessionInfo -
  339 + * @param device -
  340 + * @param deviceProfileOpt -
386 */ 341 */
387 - public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) {  
388 - SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration());  
389 - if (sessionInfo != null) {  
390 - //#1.1 + #1.2  
391 - List<String> attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient);  
392 - if (attrSharedNames.size() > 0) {  
393 - //#2.1  
394 - try {  
395 - TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getAdaptor().convertToGetAttributes(null, attrSharedNames);  
396 - lwM2MClient.getDelayedRequestsId().add(getAttributeMsg.getRequestId());  
397 - transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST));  
398 - } catch (AdaptorException e) {  
399 - log.warn("Failed to decode get attributes request", e);  
400 - }  
401 - }  
402 - // #2.2  
403 - else {  
404 - lwM2MClient.onSuccessOrErrorDelayedRequests(null);  
405 - }  
406 - } 342 + @Override
  343 + public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {
  344 + Optional<String> registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream()
  345 + .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid()))
  346 + .map(Map.Entry::getKey)
  347 + .findFirst();
  348 + registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt));
407 } 349 }
408 350
409 /** 351 /**
410 - * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values  
411 - * #1 Get path resource by result attributesResponse  
412 - * #1.1 If two names have equal path => last time attribute  
413 - * #2.1 if there is a difference in values between the current resource values and the shared attribute values  
414 - * => sent to client Request Update of value (new value from shared attribute)  
415 - * and LwM2MClient.delayedRequests.add(path)  
416 - * #2.1 if there is not a difference in values between the current resource values and the shared attribute values 352 + * Trigger Server path = "/1/0/8"
417 * 353 *
418 - * @param attributesResponse -  
419 - * @param sessionInfo - 354 + * Trigger bootStrap path = "/1/0/9" - have to implemented on client
420 */ 355 */
421 - public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {  
422 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(sessionInfo);  
423 - if (lwM2MClient.getDelayedRequestsId().contains(attributesResponse.getRequestId())) {  
424 - attributesResponse.getSharedAttributeListList().forEach(attr -> {  
425 - String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey());  
426 - // #1.1  
427 - if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) {  
428 - lwM2MClient.getDelayedRequests().put(path, attr);  
429 - } else {  
430 - lwM2MClient.getDelayedRequests().put(path, attr);  
431 - }  
432 - });  
433 - // #2.1  
434 - lwM2MClient.getDelayedRequests().forEach((k, v) -> {  
435 - ArrayList<TransportProtos.KeyValueProto> listV = new ArrayList<>();  
436 - listV.add(v.getKv());  
437 - this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k);  
438 - });  
439 - lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId());  
440 - if (lwM2MClient.getDelayedRequests().size() == 0) {  
441 - lwM2MClient.onSuccessOrErrorDelayedRequests(null);  
442 - }  
443 - }  
444 - }  
445 -  
446 - private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) {  
447 - if (valueNew != null && !valueNew.toString().equals(valueOld.toString())) {  
448 - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,  
449 - ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(),  
450 - true);  
451 - } 356 + @Override
  357 + public void doTrigger(LeshanServer lwServer, Registration registration, String path) {
  358 + lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE,
  359 + ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(),
  360 + false);
452 } 361 }
453 362
454 /** 363 /**
455 - * Get names and keyNames from profile shared!!!! attr resources IsWritable 364 + * Deregister session in transport
456 * 365 *
457 - * @param lwM2MClient -  
458 - * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable 366 + * @param sessionInfo - lwm2m client
459 */ 367 */
460 - private List<String> getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) {  
461 - LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid());  
462 - Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class);  
463 - ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class);  
464 -  
465 - ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet()  
466 - .stream()  
467 - .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null &&  
468 - context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable()))  
469 - .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));  
470 -  
471 - Set<String> namesIsWritable = ConcurrentHashMap.newKeySet();  
472 - namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values()));  
473 - return new ArrayList<>(namesIsWritable); 368 + @Override
  369 + public void doDisconnect(SessionInfoProto sessionInfo) {
  370 + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null);
  371 + transportService.deregisterSession(sessionInfo);
474 } 372 }
475 373
476 -  
477 /** 374 /**
478 - * Sent Attribute and Telemetry to Thingsboard  
479 - * #1 - get AttrName/TelemetryName with value:  
480 - * #1.1 from Client  
481 - * #1.2 from LwM2MClient:  
482 - * -- resourceId == path from LwM2MClientProfile.postAttributeProfile/postTelemetryProfile/postObserveProfile  
483 - * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId)  
484 - * #2 - set Attribute/Telemetry 375 + * Session device in thingsboard is closed
485 * 376 *
486 - * @param registration - Registration LwM2M Client 377 + * @param sessionInfo - lwm2m client
487 */ 378 */
488 - private void updateAttrTelemetry(Registration registration, boolean start, Set<String> paths) {  
489 - JsonObject attributes = new JsonObject();  
490 - JsonObject telemetries = new JsonObject();  
491 - if (start) {  
492 - // #1.1  
493 - JsonObject attributeClient = this.getAttributeClient(registration);  
494 - if (attributeClient != null) {  
495 - attributeClient.entrySet().forEach(p -> attributes.add(p.getKey(), p.getValue()));  
496 - }  
497 - }  
498 - // #1.2  
499 - try {  
500 - writeLock.lock();  
501 - this.getParametersFromProfile(attributes, telemetries, registration, paths);  
502 - } catch (Exception e) {  
503 - log.error("UpdateAttrTelemetry", e);  
504 - } finally {  
505 - writeLock.unlock();  
506 - }  
507 - if (attributes.getAsJsonObject().entrySet().size() > 0)  
508 - this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration);  
509 - if (telemetries.getAsJsonObject().entrySet().size() > 0)  
510 - this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration); 379 + private void doCloseSession(SessionInfoProto sessionInfo) {
  380 + TransportProtos.SessionEvent event = SessionEvent.CLOSED;
  381 + TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder()
  382 + .setSessionType(TransportProtos.SessionType.ASYNC)
  383 + .setEvent(event).build();
  384 + transportService.process(sessionInfo, msg, null);
511 } 385 }
512 386
513 /** 387 /**
514 - * get AttrName/TelemetryName with value from Client 388 + * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay,
  389 + * * if you need to do long time processing use a dedicated thread pool.
515 * 390 *
516 * @param registration - 391 * @param registration -
517 - * @return - JsonObject, format: {name: value}}  
518 */ 392 */
519 - private JsonObject getAttributeClient(Registration registration) {  
520 - if (registration.getAdditionalRegistrationAttributes().size() > 0) {  
521 - JsonObject resNameValues = new JsonObject();  
522 - registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty);  
523 - return resNameValues;  
524 - }  
525 - return null; 393 + protected void onAwakeDev(Registration registration) {
  394 + log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
  395 + //TODO: associate endpointId with device information.
526 } 396 }
527 397
528 /** 398 /**
529 - * @param attributes - new JsonObject  
530 - * @param telemetry - new JsonObject  
531 - * @param registration - Registration LwM2M Client  
532 - * result: add to JsonObject those resources to which the user is subscribed and they have a value  
533 - * if path==null add All resources else only one  
534 - * (attributes/telemetry): new {name(Attr/Telemetry):value} 399 + * This method is used to sync with sessions
  400 + * Removes a profile if not used in sessions
535 */ 401 */
536 - private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {  
537 - LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid());  
538 - lwM2MClientProfile.getPostAttributeProfile().forEach(p -> {  
539 - LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString());  
540 - if (pathIds.isResource()) {  
541 - if (path == null || path.contains(p.getAsString())) {  
542 - this.addParameters(p.getAsString().toString(), attributes, registration);  
543 - }  
544 - }  
545 - });  
546 - lwM2MClientProfile.getPostTelemetryProfile().forEach(p -> {  
547 - LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString());  
548 - if (pathIds.isResource()) {  
549 - if (path == null || path.contains(p.getAsString())) {  
550 - this.addParameters(p.getAsString().toString(), telemetry, registration);  
551 - } 402 + private void syncSessionsAndProfiles() {
  403 + Map<UUID, LwM2MClientProfile> profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet()
  404 + .stream()
  405 + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
  406 + profilesClone.forEach((k, v) -> {
  407 + String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet()
  408 + .stream()
  409 + .filter(e -> e.getValue().getProfileUuid().equals(k))
  410 + .findFirst()
  411 + .map(Map.Entry::getKey) // return the key of the matching entry if found
  412 + .orElse("");
  413 + if (registrationId.isEmpty()) {
  414 + lwM2mInMemorySecurityStore.getProfiles().remove(k);
552 } 415 }
553 }); 416 });
554 } 417 }
555 418
556 /** 419 /**
557 - * @param parameters - JsonObject attributes/telemetry  
558 - * @param registration - Registration LwM2M Client  
559 - */  
560 - private void addParameters(String path, JsonObject parameters, Registration registration) {  
561 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registration.getId());  
562 - JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile();  
563 - String resName = String.valueOf(names.get(path));  
564 - if (resName != null && !resName.isEmpty()) {  
565 - try {  
566 - String resValue = this.getResourceValueToString(lwM2MClient, path);  
567 - if (resValue != null) {  
568 - parameters.addProperty(resName, resValue);  
569 - }  
570 - } catch (Exception e) {  
571 - log.error(e.getStackTrace().toString());  
572 - }  
573 - }  
574 - }  
575 -  
576 - /**  
577 - * Prepare Sent to Thigsboard callback - Attribute or Telemetry  
578 - *  
579 - * @param msg - JsonArray: [{name: value}]  
580 - * @param topicName - Api Attribute or Telemetry 420 + * @param msg - text msg
581 * @param registration - Id of Registration LwM2M Client 421 * @param registration - Id of Registration LwM2M Client
582 */ 422 */
583 - public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) {  
584 - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);  
585 - if (sessionInfo != null) {  
586 - context.sentParametersOnThingsboard(msg, topicName, sessionInfo);  
587 - } else {  
588 - log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null);  
589 - }  
590 - }  
591 -  
592 - /**  
593 - * Start observe  
594 - * #1 - Analyze:  
595 - * #1.1 path in observe == (attribute or telemetry)  
596 - * #2 Analyze after sent request (response):  
597 - * #2.1 First: lwM2MTransportRequest.sendResponse -> ObservationListener.newObservation  
598 - * #2.2 Next: ObservationListener.onResponse *  
599 - *  
600 - * @param lwServer - LeshanServer  
601 - * @param registration - Registration LwM2M Client  
602 - */  
603 - private void onSentObserveToClient(LeshanServer lwServer, Registration registration) {  
604 - if (lwServer.getObservationService().getObservations(registration).size() > 0) {  
605 - this.setCancelObservations(lwServer, registration);  
606 - }  
607 - LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId());  
608 - Set<String> clientInstances = this.getAllInstancesInClient(registration);  
609 - lwM2MClientProfile.getPostObserveProfile().forEach(p -> {  
610 - // #1.1  
611 - String target = p.getAsString().toString();  
612 - String[] resPath = target.split("/");  
613 - String instance = "/" + resPath[1] + "/" + resPath[2];  
614 - if (clientInstances.contains(instance)) {  
615 - // #2  
616 -// if (this.getResourceValueToString(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()), target) != null) {  
617 - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE,  
618 - null, null, null, null, this.context.getCtxServer().getTimeout(),  
619 - false);  
620 -// }  
621 - }  
622 - }); 423 + public void sentLogsToThingsboard(String msg, Registration registration) {
  424 + if (msg != null) {
  425 + JsonObject telemetries = new JsonObject();
  426 + telemetries.addProperty(LOG_LW2M_TELEMETRY, msg);
  427 + this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration);
  428 + }
623 } 429 }
624 430
625 - public void setCancelObservations(LeshanServer lwServer, Registration registration) {  
626 - if (registration != null) {  
627 - Set<Observation> observations = lwServer.getObservationService().getObservations(registration);  
628 - observations.forEach(observation -> this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString())); 431 +
  432 + /**
  433 + * // !!! Ok
  434 + * Prepare Sent to Thigsboard callback - Attribute or Telemetry
  435 + *
  436 + * @param msg - JsonArray: [{name: value}]
  437 + * @param topicName - Api Attribute or Telemetry
  438 + * @param registration - Id of Registration LwM2M Client
  439 + */
  440 + public void updateParametersOnThingsboard(JsonElement msg, String topicName, Registration registration) {
  441 + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
  442 + if (sessionInfo != null) {
  443 + context.sentParametersOnThingsboard(msg, topicName, sessionInfo);
  444 + } else {
  445 + log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registration, null);
629 } 446 }
630 } 447 }
631 448
632 /** 449 /**
633 - * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());  
634 - * At server side this will not remove the observation from the observation store, to do it you need to use  
635 - * {@code ObservationService#cancelObservation()} 450 + * #1 сlientOnlyObserveAfterConnect == true
  451 + * - Only Observe Request to the client marked as observe from the profile configuration.
  452 + * #2. сlientOnlyObserveAfterConnect == false & clientUpdateValueAfterConnect == false
  453 + * - Request to the client after registration to read the values of the resources marked as attribute or telemetry from the profile configuration.
  454 + * - then Observe Request to the client marked as observe from the profile configuration.
  455 + * #3. сlientOnlyObserveAfterConnect == false & clientUpdateValueAfterConnect == true
  456 + * После регистрации отправляю запрос на read всех ресурсов, котрые послк регистрации, а затем запрос на observe (edited)
  457 + * - Request to the client after registration to read all resource values for all objects
  458 + * - then Observe Request to the client marked as observe from the profile configuration.
  459 + *
  460 + * @param lwServer - LeshanServer
  461 + * @param registration - Registration LwM2M Client
  462 + * @param lwM2MClient - object with All parameters off client
636 */ 463 */
637 - public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) {  
638 - lwServer.getObservationService().cancelObservations(registration, path); 464 + private void setLwM2mFromClientValue(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, LwM2MClientProfile lwM2MClientProfile) {
  465 + Set<String> clientObjects = this.getAllOjectsInClient(registration);
  466 + if (clientObjects != null) {
  467 + // #2
  468 + if (!LwM2MTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile) && !LwM2MTransportHandler.getClientUpdateValueAfterConnect(lwM2MClientProfile)) {
  469 + this.onSentReadAttrTelemetryToClient(lwServer, registration);
  470 + }
  471 + // #3
  472 + else {
  473 + clientObjects.forEach(path -> {
  474 + lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
  475 + lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false);
  476 + });
  477 + }
  478 + }
  479 + // #1
  480 + this.onSentObserveToClient(lwServer, registration);
639 } 481 }
640 482
641 /** 483 /**
642 - * @param parameters - JsonArray postAttributeProfile/postTelemetryProfile  
643 - * @param path - recourse from postObserveProfile  
644 - * @return rez - true if path observe is in attribute/telemetry 484 + * @param registration -
  485 + * @param lwM2mObject -
  486 + * @param path -
645 */ 487 */
646 -// private boolean getValidateObserve(JsonElement parameters, String path) {  
647 -// AtomicBoolean rez = new AtomicBoolean(false);  
648 -// if (parameters.isJsonArray()) {  
649 -// parameters.getAsJsonArray().forEach(p -> {  
650 -// if (p.getAsString().toString().equals(path)) rez.set(true);  
651 -// }  
652 -// );  
653 -// } else if (parameters.isJsonObject()) {  
654 -// rez.set((parameters.getAsJsonObject().entrySet()).stream().map(json -> json.toString())  
655 -// .filter(path::equals).findAny().orElse(null) != null);  
656 -// }  
657 -// return rez.get();  
658 -// } 488 + private void updateObjectResourceValue(Registration registration, LwM2mObject lwM2mObject, String path) {
  489 + LwM2mPath pathIds = new LwM2mPath(path);
  490 + lwM2mObject.getInstances().forEach((instanceId, instance) -> {
  491 + String pathInstance = pathIds.toString() + "/" + instanceId;
  492 + this.updateObjectInstanceResourceValue(registration, instance, pathInstance);
  493 + });
  494 + }
659 495
660 /** 496 /**
661 - * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource  
662 - *  
663 - * @param registration - Registration LwM2M Client  
664 - * @param path - observe  
665 - * @param response - observe 497 + * @param registration -
  498 + * @param lwM2mObjectInstance -
  499 + * @param path -
666 */ 500 */
667 -  
668 - public void onObservationResponse(Registration registration, String path, ReadResponse response) {  
669 - if (response.getContent() != null) {  
670 - if (response.getContent() instanceof LwM2mObject) {  
671 - LwM2mObject lwM2mObject = (LwM2mObject) response.getContent();  
672 - } else if (response.getContent() instanceof LwM2mObjectInstance) {  
673 - LwM2mObjectInstance lwM2mObjectInstance = (LwM2mObjectInstance) response.getContent();  
674 - } else if (response.getContent() instanceof LwM2mResource) {  
675 - LwM2mResource lwM2mResource = (LwM2mResource) response.getContent();  
676 - this.onObservationSetResourcesValue(registration, lwM2mResource, path);  
677 -// } else if (response.getContent() instanceof LwM2mMultipleResource) {  
678 -// LwM2mMultipleResource resource = (LwM2mMultipleResource) response.getContent();  
679 -// this.onObservationSetResourcesValue(registration, null, resource.getValues(), path);  
680 - }  
681 - } 501 + private void updateObjectInstanceResourceValue(Registration registration, LwM2mObjectInstance lwM2mObjectInstance, String path) {
  502 + LwM2mPath pathIds = new LwM2mPath(path);
  503 + lwM2mObjectInstance.getResources().forEach((resourceId, resource) -> {
  504 + String pathRez = pathIds.toString() + "/" + resourceId;
  505 + this.updateResourcesValue(registration, resource, pathRez);
  506 + });
682 } 507 }
683 508
684 /** 509 /**
@@ -687,77 +512,53 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -687,77 +512,53 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
687 * #2 Update new Resources (replace old Resource Value on new Resource Value) 512 * #2 Update new Resources (replace old Resource Value on new Resource Value)
688 * 513 *
689 * @param registration - Registration LwM2M Client 514 * @param registration - Registration LwM2M Client
690 - * @param - LwM2mSingleResource response.getContent()  
691 - * @param - LwM2mSingleResource response.getContent() 515 + * @param - LwM2mSingleResource response.getContent()
  516 + * @param - LwM2mSingleResource response.getContent()
692 * @param path - resource 517 * @param path - resource
693 */ 518 */
694 - private void onObservationSetResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { 519 + private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
695 LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); 520 LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null);
696 lwM2MClient.updateResourceValue(path, lwM2mResource); 521 lwM2MClient.updateResourceValue(path, lwM2mResource);
697 - log.warn("upDateResize: [{}] [{}] [{}]", lwM2MClient.getEndPoint(), lwM2MClient.getResources().size(), path); 522 + log.warn("upDateResize: [{}] [{}]", lwM2MClient.getEndPoint(), path);
698 Set<String> paths = new HashSet<>(); 523 Set<String> paths = new HashSet<>();
699 paths.add(path); 524 paths.add(path);
700 this.updateAttrTelemetry(registration, false, paths); 525 this.updateAttrTelemetry(registration, false, paths);
701 } 526 }
702 527
703 /** 528 /**
704 - * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...)  
705 - * config attr/telemetry... in profile  
706 - */  
707 - public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) {  
708 - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList());  
709 - }  
710 -  
711 - /**  
712 - * Update - sent request in change value resources in Client  
713 - * Path to resources from profile equal keyName or from ModelObject equal name  
714 - * Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)  
715 - * Delete - nothing * 529 + * Sent Attribute and Telemetry to Thingsboard
  530 + * #1 - get AttrName/TelemetryName with value:
  531 + * #1.1 from Client
  532 + * #1.2 from LwM2MClient:
  533 + * -- resourceId == path from LwM2MClientProfile.postAttributeProfile/postTelemetryProfile/postObserveProfile
  534 + * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId)
  535 + * #2 - set Attribute/Telemetry
716 * 536 *
717 - * @param msg - 537 + * @param registration - Registration LwM2M Client
718 */ 538 */
719 - public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {  
720 - if (msg.getSharedUpdatedCount() > 0) {  
721 - JsonElement el = JsonConverter.toJson(msg);  
722 - el.getAsJsonObject().entrySet().forEach(de -> {  
723 - String path = this.getPathAttributeUpdate(sessionInfo, de.getKey());  
724 - String value = de.getValue().getAsString();  
725 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue();  
726 - LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));  
727 - ResourceModel resourceModel = context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path));  
728 - if (!path.isEmpty() && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) {  
729 - if (resourceModel != null && resourceModel.operations.isWritable()) {  
730 - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,  
731 - ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(),  
732 - false);  
733 - } else {  
734 - log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value);  
735 - String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value);  
736 - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration());  
737 - }  
738 - } else {  
739 - log.error("Attribute name - [{}] value - [{}] is not present as attribute in profile and cannot be updated", de.getKey(), value);  
740 - String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", de.getKey(), value);  
741 - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration());  
742 - }  
743 - });  
744 - } else if (msg.getSharedDeletedCount() > 0) {  
745 - log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); 539 + private void updateAttrTelemetry(Registration registration, boolean start, Set<String> paths) {
  540 + JsonObject attributes = new JsonObject();
  541 + JsonObject telemetries = new JsonObject();
  542 + if (start) {
  543 + // #1.1
  544 + JsonObject attributeClient = this.getAttributeClient(registration);
  545 + if (attributeClient != null) {
  546 + attributeClient.entrySet().forEach(p -> attributes.add(p.getKey(), p.getValue()));
  547 + }
746 } 548 }
747 - }  
748 -  
749 - /**  
750 - * Get path to resource from profile equal keyName or from ModelObject equal name  
751 - * Only for resource: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)  
752 - *  
753 - * @param sessionInfo -  
754 - * @param name -  
755 - * @return path if path isPresent in postProfile  
756 - */  
757 - private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) {  
758 - String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name);  
759 -// return !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdateModelObject(name);  
760 - return !profilePath.isEmpty() ? profilePath : null; 549 + // #1.2
  550 + try {
  551 + writeLock.lock();
  552 + this.getParametersFromProfile(attributes, telemetries, registration, paths);
  553 + } catch (Exception e) {
  554 + log.error("UpdateAttrTelemetry", e);
  555 + } finally {
  556 + writeLock.unlock();
  557 + }
  558 + if (attributes.getAsJsonObject().entrySet().size() > 0)
  559 + this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration);
  560 + if (telemetries.getAsJsonObject().entrySet().size() > 0)
  561 + this.updateParametersOnThingsboard(telemetries, DEVICE_TELEMETRY_TOPIC, registration);
761 } 562 }
762 563
763 /** 564 /**
@@ -780,85 +581,194 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -780,85 +581,194 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
780 return telemetriesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); 581 return telemetriesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent();
781 } 582 }
782 583
  584 + /**
  585 + * Start observe
  586 + * #1 - Analyze:
  587 + * #1.1 path in observe profile == client resource
  588 + *
  589 + * @param lwServer - LeshanServer
  590 + * @param registration - Registration LwM2M Client
  591 + */
  592 + private void onSentObserveToClient(LeshanServer lwServer, Registration registration) {
  593 + if (lwServer.getObservationService().getObservations(registration).size() > 0) {
  594 + this.setCancelObservations(lwServer, registration);
  595 + }
  596 + LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId());
  597 + Set<String> clientInstances = this.getAllInstancesInClient(registration);
  598 + lwM2MClientProfile.getPostObserveProfile().forEach(p -> {
  599 + // #1.1
  600 + String target = p.getAsString().toString();
  601 + String[] resPath = target.split("/");
  602 + String instance = "/" + resPath[1] + "/" + resPath[2];
  603 + if (clientInstances.contains(instance)) {
  604 + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE,
  605 + null, null, null, null, this.context.getCtxServer().getTimeout(),
  606 + false);
  607 + }
  608 + });
  609 + }
783 610
784 /** 611 /**
785 - * Get path to resource from profile equal keyName 612 + * Update parameters device in LwM2MClient
  613 + * If new deviceProfile != old deviceProfile => update deviceProfile
786 * 614 *
787 - * @param sessionInfo -  
788 - * @param name -  
789 - * @return - 615 + * @param registrationId -
  616 + * @param device -
790 */ 617 */
791 - private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {  
792 - LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));  
793 - return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()  
794 - .filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey)  
795 - .orElse(""); 618 + private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional<DeviceProfile> deviceProfileOpt) {
  619 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId);
  620 + lwM2MClient.setDeviceName(device.getName());
  621 + if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) {
  622 + Set<String> registrationIds = new HashSet<>();
  623 + registrationIds.add(registrationId);
  624 + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile));
  625 + }
  626 +
  627 + lwM2MClient.setProfileUuid(device.getDeviceProfileId().getId());
796 } 628 }
797 629
798 /** 630 /**
799 - * Update resource (attribute) value on thingsboard after update value in client 631 + * @param registration -
  632 + * @return - all object in client
  633 + */
  634 + private Set<String> getAllOjectsInClient(Registration registration) {
  635 + Set<String> clientObjects = ConcurrentHashMap.newKeySet();
  636 + Arrays.stream(registration.getObjectLinks()).forEach(url -> {
  637 + LwM2mPath pathIds = new LwM2mPath(url.getUrl());
  638 + if (pathIds.isObjectInstance()) {
  639 + clientObjects.add("/" + pathIds.getObjectId());
  640 + }
  641 + });
  642 + return (clientObjects.size() > 0) ? clientObjects : null;
  643 + }
  644 +
  645 + /**
  646 + * @param registration -
  647 + * @return all instances in client
  648 + */
  649 + private Set<String> getAllInstancesInClient(Registration registration) {
  650 + Set<String> clientInstances = ConcurrentHashMap.newKeySet();
  651 + Arrays.stream(registration.getObjectLinks()).forEach(url -> {
  652 + LwM2mPath pathIds = new LwM2mPath(url.getUrl());
  653 + if (pathIds.isObjectInstance()) {
  654 + clientInstances.add(url.getUrl());
  655 + }
  656 + });
  657 + return (clientInstances.size() > 0) ? clientInstances : null;
  658 + }
  659 +
  660 + private void onSentReadAttrTelemetryToClient(LeshanServer lwServer, Registration registration) {
  661 + LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId());
  662 + Set<String> clientInstances = this.getAllInstancesInClient(registration);
  663 + Set<String> attr = ConcurrentHashMap.newKeySet();
  664 + try {
  665 + attr = new ObjectMapper().readValue(lwM2MClientProfile.getPostAttributeProfile().getAsJsonArray().toString().getBytes(), Set.class);
  666 + attr.addAll(new ObjectMapper().readValue(lwM2MClientProfile.getPostTelemetryProfile().getAsJsonArray().toString().getBytes(), Set.class));
  667 + } catch (IOException e) {
  668 + e.printStackTrace();
  669 + }
  670 + attr.forEach(p -> {
  671 + // #1.1
  672 + String target = p;
  673 + String[] resPath = target.split("/");
  674 + String instance = "/" + resPath[1] + "/" + resPath[2];
  675 + if (clientInstances.contains(instance)) {
  676 + lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
  677 + null, null, null, this.context.getCtxServer().getTimeout(), false);
  678 + }
  679 + });
  680 + }
  681 +
  682 + /**
  683 + * get AttrName/TelemetryName with value from Client
800 * 684 *
801 * @param registration - 685 * @param registration -
802 - * @param path -  
803 - * @param request - 686 + * @return - JsonObject, format: {name: value}}
804 */ 687 */
805 - public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) {  
806 -// ResourceModel resource = context.getCtxServer().getResourceModel(registration, new LwM2mPath(path));  
807 -// if (resource.multiple) {  
808 - this.onObservationSetResourcesValue(registration, ((LwM2mResource) request.getNode()), path);  
809 -// } else {  
810 -// this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path);  
811 -// }  
812 - if (isDelayedUpdate) {  
813 - lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null)  
814 - .onSuccessOrErrorDelayedRequests(request.getPath().toString()); 688 + private JsonObject getAttributeClient(Registration registration) {
  689 + if (registration.getAdditionalRegistrationAttributes().size() > 0) {
  690 + JsonObject resNameValues = new JsonObject();
  691 + registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty);
  692 + return resNameValues;
815 } 693 }
  694 + return null;
  695 + }
  696 +
  697 + /**
  698 + * @param attributes - new JsonObject
  699 + * @param telemetry - new JsonObject
  700 + * @param registration - Registration LwM2M Client
  701 + * @param path
  702 + */
  703 + private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {
  704 + LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId());
  705 + lwM2MClientProfile.getPostAttributeProfile().forEach(p -> {
  706 + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString());
  707 + if (pathIds.isResource()) {
  708 + if (path == null || path.contains(p.getAsString())) {
  709 + this.addParameters(p.getAsString().toString(), attributes, registration);
  710 + }
  711 + }
  712 + });
  713 + lwM2MClientProfile.getPostTelemetryProfile().forEach(p -> {
  714 + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString());
  715 + if (pathIds.isResource()) {
  716 + if (path == null || path.contains(p.getAsString())) {
  717 + this.addParameters(p.getAsString().toString(), telemetry, registration);
  718 + }
  719 + }
  720 + });
816 } 721 }
817 722
818 /** 723 /**
819 - * @param sessionInfo -  
820 - * @param deviceProfile - 724 + * @param parameters - JsonObject attributes/telemetry
  725 + * @param registration - Registration LwM2M Client
821 */ 726 */
822 - public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {  
823 - Set<String> registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet()  
824 - .stream()  
825 - .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId()))  
826 - .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new));  
827 - if (registrationIds.size() > 0) {  
828 - this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile); 727 + private void addParameters(String path, JsonObject parameters, Registration registration) {
  728 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registration.getId());
  729 + JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile();
  730 + String resName = String.valueOf(names.get(path));
  731 + if (resName != null && !resName.isEmpty()) {
  732 + try {
  733 + String resValue = this.getResourceValueToString(lwM2MClient, path);
  734 + if (resValue != null) {
  735 + parameters.addProperty(resName, resValue);
  736 + }
  737 + } catch (Exception e) {
  738 + log.error(e.getStackTrace().toString());
  739 + }
829 } 740 }
830 } 741 }
831 742
832 /** 743 /**
833 - * @param sessionInfo -  
834 - * @param device -  
835 - * @param deviceProfileOpt - 744 + * @param path - path resource
  745 + * @return - value of Resource or null
836 */ 746 */
837 - public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {  
838 - Optional<String> registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream()  
839 - .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid()))  
840 - .map(Map.Entry::getKey)  
841 - .findFirst();  
842 - registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt)); 747 + private String getResourceValueToString(LwM2MClient lwM2MClient, String path) {
  748 + LwM2mPath pathIds = new LwM2mPath(path);
  749 + ResourceValue resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, pathIds);
  750 + return (resourceValue == null) ? null :
  751 + (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds);
  752 + }
  753 +
  754 +
  755 + private ResourceValue returnResourceValueFromLwM2MClient(LwM2MClient lwM2MClient, LwM2mPath pathIds) {
  756 + ResourceValue resourceValue = null;
  757 + if (pathIds.isResource()) {
  758 + resourceValue = lwM2MClient.getResources().get(pathIds.toString());
  759 + }
  760 + return resourceValue;
843 } 761 }
844 762
845 /** 763 /**
846 - * Update parameters device in LwM2MClient  
847 - * If new deviceProfile != old deviceProfile => update deviceProfile 764 + * Update resource (attribute) value on thingsboard after update value in client
848 * 765 *
849 - * @param registrationId -  
850 - * @param device - 766 + * @param registration -
  767 + * @param path -
  768 + * @param request -
851 */ 769 */
852 - private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional<DeviceProfile> deviceProfileOpt) {  
853 - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId);  
854 - lwM2MClient.setDeviceName(device.getName());  
855 - if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) {  
856 - Set<String> registrationIds = new HashSet<>();  
857 - registrationIds.add(registrationId);  
858 - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile));  
859 - }  
860 -  
861 - lwM2MClient.setProfileUuid(device.getDeviceProfileId().getId()); 770 + public void onWriteResponseOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) {
  771 + this.updateResourcesValue(registration, ((LwM2mResource) request.getNode()), path);
862 } 772 }
863 773
864 /** 774 /**
@@ -989,16 +899,6 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -989,16 +899,6 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
989 return analyzerParameters; 899 return analyzerParameters;
990 } 900 }
991 901
992 - private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap<String, String> keyNameOld, ConcurrentMap<String, String> keyNameNew) {  
993 - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();  
994 - Set<String> paths = keyNameNew.entrySet()  
995 - .stream()  
996 - .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey())))  
997 - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet();  
998 - analyzerParameters.setPathPostParametersAdd(paths);  
999 - return analyzerParameters;  
1000 - }  
1001 -  
1002 private ResultsAnalyzerParameters getAnalyzerParametersIn(Set<String> parametersObserve, Set<String> parameters) { 902 private ResultsAnalyzerParameters getAnalyzerParametersIn(Set<String> parametersObserve, Set<String> parameters) {
1003 ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters(); 903 ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
1004 analyzerParameters.setPathPostParametersAdd(parametersObserve 904 analyzerParameters.setPathPostParametersAdd(parametersObserve
@@ -1031,60 +931,147 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -1031,60 +931,147 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
1031 }); 931 });
1032 } 932 }
1033 933
  934 + private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap<String, String> keyNameOld, ConcurrentMap<String, String> keyNameNew) {
  935 + ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
  936 + Set<String> paths = keyNameNew.entrySet()
  937 + .stream()
  938 + .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey())))
  939 + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)).keySet();
  940 + analyzerParameters.setPathPostParametersAdd(paths);
  941 + return analyzerParameters;
  942 + }
  943 +
1034 private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set<String> paramAnallyzer) { 944 private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set<String> paramAnallyzer) {
1035 LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); 945 LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null);
1036 paramAnallyzer.forEach(p -> { 946 paramAnallyzer.forEach(p -> {
1037 - if (this.getResourceValue(lwM2MClient, new LwM2mPath(p)) != null) { 947 + if (this.returnResourceValueFromLwM2MClient(lwM2MClient, new LwM2mPath(p)) != null) {
1038 this.setCancelObservationRecourse(lwServer, registration, p); 948 this.setCancelObservationRecourse(lwServer, registration, p);
1039 } 949 }
1040 } 950 }
1041 ); 951 );
1042 } 952 }
1043 953
1044 - private ResourceValue getResourceValue(LwM2MClient lwM2MClient, LwM2mPath pathIds) {  
1045 - ResourceValue resourceValue = null;  
1046 - if (pathIds.isResource()) {  
1047 - resourceValue = lwM2MClient.getResources().get(pathIds.toString()); 954 + private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) {
  955 + if (valueNew != null && !valueNew.toString().equals(valueOld.toString())) {
  956 + lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
  957 + ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(),
  958 + true);
1048 } 959 }
1049 - return resourceValue;  
1050 } 960 }
1051 961
1052 /** 962 /**
1053 - * Trigger Server path = "/1/0/8" 963 + * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...)
  964 + * config attr/telemetry... in profile
  965 + */
  966 + public void onToTransportUpdateCredentials(TransportProtos.ToTransportUpdateCredentialsProto updateCredentials) {
  967 + log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList());
  968 + }
  969 +
  970 + /**
  971 + * Get path to resource from profile equal keyName or from ModelObject equal name
  972 + * Only for resource: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase)
1054 * 973 *
1055 - * Trigger bootStrap path = "/1/0/9" - have to implemented on client 974 + * @param sessionInfo -
  975 + * @param name -
  976 + * @return path if path isPresent in postProfile
1056 */ 977 */
1057 - public void doTrigger(LeshanServer lwServer, Registration registration, String path) {  
1058 - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE,  
1059 - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(),  
1060 - false); 978 + private String getPathAttributeUpdate(TransportProtos.SessionInfoProto sessionInfo, String name) {
  979 + String profilePath = this.getPathAttributeUpdateProfile(sessionInfo, name);
  980 + return !profilePath.isEmpty() ? profilePath : null;
1061 } 981 }
1062 982
1063 /** 983 /**
1064 - * Session device in thingsboard is closed 984 + * Get path to resource from profile equal keyName
1065 * 985 *
1066 - * @param sessionInfo - lwm2m client 986 + * @param sessionInfo -
  987 + * @param name -
  988 + * @return -
1067 */ 989 */
1068 - private void doCloseSession(SessionInfoProto sessionInfo) {  
1069 - TransportProtos.SessionEvent event = SessionEvent.CLOSED;  
1070 - TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder()  
1071 - .setSessionType(TransportProtos.SessionType.ASYNC)  
1072 - .setEvent(event).build();  
1073 - transportService.process(sessionInfo, msg, null); 990 + private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
  991 + LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
  992 + return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
  993 + .filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey)
  994 + .orElse("");
1074 } 995 }
1075 996
1076 /** 997 /**
1077 - * Deregister session in transport 998 + * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values
  999 + * #1 Get path resource by result attributesResponse
  1000 + * #1.1 If two names have equal path => last time attribute
  1001 + * #2.1 if there is a difference in values between the current resource values and the shared attribute values
  1002 + * => sent to client Request Update of value (new value from shared attribute)
  1003 + * and LwM2MClient.delayedRequests.add(path)
  1004 + * #2.1 if there is not a difference in values between the current resource values and the shared attribute values
1078 * 1005 *
1079 - * @param sessionInfo - lwm2m client 1006 + * @param attributesResponse -
  1007 + * @param sessionInfo -
1080 */ 1008 */
1081 - public void doDisconnect(SessionInfoProto sessionInfo) {  
1082 - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null);  
1083 - transportService.deregisterSession(sessionInfo); 1009 + public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) {
  1010 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(sessionInfo);
  1011 + attributesResponse.getSharedAttributeListList().forEach(attr -> {
  1012 + String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey());
  1013 + // #1.1
  1014 + if (lwM2MClient.getDelayedRequests().containsKey(path) && attr.getTs() > lwM2MClient.getDelayedRequests().get(path).getTs()) {
  1015 + lwM2MClient.getDelayedRequests().put(path, attr);
  1016 + } else {
  1017 + lwM2MClient.getDelayedRequests().put(path, attr);
  1018 + }
  1019 + });
  1020 + // #2.1
  1021 + lwM2MClient.getDelayedRequests().forEach((k, v) -> {
  1022 + ArrayList<TransportProtos.KeyValueProto> listV = new ArrayList<>();
  1023 + listV.add(v.getKv());
  1024 + this.putDelayedUpdateResourcesClient(lwM2MClient, this.getResourceValueToString(lwM2MClient, k), getJsonObject(listV).get(v.getKv().getKey()), k);
  1025 + });
1084 } 1026 }
1085 1027
1086 - private void checkInactivityAndReportActivity() {  
1087 - lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key))); 1028 + /**
  1029 + * @param lwM2MClient -
  1030 + * @return
  1031 + */
  1032 + private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) {
  1033 + if (lwM2MClient != null) {
  1034 + TransportProtos.ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse();
  1035 + if (msg == null || msg.getDeviceInfo() == null) {
  1036 + log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED);
  1037 + this.closeClientSession(lwM2MClient.getRegistration());
  1038 + return null;
  1039 + } else {
  1040 + return SessionInfoProto.newBuilder()
  1041 + .setNodeId(this.context.getNodeId())
  1042 + .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits())
  1043 + .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits())
  1044 + .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())
  1045 + .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
  1046 + .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
  1047 + .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
  1048 + .setDeviceName(msg.getDeviceInfo().getDeviceName())
  1049 + .setDeviceType(msg.getDeviceInfo().getDeviceType())
  1050 + .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
  1051 + .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB())
  1052 + .build();
  1053 + }
  1054 + }
  1055 + return null;
  1056 + }
  1057 +
  1058 +
  1059 + /**
  1060 + * @param registration - Registration LwM2M Client
  1061 + * @return - sessionInfo after access connect client
  1062 + */
  1063 + private SessionInfoProto getValidateSessionInfo(Registration registration) {
  1064 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null);
  1065 + return getNewSessionInfoProto(lwM2MClient);
  1066 + }
  1067 +
  1068 + /**
  1069 + * @param registrationId -
  1070 + * @return -
  1071 + */
  1072 + private SessionInfoProto getValidateSessionInfo(String registrationId) {
  1073 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId);
  1074 + return getNewSessionInfoProto(lwM2MClient);
1088 } 1075 }
1089 1076
1090 /** 1077 /**
@@ -1098,22 +1085,55 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { @@ -1098,22 +1085,55 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService {
1098 } 1085 }
1099 } 1086 }
1100 1087
1101 - public void sentLogsToThingsboard(String msg, Registration registration) {  
1102 - if (msg != null) {  
1103 - JsonObject telemetries = new JsonObject();  
1104 - telemetries.addProperty(LOG_LW2M_TELEMETRY, msg);  
1105 - this.updateParametersOnThingsboard(telemetries, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registration); 1088 + private void checkInactivityAndReportActivity() {
  1089 + lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key)));
  1090 + }
  1091 +
  1092 + /**
  1093 + * If there is a difference in values between the current resource values and the shared attribute values
  1094 + * when the client connects to the server
  1095 + * #1 get attributes name from profile include name resources in ModelObject if resource isWritable
  1096 + * #2.1 #1 size > 0 => send Request getAttributes to thingsboard
  1097 + *
  1098 + * @param lwM2MClient - LwM2M Client
  1099 + */
  1100 + public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) {
  1101 + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration());
  1102 + if (sessionInfo != null) {
  1103 + //#1.1 + #1.2
  1104 + List<String> attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient);
  1105 + if (attrSharedNames.size() > 0) {
  1106 + //#2.1
  1107 + try {
  1108 + TransportProtos.GetAttributeRequestMsg getAttributeMsg = context.getAdaptor().convertToGetAttributes(null, attrSharedNames);
  1109 + transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST));
  1110 + } catch (AdaptorException e) {
  1111 + log.warn("Failed to decode get attributes request", e);
  1112 + }
  1113 + }
1106 } 1114 }
1107 } 1115 }
1108 1116
  1117 +
1109 /** 1118 /**
1110 - * @param path - path resource  
1111 - * @return - value of Resource or null 1119 + * Get names and keyNames from profile shared!!!! attr resources IsWritable
  1120 + *
  1121 + * @param lwM2MClient -
  1122 + * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable
1112 */ 1123 */
1113 - private String getResourceValueToString(LwM2MClient lwM2MClient, String path) {  
1114 - LwM2mPath pathIds = new LwM2mPath(path);  
1115 - ResourceValue resourceValue = this.getResourceValue(lwM2MClient, pathIds);  
1116 - return (resourceValue == null) ? null :  
1117 - (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds); 1124 + private List<String> getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) {
  1125 + LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid());
  1126 + Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class);
  1127 + ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), ConcurrentHashMap.class);
  1128 +
  1129 + ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet()
  1130 + .stream()
  1131 + .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null &&
  1132 + context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable()))
  1133 + .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue));
  1134 +
  1135 + Set<String> namesIsWritable = ConcurrentHashMap.newKeySet();
  1136 + namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values()));
  1137 + return new ArrayList<>(namesIsWritable);
1118 } 1138 }
1119 } 1139 }
@@ -18,12 +18,8 @@ package org.thingsboard.server.transport.lwm2m.server.client; @@ -18,12 +18,8 @@ package org.thingsboard.server.transport.lwm2m.server.client;
18 import lombok.Data; 18 import lombok.Data;
19 import lombok.extern.slf4j.Slf4j; 19 import lombok.extern.slf4j.Slf4j;
20 import org.eclipse.leshan.core.node.LwM2mMultipleResource; 20 import org.eclipse.leshan.core.node.LwM2mMultipleResource;
21 -import org.eclipse.leshan.core.node.LwM2mObjectInstance;  
22 -import org.eclipse.leshan.core.node.LwM2mPath;  
23 import org.eclipse.leshan.core.node.LwM2mResource; 21 import org.eclipse.leshan.core.node.LwM2mResource;
24 import org.eclipse.leshan.core.node.LwM2mSingleResource; 22 import org.eclipse.leshan.core.node.LwM2mSingleResource;
25 -import org.eclipse.leshan.core.response.LwM2mResponse;  
26 -import org.eclipse.leshan.core.response.ReadResponse;  
27 import org.eclipse.leshan.server.californium.LeshanServer; 23 import org.eclipse.leshan.server.californium.LeshanServer;
28 import org.eclipse.leshan.server.registration.Registration; 24 import org.eclipse.leshan.server.registration.Registration;
29 import org.eclipse.leshan.server.security.SecurityInfo; 25 import org.eclipse.leshan.server.security.SecurityInfo;
@@ -33,7 +29,6 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServiceImpl; @@ -33,7 +29,6 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServiceImpl;
33 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; 29 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
34 30
35 import java.util.Map; 31 import java.util.Map;
36 -import java.util.Set;  
37 import java.util.UUID; 32 import java.util.UUID;
38 import java.util.concurrent.ConcurrentHashMap; 33 import java.util.concurrent.ConcurrentHashMap;
39 34
@@ -54,10 +49,10 @@ public class LwM2MClient implements Cloneable { @@ -54,10 +49,10 @@ public class LwM2MClient implements Cloneable {
54 private ValidateDeviceCredentialsResponseMsg credentialsResponse; 49 private ValidateDeviceCredentialsResponseMsg credentialsResponse;
55 private Map<String, String> attributes; 50 private Map<String, String> attributes;
56 private Map<String, ResourceValue> resources; 51 private Map<String, ResourceValue> resources;
57 - private Set<String> pendingRequests; 52 + // private Set<String> pendingRequests;
58 private Map<String, TransportProtos.TsKvProto> delayedRequests; 53 private Map<String, TransportProtos.TsKvProto> delayedRequests;
59 - private Set<Integer> delayedRequestsId;  
60 - private Map<String, LwM2mResponse> responses; 54 +// private Set<Integer> delayedRequestsId;
  55 +// private Map<String, LwM2mResponse> responses;
61 private final LwM2mValueConverterImpl converter; 56 private final LwM2mValueConverterImpl converter;
62 57
63 public Object clone() throws CloneNotSupportedException { 58 public Object clone() throws CloneNotSupportedException {
@@ -70,69 +65,76 @@ public class LwM2MClient implements Cloneable { @@ -70,69 +65,76 @@ public class LwM2MClient implements Cloneable {
70 this.securityInfo = securityInfo; 65 this.securityInfo = securityInfo;
71 this.credentialsResponse = credentialsResponse; 66 this.credentialsResponse = credentialsResponse;
72 this.attributes = new ConcurrentHashMap<>(); 67 this.attributes = new ConcurrentHashMap<>();
73 - this.pendingRequests = ConcurrentHashMap.newKeySet(); 68 +// this.pendingRequests = ConcurrentHashMap.newKeySet();
74 this.delayedRequests = new ConcurrentHashMap<>(); 69 this.delayedRequests = new ConcurrentHashMap<>();
75 this.resources = new ConcurrentHashMap<>(); 70 this.resources = new ConcurrentHashMap<>();
76 - this.delayedRequestsId = ConcurrentHashMap.newKeySet(); 71 +// this.delayedRequestsId = ConcurrentHashMap.newKeySet();
77 this.profileUuid = profileUuid; 72 this.profileUuid = profileUuid;
78 /** 73 /**
79 * Key <objectId>, response<Value -> instance -> resources: value...> 74 * Key <objectId>, response<Value -> instance -> resources: value...>
80 */ 75 */
81 - this.responses = new ConcurrentHashMap<>(); 76 +// this.responses = new ConcurrentHashMap<>();
82 this.converter = LwM2mValueConverterImpl.getInstance(); 77 this.converter = LwM2mValueConverterImpl.getInstance();
83 } 78 }
84 79
85 - /**  
86 - * Fill with data -> Model client  
87 - *  
88 - * @param path -  
89 - * @param response -  
90 - */  
91 - public void onSuccessHandler(String path, LwM2mResponse response) {  
92 - this.responses.put(path, response);  
93 - this.pendingRequests.remove(path);  
94 - if (this.pendingRequests.size() == 0) {  
95 - this.initValue();  
96 - this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this);  
97 - }  
98 - } 80 +// /**
  81 +// * Fill with data -> Model client
  82 +// *
  83 +// * @param path -
  84 +// * @param response -
  85 +// */
  86 +// public void onSuccessHandler(String path, LwM2mResponse response) {
  87 +// this.responses.put(path, response);
  88 +// this.pendingRequests.remove(path);
  89 +// if (this.pendingRequests.size() == 0) {
  90 +// this.initValue();
  91 +// this.lwM2MTransportServiceImpl.putDelayedUpdateResourcesThingsboard(this);
  92 +// }
  93 +// }
  94 +//
  95 +// private void initValue() {
  96 +// this.responses.forEach((key, lwM2mResponse) -> {
  97 +// LwM2mPath pathIds = new LwM2mPath(key);
  98 +// if (pathIds.isObjectInstance()) {
  99 +// ((LwM2mObjectInstance) ((ReadResponse) lwM2mResponse).getContent()).getResources().forEach((k, v) -> {
  100 +// String pathRez = pathIds.toString() + "/" + k;
  101 +// this.updateResourceValue(pathRez, v);
  102 +// });
  103 +// }
  104 +// else if (pathIds.isResource()) {
  105 +// this.updateResourceValue(pathIds.toString(), ((LwM2mResource) ((ReadResponse) lwM2mResponse).getContent()));
  106 +// }
  107 +// });
  108 +// if (this.responses.size() == 0) this.responses = new ConcurrentHashMap<>();
  109 +// }
99 110
100 - private void initValue() {  
101 - this.responses.forEach((key, lwM2mResponse) -> {  
102 - LwM2mPath pathIds = new LwM2mPath(key);  
103 - if (pathIds.isObjectInstance()) {  
104 - ((LwM2mObjectInstance) ((ReadResponse) lwM2mResponse).getContent()).getResources().forEach((k, v) -> {  
105 - String pathRez = pathIds.toString() + "/" + k;  
106 - this.updateResourceValue(pathRez, v);  
107 - });  
108 - }  
109 - else if (pathIds.isResource()) {  
110 - this.updateResourceValue(pathIds.toString(), ((LwM2mResource) ((ReadResponse) lwM2mResponse).getContent()));  
111 - }  
112 - });  
113 - if (this.responses.size() == 0) this.responses = new ConcurrentHashMap<>();  
114 - } 111 +// public void updateObjectInstanceResourceValue(String pathInst, LwM2mObjectInstance instance) {
  112 +// LwM2mPath pathIds = new LwM2mPath(pathInst);
  113 +// instance.getResources().forEach((k, v) -> {
  114 +// String pathRez = pathIds.toString() + "/" + k;
  115 +// this.updateResourceValue(pathRez, v);
  116 +// });
  117 +// }
115 118
116 public void updateResourceValue(String pathRez, LwM2mResource rez) { 119 public void updateResourceValue(String pathRez, LwM2mResource rez) {
117 - if (rez instanceof LwM2mMultipleResource){ 120 + if (rez instanceof LwM2mMultipleResource) {
118 this.resources.put(pathRez, new ResourceValue(rez.getValues(), null, true)); 121 this.resources.put(pathRez, new ResourceValue(rez.getValues(), null, true));
119 - }  
120 - else if (rez instanceof LwM2mSingleResource) { 122 + } else if (rez instanceof LwM2mSingleResource) {
121 this.resources.put(pathRez, new ResourceValue(null, rez.getValue(), false)); 123 this.resources.put(pathRez, new ResourceValue(null, rez.getValue(), false));
122 } 124 }
123 } 125 }
124 126
125 - /**  
126 - * if path != null  
127 - *  
128 - * @param path  
129 - */  
130 - public void onSuccessOrErrorDelayedRequests(String path) {  
131 - if (path != null) this.delayedRequests.remove(path);  
132 - if (this.delayedRequests.size() == 0 && this.getDelayedRequestsId().size() == 0) {  
133 - this.lwM2MTransportServiceImpl.updatesAndSentModelParameter(this);  
134 - }  
135 - } 127 +// /**
  128 +// * if path != null
  129 +// *
  130 +// * @param path
  131 +// */
  132 +// public void onSuccessOrErrorDelayedRequests(String path) {
  133 +// if (path != null) this.delayedRequests.remove(path);
  134 +// if (this.delayedRequests.size() == 0 && this.getDelayedRequestsId().size() == 0) {
  135 +// this.lwM2MTransportServiceImpl.updatesAndSentModelParameter(this);
  136 +// }
  137 +// }
136 138
137 } 139 }
138 140
@@ -21,14 +21,20 @@ @@ -21,14 +21,20 @@
21 <ng-template matTabContent> 21 <ng-template matTabContent>
22 <section [formGroup]="lwm2mDeviceProfileFormGroup"> 22 <section [formGroup]="lwm2mDeviceProfileFormGroup">
23 <div class="mat-padding" style="padding-bottom: 0px"> 23 <div class="mat-padding" style="padding-bottom: 0px">
24 - <mat-checkbox formControlName="clientUpdateValueAfterConnect" color="primary" 24 + <mat-checkbox formControlName="clientOnlyObserveAfterConnect" color="primary"
  25 + matTooltip="{{ translate.get('device-profile.lwm2m.client-only-observe-after-connect-tip',
  26 + { count: +lwm2mDeviceProfileFormGroup.get('clientOnlyObserveAfterConnect').value }) | async }}"
  27 + matTooltipPosition="above">
  28 + {{ translate.get('device-profile.lwm2m.client-only-observe-after-connect',
  29 + { count: +lwm2mDeviceProfileFormGroup.get('clientOnlyObserveAfterConnect').value }) | async }}
  30 + </mat-checkbox>
  31 + <mat-checkbox *ngIf="!lwm2mDeviceProfileFormGroup.get('clientOnlyObserveAfterConnect').value"
  32 + formControlName="clientUpdateValueAfterConnect" color="primary"
25 matTooltip="{{ translate.get('device-profile.lwm2m.client-update-value-after-connect-tip', 33 matTooltip="{{ translate.get('device-profile.lwm2m.client-update-value-after-connect-tip',
26 - { count: +lwm2mDeviceProfileFormGroup.get('clientUpdateValueAfterConnect').value,  
27 - value: lwm2mDeviceProfileFormGroup.get('clientUpdateValueAfterConnect').value }) | async }}" 34 + { count: +lwm2mDeviceProfileFormGroup.get('clientUpdateValueAfterConnect').value }) | async }}"
28 matTooltipPosition="above"> 35 matTooltipPosition="above">
29 {{ translate.get('device-profile.lwm2m.client-update-value-after-connect', 36 {{ translate.get('device-profile.lwm2m.client-update-value-after-connect',
30 - { count: +lwm2mDeviceProfileFormGroup.get('clientUpdateValueAfterConnect').value,  
31 - value: lwm2mDeviceProfileFormGroup.get('clientUpdateValueAfterConnect').value }) | async }} 37 + { count: +lwm2mDeviceProfileFormGroup.get('clientUpdateValueAfterConnect').value }) | async }}
32 </mat-checkbox> 38 </mat-checkbox>
33 </div> 39 </div>
34 <div class="mat-padding" style="padding-top: 0"> 40 <div class="mat-padding" style="padding-top: 0">
@@ -74,6 +74,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -74,6 +74,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
74 private deviceProfileService: DeviceProfileService, 74 private deviceProfileService: DeviceProfileService,
75 @Inject(WINDOW) private window: Window) { 75 @Inject(WINDOW) private window: Window) {
76 this.lwm2mDeviceProfileFormGroup = this.fb.group({ 76 this.lwm2mDeviceProfileFormGroup = this.fb.group({
  77 + clientOnlyObserveAfterConnect: [true, []],
77 clientUpdateValueAfterConnect: [false, []], 78 clientUpdateValueAfterConnect: [false, []],
78 objectIds: [null, Validators.required], 79 objectIds: [null, Validators.required],
79 observeAttrTelemetry: [null, Validators.required], 80 observeAttrTelemetry: [null, Validators.required],
@@ -144,6 +145,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -144,6 +145,7 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
144 145
145 private updateWriteValue = (value: ModelValue): void => { 146 private updateWriteValue = (value: ModelValue): void => {
146 this.lwm2mDeviceProfileFormGroup.patchValue({ 147 this.lwm2mDeviceProfileFormGroup.patchValue({
  148 + clientOnlyObserveAfterConnect: this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect,
147 clientUpdateValueAfterConnect: this.configurationValue.clientLwM2mSettings.clientUpdateValueAfterConnect, 149 clientUpdateValueAfterConnect: this.configurationValue.clientLwM2mSettings.clientUpdateValueAfterConnect,
148 objectIds: value, 150 objectIds: value,
149 observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value['objectsList']), 151 observeAttrTelemetry: this.getObserveAttrTelemetryObjects(value['objectsList']),
@@ -176,6 +178,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro @@ -176,6 +178,8 @@ export class Lwm2mDeviceProfileTransportConfigurationComponent implements Contro
176 178
177 private updateDeviceProfileValue(config): void { 179 private updateDeviceProfileValue(config): void {
178 if (this.lwm2mDeviceProfileFormGroup.valid) { 180 if (this.lwm2mDeviceProfileFormGroup.valid) {
  181 + this.configurationValue.clientLwM2mSettings.clientOnlyObserveAfterConnect =
  182 + config.clientOnlyObserveAfterConnect;
179 this.configurationValue.clientLwM2mSettings.clientUpdateValueAfterConnect = 183 this.configurationValue.clientLwM2mSettings.clientUpdateValueAfterConnect =
180 config.clientUpdateValueAfterConnect; 184 config.clientUpdateValueAfterConnect;
181 this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M); 185 this.updateObserveAttrTelemetryFromGroupToJson(config.observeAttrTelemetry.clientLwM2M);
@@ -97,7 +97,8 @@ export interface ProfileConfigModels { @@ -97,7 +97,8 @@ export interface ProfileConfigModels {
97 } 97 }
98 98
99 export interface ClientLwM2mSettings { 99 export interface ClientLwM2mSettings {
100 - clientUpdateValueAfterConnect: false; 100 + clientOnlyObserveAfterConnect: boolean;
  101 + clientUpdateValueAfterConnect: boolean;
101 } 102 }
102 export interface ObservableAttributes { 103 export interface ObservableAttributes {
103 observe: string[]; 104 observe: string[];
@@ -145,17 +146,26 @@ function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecur @@ -145,17 +146,26 @@ function getDefaultProfileBootstrapSecurityConfig(hostname: any): BootstrapSecur
145 }; 146 };
146 } 147 }
147 148
  149 +function getDefaultProfileObserveAttrConfig(): ObservableAttributes {
  150 + return {
  151 + observe: [],
  152 + attribute: [],
  153 + telemetry: [],
  154 + keyName: {}
  155 + };
  156 +}
  157 +
  158 +function getDefaultProfileClientLwM2mSettingsConfig(): ClientLwM2mSettings {
  159 + return {
  160 + clientOnlyObserveAfterConnect: true,
  161 + clientUpdateValueAfterConnect: false
  162 + };
  163 +}
  164 +
148 export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels { 165 export function getDefaultProfileConfig(hostname?: any): ProfileConfigModels {
149 return { 166 return {
150 - clientLwM2mSettings: {  
151 - clientUpdateValueAfterConnect: false  
152 - },  
153 - observeAttr: {  
154 - observe: [],  
155 - attribute: [],  
156 - telemetry: [],  
157 - keyName: {}  
158 - }, 167 + clientLwM2mSettings: getDefaultProfileClientLwM2mSettingsConfig(),
  168 + observeAttr: getDefaultProfileObserveAttrConfig(),
159 bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_HOST_NAME) 169 bootstrap: getDefaultProfileBootstrapSecurityConfig((hostname) ? hostname : DEFAULT_HOST_NAME)
160 }; 170 };
161 } 171 }
@@ -1103,6 +1103,8 @@ @@ -1103,6 +1103,8 @@
1103 "schedule-time-to": "To", 1103 "schedule-time-to": "To",
1104 "schedule-days-of-week-required": "At least one day of week should be selected.", 1104 "schedule-days-of-week-required": "At least one day of week should be selected.",
1105 "lwm2m": { 1105 "lwm2m": {
  1106 + "client-only-observe-after-connect": "{ count, plural, 1 {Only Observe Request to the client after registration} other {Read&Observe Request to the client after registration} }",
  1107 + "client-only-observe-after-connect-tip": "{ count, plural, 1 {Only Observe Request to the client marked as observe from the profile configuration.} other {Read Request to the client after registration to read the values of the resources then Observe Request to the client marked as observe from the profile configuration.} }",
1106 "client-update-value-after-connect": "{ count, plural, 1 {Request to the client after registration for All resource values} other {Request to the client after registration to read values only as attributes or telemetry} }", 1108 "client-update-value-after-connect": "{ count, plural, 1 {Request to the client after registration for All resource values} other {Request to the client after registration to read values only as attributes or telemetry} }",
1107 "client-update-value-after-connect-tip": "{ count, plural, 1 {Request to the client after registration to read all resource values for all objects} other {Request to the client after registration to read the values of the resources marked as attribute or telemetry from the profile configuration.} }", 1109 "client-update-value-after-connect-tip": "{ count, plural, 1 {Request to the client after registration to read all resource values for all objects} other {Request to the client after registration to read the values of the resources marked as attribute or telemetry from the profile configuration.} }",
1108 "object-list": "Object list", 1110 "object-list": "Object list",