Commit 1150d4e4f30180ae2c54e3bdca5f36e525c2772a

Authored by nickAS21
1 parent ca46f5fb

Lwm2m: backEnd: add saveDeviceWithCredential

... ... @@ -278,7 +278,6 @@ public class DeviceController extends BaseController {
278 278 try {
279 279 Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS);
280 280 DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials));
281   - //log.info("0 LwM2M CredentialsUpdate start)
282 281 tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null);
283 282 logEntityAction(device.getId(), device,
284 283 device.getCustomerId(),
... ...
... ... @@ -15,17 +15,32 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
  18 +import com.fasterxml.jackson.databind.ObjectMapper;
18 19 import lombok.extern.slf4j.Slf4j;
19 20 import org.springframework.security.access.prepost.PreAuthorize;
20   -import org.springframework.web.bind.annotation.*;
  21 +import org.springframework.web.bind.annotation.PathVariable;
  22 +import org.springframework.web.bind.annotation.RequestBody;
  23 +import org.springframework.web.bind.annotation.RequestMapping;
  24 +import org.springframework.web.bind.annotation.RequestMethod;
  25 +import org.springframework.web.bind.annotation.RequestParam;
  26 +import org.springframework.web.bind.annotation.ResponseBody;
  27 +import org.springframework.web.bind.annotation.RestController;
  28 +import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
  29 +import org.thingsboard.server.common.data.Device;
  30 +import org.thingsboard.server.common.data.EntityType;
  31 +import org.thingsboard.server.common.data.audit.ActionType;
21 32 import org.thingsboard.server.common.data.exception.ThingsboardException;
22 33 import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
23 34 import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
24 35 import org.thingsboard.server.common.data.page.PageData;
25 36 import org.thingsboard.server.common.data.page.PageLink;
  37 +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  38 +import org.thingsboard.server.common.data.security.DeviceCredentials;
26 39 import org.thingsboard.server.queue.util.TbCoreComponent;
  40 +import org.thingsboard.server.service.security.permission.Resource;
27 41
28 42 import java.util.List;
  43 +import java.util.Map;
29 44
30 45 @Slf4j
31 46 @RestController
... ... @@ -72,4 +87,40 @@ public class DeviceLwm2mController extends BaseController {
72 87 throw handleException(e);
73 88 }
74 89 }
  90 +
  91 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  92 + @RequestMapping(value = "/lwm2m/device-credentials", method = RequestMethod.POST)
  93 + @ResponseBody
  94 + public Device saveDeviceWithCredentials(@RequestBody (required=false) Map<Class<?>, Object> deviceWithDeviceCredentials) throws ThingsboardException {
  95 + ObjectMapper mapper = new ObjectMapper();
  96 + Device device = checkNotNull(mapper.convertValue(deviceWithDeviceCredentials.get(Device.class), Device.class));
  97 + DeviceCredentials credentials = checkNotNull(mapper.convertValue( deviceWithDeviceCredentials.get(DeviceCredentials.class), DeviceCredentials.class));
  98 + try {
  99 + device.setTenantId(getCurrentUser().getTenantId());
  100 + checkEntity(device.getId(), device, Resource.DEVICE);
  101 + Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials);
  102 + checkNotNull(savedDevice);
  103 +
  104 + tbClusterService.onDeviceChange(savedDevice, null);
  105 + tbClusterService.pushMsgToCore(new DeviceNameOrTypeUpdateMsg(savedDevice.getTenantId(),
  106 + savedDevice.getId(), savedDevice.getName(), savedDevice.getType()), null);
  107 + tbClusterService.onEntityStateChange(savedDevice.getTenantId(), savedDevice.getId(),
  108 + device.getId() == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
  109 +
  110 + logEntityAction(savedDevice.getId(), savedDevice,
  111 + savedDevice.getCustomerId(),
  112 + device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
  113 +
  114 + if (device.getId() == null) {
  115 + deviceStateService.onDeviceAdded(savedDevice);
  116 + } else {
  117 + deviceStateService.onDeviceUpdated(savedDevice);
  118 + }
  119 + return savedDevice;
  120 + } catch (Exception e) {
  121 + logEntityAction(emptyId(EntityType.DEVICE), device,
  122 + null, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
  123 + throw handleException(e);
  124 + }
  125 + }
75 126 }
... ...
... ... @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.DeviceProfileId;
27 27 import org.thingsboard.server.common.data.id.TenantId;
28 28 import org.thingsboard.server.common.data.page.PageData;
29 29 import org.thingsboard.server.common.data.page.PageLink;
  30 +import org.thingsboard.server.common.data.security.DeviceCredentials;
30 31 import org.thingsboard.server.dao.device.provision.ProvisionRequest;
31 32
32 33 import java.util.List;
... ... @@ -45,6 +46,8 @@ public interface DeviceService {
45 46
46 47 Device saveDeviceWithAccessToken(Device device, String accessToken);
47 48
  49 + Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials);
  50 +
48 51 Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, CustomerId customerId);
49 52
50 53 Device unassignDeviceFromCustomer(TenantId tenantId, DeviceId deviceId);
... ...
... ... @@ -20,7 +20,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
20 20 import lombok.EqualsAndHashCode;
21 21 import lombok.extern.slf4j.Slf4j;
22 22 import org.thingsboard.server.common.data.device.data.DeviceData;
23   -import org.thingsboard.server.common.data.device.profile.DeviceProfileData;
24 23 import org.thingsboard.server.common.data.id.CustomerId;
25 24 import org.thingsboard.server.common.data.id.DeviceId;
26 25 import org.thingsboard.server.common.data.id.DeviceProfileId;
... ... @@ -64,6 +63,17 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
64 63 this.setDeviceData(device.getDeviceData());
65 64 }
66 65
  66 + public Device updateDevice(Device device) {
  67 + this.tenantId = device.getTenantId();
  68 + this.customerId = device.getCustomerId();
  69 + this.name = device.getName();
  70 + this.type = device.getType();
  71 + this.label = device.getLabel();
  72 + this.deviceProfileId = device.getDeviceProfileId();
  73 + this.setDeviceData(device.getDeviceData());
  74 + return this;
  75 + }
  76 +
67 77 public TenantId getTenantId() {
68 78 return tenantId;
69 79 }
... ...
... ... @@ -45,15 +45,9 @@ import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient;
45 45 import javax.annotation.PostConstruct;
46 46 import java.io.File;
47 47 import java.io.IOException;
48   -import java.text.DateFormat;
49   -import java.text.SimpleDateFormat;
50   -import java.util.ArrayList;
51 48 import java.util.Arrays;
52   -import java.util.Collections;
53 49 import java.util.Date;
54 50 import java.util.LinkedList;
55   -import java.util.List;
56   -import java.util.Map;
57 51 import java.util.Optional;
58 52
59 53 @Slf4j
... ... @@ -127,14 +121,19 @@ public class LwM2MTransportHandler{
127 121
128 122 @PostConstruct
129 123 public void init() {
130   - LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service);
131   - this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener);
132   - this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener);
133   - this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener);
134   - lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service);
135   - this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener);
136   - this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener);
137   - this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener);
  124 + try {
  125 + LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service);
  126 + this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener);
  127 + this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener);
  128 + this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener);
  129 + lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service);
  130 + this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener);
  131 + this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener);
  132 + this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener);
  133 + }
  134 + catch (java.lang.NullPointerException e) {
  135 + log.error("init [{}]", e.toString());
  136 + }
138 137 }
139 138
140 139 public static NetworkConfig getCoapConfig() {
... ... @@ -150,7 +149,8 @@ public class LwM2MTransportHandler{
150 149 return coapConfig;
151 150 }
152 151
153   - public static String getValueTypeToString (Object value, ResourceModel.Type type) {
  152 + public static String getValueTypeToString (Object value, ResourceModel.Type type, int val) {
  153 + try{
154 154 switch (type) {
155 155 case STRING: // String
156 156 case OBJLNK: // ObjectLink
... ... @@ -160,16 +160,21 @@ public class LwM2MTransportHandler{
160 160 case BOOLEAN: // Boolean
161 161 return Boolean.toString((Boolean) value);
162 162 case FLOAT: // Double
163   - return Double.toString((Float)value);
  163 + return Double.toString((Double) value);
164 164 case TIME: // Date
165   - String DATE_FORMAT = "MMM d, yyyy HH:mm a";
166   - DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
167   - return formatter.format(new Date(Integer.toUnsignedLong((Integer) value)));
  165 + return Long.toString(((Date) value).getTime());
  166 +// String DATE_FORMAT = "MMM d, yyyy HH:mm a";
  167 +// DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
  168 +// return formatter.format(new Date(Integer.toUnsignedLong((Integer) value)));
168 169 case OPAQUE: // byte[] value, base64
169 170 return Hex.encodeHexString((byte[])value);
170 171 default:
171 172 return null;
172 173 }
  174 + } catch (Exception e) {
  175 + log.error(e.getStackTrace().toString());
  176 + return null;
  177 + }
173 178 }
174 179
175 180 public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
... ... @@ -305,28 +310,6 @@ public class LwM2MTransportHandler{
305 310 }
306 311 }
307 312
308   - /**
309   - * Equals to Map for values
310   - * @param map1 -
311   - * @param map2 -
312   - * @param <V> -
313   - * @return - true if equals
314   - */
315   - public static <V extends Comparable<V>> boolean mapsEquals(Map<?,V> map1, Map<?,V> map2) {
316   - List<V> values1 = new ArrayList<>(map1.values());
317   - List<V> values2 = new ArrayList<>(map2.values());
318   - Collections.sort(values1);
319   - Collections.sort(values2);
320   - return values1.equals(values2);
321   - }
322   -
323   - public static String convertCamelCase (String str) {
324   - str = str.toLowerCase().replace("/[^a-z ]+/g", " ");
325   - str = str.replace("/^(.)|\\s(.)/g", "$1");
326   - str = str.replace("/[^a-zA-Z]+/g", "");
327   - return str;
328   - }
329   -
330 313 public static String splitCamelCaseString(String s){
331 314 LinkedList<String> linkedListOut = new LinkedList<>();
332 315 LinkedList<String> linkedList = new LinkedList<String>((Arrays.asList(s.split(" "))));
... ...
... ... @@ -20,6 +20,7 @@ import org.eclipse.californium.core.coap.Response;
20 20 import org.eclipse.leshan.core.attributes.Attribute;
21 21 import org.eclipse.leshan.core.attributes.AttributeSet;
22 22 import org.eclipse.leshan.core.model.ResourceModel;
  23 +import org.eclipse.leshan.core.node.LwM2mPath;
23 24 import org.eclipse.leshan.core.node.LwM2mSingleResource;
24 25 import org.eclipse.leshan.core.node.ObjectLink;
25 26 import org.eclipse.leshan.core.observation.Observation;
... ... @@ -50,6 +51,7 @@ import org.springframework.beans.factory.annotation.Autowired;
50 51 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
51 52 import org.springframework.stereotype.Service;
52 53 import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient;
  54 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
53 55
54 56 import javax.annotation.PostConstruct;
55 57 import java.util.ArrayList;
... ... @@ -79,16 +81,17 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandle
79 81 public class LwM2MTransportRequest {
80 82 private final ExecutorService executorService;
81 83 private static final String RESPONSE_CHANNEL = "THINGSBOARD_RESP";
  84 + private final LwM2mValueConverterImpl converter;
82 85
83 86 @Autowired
84 87 LwM2MTransportService service;
85 88
86 89 public LwM2MTransportRequest() {
  90 + this.converter = new LwM2mValueConverterImpl();
87 91 executorService = Executors.newCachedThreadPool(
88 92 new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL)));
89 93 }
90 94
91   -
92 95 @PostConstruct
93 96 public void init() {
94 97 }
... ... @@ -115,12 +118,12 @@ public class LwM2MTransportRequest {
115 118 */
116 119 public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper, String contentFormatParam,
117 120 LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs, boolean isDelayedUpdate) {
118   - ResultIds resultIds = new ResultIds(target);
  121 + LwM2mPath resultIds = new LwM2mPath(target);
119 122 if (registration != null && resultIds.getObjectId() >= 0) {
120 123 DownlinkRequest request = null;
121 124 ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null;
122   - ResourceModel resource = (resultIds.resourceId >= 0) ? (lwM2MClient != null) ?
123   - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.resourceId) : null : null;
  125 + ResourceModel resource = (resultIds.getResourceId() !=null && lwM2MClient != null) ?
  126 + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()) : null;
124 127 ResourceModel.Type resType = (resource == null) ? null : resource.type;
125 128 boolean resMultiple = (resource == null) ? false : resource.multiple;
126 129 timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
... ... @@ -132,10 +135,10 @@ public class LwM2MTransportRequest {
132 135 request = new DiscoverRequest(target);
133 136 break;
134 137 case GET_TYPE_OPER_OBSERVE:
135   - if (resultIds.getResourceId() >= 0) {
136   - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId());
137   - } else if (resultIds.getInstanceId() >= 0) {
138   - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getInstanceId());
  138 + if (resultIds.isResource()) {
  139 + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId());
  140 + } else if (resultIds.isObjectInstance()) {
  141 + request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId());
139 142 } else if (resultIds.getObjectId() >= 0) {
140 143 request = new ObserveRequest(resultIds.getObjectId());
141 144 }
... ... @@ -145,7 +148,8 @@ public class LwM2MTransportRequest {
145 148 break;
146 149 case POST_TYPE_OPER_EXECUTE:
147 150 if (params != null && !resMultiple) {
148   - request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType));
  151 +// request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType));
  152 + request = new ExecuteRequest(target, (String) this.converter.convertValue(params, resType, ResourceModel.Type.STRING, resultIds));
149 153 } else {
150 154 request = new ExecuteRequest(target);
151 155 }
... ... @@ -153,11 +157,11 @@ public class LwM2MTransportRequest {
153 157 case POST_TYPE_OPER_WRITE_REPLACE:
154 158 // Request to write a <b>String Single-Instance Resource</b> using the TLV content format.
155 159 if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) {
156   - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration);
  160 + request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration);
157 161 }
158 162 // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON)
159 163 else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) {
160   - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType, registration);
  164 + request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resType, registration);
161 165 }
162 166 break;
163 167 case PUT_TYPE_OPER_WRITE_UPDATE:
... ... @@ -202,10 +206,10 @@ public class LwM2MTransportRequest {
202 206 Attribute pmin = new Attribute(MINIMUM_PERIOD, Integer.toUnsignedLong(Integer.valueOf("1")));
203 207 Attribute[] attrs = {pmin};
204 208 AttributeSet attrSet = new AttributeSet(attrs);
205   - if (resultIds.getResourceId() >= 0) {
206   - request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), attrSet);
207   - } else if (resultIds.getInstanceId() >= 0) {
208   - request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getInstanceId(), attrSet);
  209 + if (resultIds.isResource()) {
  210 + request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(), attrSet);
  211 + } else if (resultIds.isObjectInstance()) {
  212 + request = new WriteAttributesRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), attrSet);
209 213 } else if (resultIds.getObjectId() >= 0) {
210 214 request = new WriteAttributesRequest(resultIds.getObjectId(), attrSet);
211 215 }
... ...
... ... @@ -64,7 +64,6 @@ import java.util.HashSet;
64 64 import java.util.List;
65 65 import java.util.Map;
66 66 import java.util.NoSuchElementException;
67   -import java.util.Objects;
68 67 import java.util.Optional;
69 68 import java.util.Random;
70 69 import java.util.Set;
... ... @@ -186,9 +185,9 @@ public class LwM2MTransportService {
186 185 if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) {
187 186 this.syncSessionsAndProfiles();
188 187 }
189   - log.info("Client: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
  188 + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
190 189 } else {
191   - log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
  190 + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
192 191 }
193 192 }
194 193
... ... @@ -242,15 +241,15 @@ public class LwM2MTransportService {
242 241 private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) {
243 242 // #1
244 243 Arrays.stream(registration.getObjectLinks()).forEach(url -> {
245   - ResultIds pathIds = new ResultIds(url.getUrl());
246   - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) {
  244 + LwM2mPath pathIds = new LwM2mPath(url.getUrl());
  245 + if (pathIds.isObjectInstance() && !pathIds.isResource()) {
247 246 lwM2MClient.getPendingRequests().add(url.getUrl());
248 247 }
249 248 });
250 249 // #2
251 250 Arrays.stream(registration.getObjectLinks()).forEach(url -> {
252   - ResultIds pathIds = new ResultIds(url.getUrl());
253   - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) {
  251 + LwM2mPath pathIds = new LwM2mPath(url.getUrl());
  252 + if (pathIds.isObjectInstance() && !pathIds.isResource()) {
254 253 lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ, ContentFormat.TLV.getName(),
255 254 lwM2MClient, null, null, this.context.getCtxServer().getTimeout(), false);
256 255 }
... ... @@ -361,10 +360,10 @@ public class LwM2MTransportService {
361 360 }
362 361 });
363 362 // #2.1
364   - lwM2MClient.getDelayedRequests().forEach((k, v)->{
  363 + lwM2MClient.getDelayedRequests().forEach((k, v) -> {
365 364 List listV = new ArrayList<TransportProtos.KeyValueProto>();
366 365 listV.add(v.getKv());
367   - this.putDelayedUpdateResourcesClient (lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k);
  366 + this.putDelayedUpdateResourcesClient(lwM2MClient, lwM2MClient.getResourceValue(k), getJsonObject(listV).get(v.getKv().getKey()), k);
368 367 System.out.printf(" k: %s, v: %s%n, v1: %s%n", k, v.getKv().getStringV(), lwM2MClient.getResourceValue(k));
369 368 });
370 369 lwM2MClient.getDelayedRequestsId().remove(attributesResponse.getRequestId());
... ... @@ -374,7 +373,7 @@ public class LwM2MTransportService {
374 373 }
375 374 }
376 375
377   - private void putDelayedUpdateResourcesClient (LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path){
  376 + private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) {
378 377 if (!valueOld.toString().equals(valueNew.toString())) {
379 378 lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
380 379 ContentFormat.TLV.getName(), lwM2MClient, null, valueNew, this.context.getCtxServer().getTimeout(),
... ... @@ -465,18 +464,20 @@ public class LwM2MTransportService {
465 464 private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {
466 465 AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid());
467 466 attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> {
468   - ResultIds pathIds = new ResultIds(p.getAsString().toString());
469   - if (pathIds.getResourceId() > -1) {
  467 +// ResultIds pathIds = new ResultIds(p.getAsString().toString());
  468 + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString());
  469 + if (pathIds.isResource()) {
470 470 if (path == null || path.contains(p.getAsString())) {
471   - this.addParameters(p.getAsString().toString(), attributes, registration);
  471 + this.addParameters(p.getAsString().toString(), attributes, registration, "attributes");
472 472 }
473 473 }
474 474 });
475 475 attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> {
476   - ResultIds pathIds = new ResultIds(p.getAsString().toString());
477   - if (pathIds.getResourceId() > -1) {
  476 +// ResultIds pathIds = new ResultIds(p.getAsString().toString());
  477 + LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString());
  478 + if (pathIds.isResource()) {
478 479 if (path == null || path.contains(p.getAsString())) {
479   - this.addParameters(p.getAsString().toString(), telemetry, registration);
  480 + this.addParameters(p.getAsString().toString(), telemetry, registration, "telemetry");
480 481 }
481 482 }
482 483 });
... ... @@ -486,13 +487,19 @@ public class LwM2MTransportService {
486 487 * @param parameters - JsonObject attributes/telemetry
487 488 * @param registration - Registration LwM2M Client
488 489 */
489   - private void addParameters(String path, JsonObject parameters, Registration registration) {
  490 + private void addParameters(String path, JsonObject parameters, Registration registration, String nameParam) {
490 491 JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile();
491 492 String resName = String.valueOf(names.get(path));
492 493 if (resName != null && !resName.isEmpty()) {
493   - String resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path);
494   - if (resValue != null) {
495   - parameters.addProperty(resName, resValue);
  494 + String resValue = null;
  495 + try {
  496 + resValue = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path);
  497 + if (resValue != null) {
  498 +// log.info("addParameters Path: [{}] ResValue : [{}] nameParam [{}]", path, lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getResourceValue(path), nameParam);
  499 + parameters.addProperty(resName, resValue);
  500 + }
  501 + } catch (Exception e) {
  502 + log.error(e.getStackTrace().toString());
496 503 }
497 504 }
498 505 }
... ... @@ -629,42 +636,73 @@ public class LwM2MTransportService {
629 636 * @param path - resource
630 637 */
631 638 private void onObservationSetResourcesValue(Registration registration, Object value, Map<Integer, ?> values, String path) {
632   - ResultIds resultIds = new ResultIds(path);
633   - // #1
634   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId());
635   - ModelObject modelObject = lwM2MClient.getModelObjects().get(resultIds.getObjectId());
636   - Map<Integer, LwM2mObjectInstance> instancesModelObject = modelObject.getInstances();
637   - LwM2mObjectInstance instanceOld = (instancesModelObject.get(resultIds.instanceId) != null) ? instancesModelObject.get(resultIds.instanceId) : null;
638   - Map<Integer, LwM2mResource> resourcesOld = (instanceOld != null) ? instanceOld.getResources() : null;
639   - LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null;
640   - // #2
641   - LwM2mResource resourceNew;
642   - if (Objects.requireNonNull(resourceOld).isMultiInstances()) {
643   - resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resourceOld.getType());
644   - } else {
645   - resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resourceOld.getType());
646   - }
647   - //#3
648   - Map<Integer, LwM2mResource> resourcesNew = new HashMap<>(resourcesOld);
649   - // #4
650   - resourcesNew.remove(resourceOld);
651   - // #5
652   - resourcesNew.put(resultIds.getResourceId(), resourceNew);
653   - // #6
654   - LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.instanceId, resourcesNew.values());
655   - // #7
656   - CountDownLatch respLatch = new CountDownLatch(1);
657   - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.instanceId);
658   - instancesModelObject.put(resultIds.instanceId, instanceNew);
659   - respLatch.countDown();
660 639 try {
661   - respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
662   - } catch (InterruptedException ex) {
663   - ex.printStackTrace();
  640 + CountDownLatch respLatch = new CountDownLatch(1);
  641 + try {
  642 + // #1
  643 + LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId());
  644 + LwM2mPath resultIds = new LwM2mPath(path);
  645 + log.warn("#0 nameDevice: [{}] resultIds: [{}] value: [{}], values: [{}] ", lwM2MClient.getDeviceName(), resultIds, value, values);
  646 + ResourceModel.Type resType = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).type;
  647 + Map<Integer, LwM2mObjectInstance> instancesModelObject = (lwM2MClient.getModelObjects().get(resultIds.getObjectId()) != null) ? lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances() : null;
  648 + Map<Integer, LwM2mResource> resourcesOld = null;
  649 + try {
  650 + CountDownLatch respResLatch = new CountDownLatch(1);
  651 + try {
  652 + resourcesOld = (instancesModelObject != null &&
  653 + instancesModelObject.get(resultIds.getObjectInstanceId()) != null &&
  654 + instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() != null) ? instancesModelObject.get(resultIds.getObjectInstanceId()).getResources() : null;
  655 +
  656 + } finally {
  657 + respResLatch.countDown();
  658 + }
  659 + try {
  660 + respResLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
  661 + } catch (InterruptedException ex) {
  662 + ex.printStackTrace();
  663 + log.error("#1_2 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value);
  664 + }
  665 + } catch (Exception e) {
  666 + e.printStackTrace();
  667 + log.error("#1_2_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value);
  668 + }
  669 + LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null;
  670 + // #2
  671 + LwM2mResource resourceNew = null;
  672 + if ((resourceOld != null && resourceOld.isMultiInstances() && !resourceOld.getValues().equals(values)) ||
  673 + (resourceOld == null && value == null)) {
  674 + resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resType);
  675 + } else if ((resourceOld != null && !resourceOld.isMultiInstances() && !resourceOld.getValue().equals(values)) ||
  676 + (resourceOld == null && value != null)) {
  677 + resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resType);
  678 + }
  679 + if (resourceNew != null) {
  680 + //#3
  681 + Map<Integer, LwM2mResource> resourcesNew = (resourcesOld == null) ? new HashMap<>() : new HashMap<>(resourcesOld);
  682 + // #4
  683 + if ((resourceOld != null)) resourcesNew.remove(resourceOld);
  684 + // #5
  685 + resourcesNew.put(resultIds.getResourceId(), resourceNew);
  686 + // #6
  687 + LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.getObjectInstanceId(), resourcesNew.values());
  688 + // #7
  689 + lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.getObjectInstanceId());
  690 + instancesModelObject.put(resultIds.getObjectInstanceId(), instanceNew);
  691 + Set<String> paths = new HashSet<>();
  692 + paths.add(path);
  693 + this.updateAttrTelemetry(registration, false, paths);
  694 + }
  695 + } finally {
  696 + respLatch.countDown();
  697 + }
  698 + try {
  699 + respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
  700 + } catch (InterruptedException ex) {
  701 + ex.printStackTrace();
  702 + log.error("#1_1 Update ResourcesValue after Observation in CountDownLatch is unsuccessfully path: [{}] value: [{}]", path, value);
  703 + }
  704 + } catch (Exception ignored) {
664 705 }
665   - Set<String> paths = new HashSet<>();
666   - paths.add(path);
667   - this.updateAttrTelemetry(registration, false, paths);
668 706 }
669 707
670 708 /**
... ... @@ -696,7 +734,7 @@ public class LwM2MTransportService {
696 734 lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
697 735 ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout(),
698 736 false);
699   - log.info("[{}] path onAttributeUpdate", path);
  737 +// log.info("[{}] path onAttributeUpdate", path);
700 738 } else {
701 739 log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value);
702 740 String logMsg = String.format(LOG_LW2M_ERROR + ": attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value);
... ... @@ -728,7 +766,7 @@ public class LwM2MTransportService {
728 766
729 767 /**
730 768 * @param profile -
731   - * @param path -
  769 + * @param path -
732 770 * @return true if path isPresent in postAttributeProfile
733 771 */
734 772 private boolean validatePathInAttrProfile(AttrTelemetryObserveValue profile, String path) {
... ... @@ -738,7 +776,7 @@ public class LwM2MTransportService {
738 776
739 777 /**
740 778 * @param profile -
741   - * @param path -
  779 + * @param path -
742 780 * @return true if path isPresent in postAttributeProfile
743 781 */
744 782 private boolean validatePathInTelemetryProfile(AttrTelemetryObserveValue profile, String path) {
... ... @@ -793,9 +831,10 @@ public class LwM2MTransportService {
793 831 * @param request -
794 832 */
795 833 public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request, boolean isDelayedUpdate) {
796   - ResultIds resultIds = new ResultIds(path);
  834 +// ResultIds resultIds = new ResultIds(path);
  835 + LwM2mPath resultIds = new LwM2mPath(path);
797 836 LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(registration.getId());
798   - LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getInstanceId()).getResource(resultIds.getResourceId());
  837 + LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getObjectInstanceId()).getResource(resultIds.getResourceId());
799 838 if (resource.isMultiInstances()) {
800 839 this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path);
801 840 } else {
... ... @@ -996,9 +1035,10 @@ public class LwM2MTransportService {
996 1035 */
997 1036 private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set<String> targets, String typeOper) {
998 1037 targets.forEach(target -> {
999   - ResultIds pathIds = new ResultIds(target);
1000   - if (pathIds.resourceId >= 0 && lwM2MClient.getModelObjects().get(pathIds.getObjectId())
1001   - .getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) {
  1038 +// ResultIds pathIds = new ResultIds(target);
  1039 + LwM2mPath pathIds = new LwM2mPath(target);
  1040 + if (pathIds.isResource() && lwM2MClient.getModelObjects().get(pathIds.getObjectId())
  1041 + .getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) {
1002 1042 if (GET_TYPE_OPER_READ.equals(typeOper)) {
1003 1043 lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper,
1004 1044 ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout(),
... ... @@ -1024,9 +1064,10 @@ public class LwM2MTransportService {
1024 1064
1025 1065 private ResourceValue getResourceValue(LwM2MClient lwM2MClient, String path) {
1026 1066 ResourceValue resourceValue = null;
1027   - ResultIds pathIds = new ResultIds(path);
1028   - if (pathIds.getResourceId() > -1) {
1029   - LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId());
  1067 +// ResultIds pathIds = new ResultIds(path);
  1068 + LwM2mPath pathIds = new LwM2mPath(path);
  1069 + if (pathIds.isResource()) {
  1070 + LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getObjectInstanceId()).getResource(pathIds.getResourceId());
1030 1071 if (resource.isMultiInstances()) {
1031 1072 if (resource.getValues().size() > 0) {
1032 1073 resourceValue = new ResourceValue();
... ...
... ... @@ -44,7 +44,6 @@ public class LwM2mServerListener {
44 44 @Override
45 45 public void registered(Registration registration, Registration previousReg,
46 46 Collection<Observation> previousObsersations) {
47   -
48 47 service.onRegistered(lhServer, registration, previousObsersations);
49 48 }
50 49
... ... @@ -54,6 +53,7 @@ public class LwM2mServerListener {
54 53 @Override
55 54 public void updated(RegistrationUpdate update, Registration updatedRegistration,
56 55 Registration previousRegistration) {
  56 + log.info("updated");
57 57 service.updatedReg(lhServer, updatedRegistration);
58 58 }
59 59
... ... @@ -63,6 +63,7 @@ public class LwM2mServerListener {
63 63 @Override
64 64 public void unregistered(Registration registration, Collection<Observation> observations, boolean expired,
65 65 Registration newReg) {
  66 + log.info("unregistered");
66 67 service.unReg(registration, observations);
67 68 }
68 69
... ... @@ -71,11 +72,13 @@ public class LwM2mServerListener {
71 72 public final PresenceListener presenceListener = new PresenceListener() {
72 73 @Override
73 74 public void onSleeping(Registration registration) {
  75 + log.info("onSleeping");
74 76 service.onSleepingDev(registration);
75 77 }
76 78
77 79 @Override
78 80 public void onAwake(Registration registration) {
  81 + log.info("onAwake");
79 82 service.onAwakeDev(registration);
80 83 }
81 84 };
... ... @@ -92,8 +95,10 @@ public class LwM2mServerListener {
92 95 if (registration != null) {
93 96 try {
94 97 service.onObservationResponse(registration, observation.getPath().toString(), response);
95   - } catch (java.lang.NullPointerException e) {
96   - log.error(e.toString());
  98 + } catch (Exception e) {
  99 + e.printStackTrace();
  100 + log.error("onResponse");
  101 +
97 102 }
98 103 }
99 104 }
... ...
... ... @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j;
20 20 import org.eclipse.leshan.core.model.ObjectModel;
21 21 import org.eclipse.leshan.core.model.ResourceModel;
22 22 import org.eclipse.leshan.core.node.LwM2mObjectInstance;
  23 +import org.eclipse.leshan.core.node.LwM2mPath;
23 24 import org.eclipse.leshan.core.response.LwM2mResponse;
24 25 import org.eclipse.leshan.core.response.ReadResponse;
25 26 import org.eclipse.leshan.core.util.Hex;
... ... @@ -29,12 +30,11 @@ import org.eclipse.leshan.server.security.SecurityInfo;
29 30 import org.thingsboard.server.gen.transport.TransportProtos;
30 31 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
31 32 import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportService;
32   -import org.thingsboard.server.transport.lwm2m.server.ResultIds;
  33 +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
33 34
34   -import java.util.UUID;
35 35 import java.util.Map;
36 36 import java.util.Set;
37   -import java.util.Collection;
  37 +import java.util.UUID;
38 38 import java.util.concurrent.ConcurrentHashMap;
39 39 import java.util.stream.Collectors;
40 40
... ... @@ -61,6 +61,7 @@ public class LwM2MClient implements Cloneable {
61 61 private Map<String, TransportProtos.TsKvProto> delayedRequests;
62 62 private Set<Integer> delayedRequestsId;
63 63 private Map<String, LwM2mResponse> responses;
  64 + private final LwM2mValueConverterImpl converter;
64 65
65 66 public Object clone() throws CloneNotSupportedException {
66 67 return super.clone();
... ... @@ -81,11 +82,13 @@ public class LwM2MClient implements Cloneable {
81 82 * Key <objectId>, response<Value -> instance -> resources: value...>
82 83 */
83 84 this.responses = new ConcurrentHashMap<>();
  85 + this.converter = new LwM2mValueConverterImpl();
84 86 }
85 87
86 88 /**
87   - * Fill with data -> Model client
88   - * @param path -
  89 + * Fill with data -> Model client
  90 + *
  91 + * @param path -
89 92 * @param response -
90 93 */
91 94 public void onSuccessHandler(String path, LwM2mResponse response) {
... ... @@ -99,9 +102,9 @@ public class LwM2MClient implements Cloneable {
99 102
100 103 private void initValue() {
101 104 this.responses.forEach((key, resp) -> {
102   - ResultIds pathIds = new ResultIds(key);
103   - if (pathIds.getObjectId() > -1) {
104   - ObjectModel objectModel = ((Collection<ObjectModel>) this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels()).stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0);
  105 + LwM2mPath pathIds = new LwM2mPath(key);
  106 + if (pathIds.isObject() || pathIds.isObjectInstance() || pathIds.isResource()) {
  107 + ObjectModel objectModel = this.lwServer.getModelProvider().getObjectModel(registration).getObjectModels().stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0);
105 108 if (this.modelObjects.get(pathIds.getObjectId()) != null) {
106 109 this.modelObjects.get(pathIds.getObjectId()).getInstances().put(((ReadResponse) resp).getContent().getId(), (LwM2mObjectInstance) ((ReadResponse) resp).getContent());
107 110 } else {
... ... @@ -122,30 +125,39 @@ public class LwM2MClient implements Cloneable {
122 125 }
123 126
124 127 public ResourceModel.Operations getOperation(String path) {
125   - ResultIds resultIds = new ResultIds(path);
126   - return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations : ResourceModel.Operations.NONE;
  128 + LwM2mPath resultIds = new LwM2mPath(path);
  129 + return (this.getModelObjects().get(resultIds.getObjectId()) != null) ?
  130 + this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations :
  131 + ResourceModel.Operations.NONE;
127 132 }
128 133
129   - public String getResourceName (String path) {
130   - ResultIds resultIds = new ResultIds(path);
  134 + public String getResourceName(String path) {
  135 + LwM2mPath resultIds = new LwM2mPath(path);
131 136 return (this.getModelObjects().get(resultIds.getObjectId()) != null) ? this.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).name : "";
132 137 }
133 138
134 139 /**
135 140 * @param path - path resource
136 141 * @return - value of Resource or null
137   - */public String getResourceValue(String path) {
  142 + */
  143 + public String getResourceValue(String path) {
138 144 String resValue = null;
139   - ResultIds pathIds = new ResultIds(path);
  145 + LwM2mPath pathIds = new LwM2mPath(path);
140 146 ModelObject modelObject = this.getModelObjects().get(pathIds.getObjectId());
141   - if (modelObject != null && modelObject.getInstances().get(pathIds.getInstanceId()) != null) {
142   - LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId());
  147 +
  148 + if (modelObject != null && modelObject.getInstances().get(pathIds.getObjectInstanceId()) != null) {
  149 + LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getObjectInstanceId());
143 150 if (instance.getResource(pathIds.getResourceId()) != null) {
144   - resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ?
145   - Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() :
146   - (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ?
147   - instance.getResource(pathIds.getResourceId()).getValues().toString() :
148   - instance.getResource(pathIds.getResourceId()).getValue().toString();
  151 + try {
  152 + resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ?
  153 + Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() :
  154 + (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ?
  155 + instance.getResource(pathIds.getResourceId()).getValues().toString() :
  156 +// getValueTypeToString(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType());
  157 + (String) converter.convertValue(instance.getResource(pathIds.getResourceId()).getValue(), instance.getResource(pathIds.getResourceId()).getType(), ResourceModel.Type.STRING, pathIds);
  158 + } catch (Exception e) {
  159 + log.warn("getResourceValue [{}]", e.getStackTrace().toString());
  160 + }
149 161 }
150 162 }
151 163 return resValue;
... ...
... ... @@ -21,7 +21,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance;
21 21 import java.util.Map;
22 22
23 23 @Data
24   -public class ModelObject {
  24 +public class ModelObject implements Cloneable {
25 25 /**
26 26 * model one on all instance
27 27 * for each instance only id resource with parameters of resources (observe, attr, telemetry)
... ... @@ -38,4 +38,8 @@ public class ModelObject {
38 38 LwM2mObjectInstance instance = this.instances.get(id);
39 39 return this.instances.remove(id, instance);
40 40 }
  41 +
  42 + public ModelObject clone() throws CloneNotSupportedException {
  43 + return (ModelObject) super.clone();
  44 + }
41 45 }
... ...
... ... @@ -177,10 +177,40 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
177 177 return doSaveDevice(device, null);
178 178 }
179 179
  180 + @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}")
  181 + @Override
  182 + public Device saveDeviceWithCredentials(Device device, DeviceCredentials deviceCredentials) {
  183 + if (device.getId() == null) {
  184 + Device deviceWithName = this.findDeviceByTenantIdAndName(device.getTenantId(), device.getName());
  185 + device = deviceWithName == null ? device : deviceWithName.updateDevice(device);
  186 + }
  187 + Device savedDevice = this.saveDeviceWithoutCredentials(device);
  188 + deviceCredentials.setDeviceId(savedDevice.getId());
  189 + if (device.getId() == null) {
  190 + deviceCredentials = deviceCredentialsService.createDeviceCredentials(savedDevice.getTenantId(), deviceCredentials);
  191 + }
  192 + else {
  193 + deviceCredentials.setId(deviceCredentialsService.findDeviceCredentialsByDeviceId(device.getTenantId(), savedDevice.getId()).getId());
  194 + deviceCredentials = deviceCredentialsService.updateDeviceCredentials(device.getTenantId(), deviceCredentials);
  195 + }
  196 + return savedDevice;
  197 + }
  198 +
180 199 private Device doSaveDevice(Device device, String accessToken) {
  200 + Device savedDevice = this.saveDeviceWithoutCredentials(device);
  201 + if (device.getId() == null) {
  202 + DeviceCredentials deviceCredentials = new DeviceCredentials();
  203 + deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));
  204 + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
  205 + deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));
  206 + deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
  207 + }
  208 + return savedDevice;
  209 + }
  210 +
  211 + private Device saveDeviceWithoutCredentials(Device device) {
181 212 log.trace("Executing saveDevice [{}]", device);
182 213 deviceValidator.validate(device, Device::getTenantId);
183   - Device savedDevice;
184 214 try {
185 215 DeviceProfile deviceProfile;
186 216 if (device.getDeviceProfileId() == null) {
... ... @@ -198,8 +228,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
198 228 }
199 229 device.setType(deviceProfile.getName());
200 230 device.setDeviceData(syncDeviceData(deviceProfile, device.getDeviceData()));
201   -
202   - savedDevice = deviceDao.save(device.getTenantId(), device);
  231 + return deviceDao.save(device.getTenantId(), device);
203 232 } catch (Exception t) {
204 233 ConstraintViolationException e = extractConstraintViolationException(t).orElse(null);
205 234 if (e != null && e.getConstraintName() != null && e.getConstraintName().equalsIgnoreCase("device_name_unq_key")) {
... ... @@ -208,14 +237,6 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
208 237 throw t;
209 238 }
210 239 }
211   - if (device.getId() == null) {
212   - DeviceCredentials deviceCredentials = new DeviceCredentials();
213   - deviceCredentials.setDeviceId(new DeviceId(savedDevice.getUuidId()));
214   - deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
215   - deviceCredentials.setCredentialsId(!StringUtils.isEmpty(accessToken) ? accessToken : RandomStringUtils.randomAlphanumeric(20));
216   - deviceCredentialsService.createDeviceCredentials(device.getTenantId(), deviceCredentials);
217   - }
218   - return savedDevice;
219 240 }
220 241
221 242 private DeviceData syncDeviceData(DeviceProfile deviceProfile, DeviceData deviceData) {
... ... @@ -530,7 +551,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
530 551 @Override
531 552 protected void validateCreate(TenantId tenantId, Device device) {
532 553 DefaultTenantProfileConfiguration profileConfiguration =
533   - (DefaultTenantProfileConfiguration)tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
  554 + (DefaultTenantProfileConfiguration) tenantProfileCache.get(tenantId).getProfileData().getConfiguration();
534 555 long maxDevices = profileConfiguration.getMaxDevices();
535 556 validateNumberOfEntitiesPerTenant(tenantId, deviceDao, maxDevices, EntityType.DEVICE);
536 557 }
... ...
... ... @@ -121,6 +121,7 @@ import java.util.HashMap;
121 121 import java.util.List;
122 122 import java.util.Map;
123 123 import java.util.Optional;
  124 +import java.util.concurrent.ConcurrentHashMap;
124 125 import java.util.concurrent.ExecutorService;
125 126 import java.util.concurrent.Executors;
126 127 import java.util.concurrent.Future;
... ... @@ -1091,6 +1092,24 @@ public class RestClient implements ClientHttpRequestInterceptor, Closeable {
1091 1092 return restTemplate.postForEntity(baseURL + "/api/device/credentials", deviceCredentials, DeviceCredentials.class).getBody();
1092 1093 }
1093 1094
  1095 + public Optional<Device> saveDeviceWithCredentials(Device device, DeviceCredentials credentials) {
  1096 + try {
  1097 + Map<Class<?>, Object> deviceCredentials = new ConcurrentHashMap<>();
  1098 + deviceCredentials.put(Device.class, device);
  1099 + deviceCredentials.put(DeviceCredentials.class, credentials);
  1100 +// return restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class).getBody();
  1101 + ResponseEntity<Device> deviceOpt = restTemplate.postForEntity(baseURL + "/api/lwm2m/device-credentials", deviceCredentials, Device.class);
  1102 + return Optional.ofNullable(deviceOpt.getBody());
  1103 + } catch (HttpClientErrorException exception) {
  1104 + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
  1105 + return Optional.empty();
  1106 + } else {
  1107 + throw exception;
  1108 + }
  1109 + }
  1110 + }
  1111 +
  1112 +
1094 1113 public PageData<Device> getTenantDevices(String type, PageLink pageLink) {
1095 1114 Map<String, String> params = new HashMap<>();
1096 1115 params.put("type", type);
... ...