Commit 24ccd2a2b54f5a6cf0de824c862178eb2cba9d63

Authored by Andrew Shvayka
1 parent df6151f5

Revert "[3.2.1] Develop/lwm2m (#3547)"

This reverts commit df6151f5.
Showing 49 changed files with 58 additions and 4439 deletions

Too many changes to show.

To preserve performance only 49 of 575 files are displayed.

... ... @@ -86,10 +86,6 @@
86 86 <artifactId>coap</artifactId>
87 87 </dependency>
88 88 <dependency>
89   - <groupId>org.thingsboard.common.transport</groupId>
90   - <artifactId>lwm2m</artifactId>
91   - </dependency>
92   - <dependency>
93 89 <groupId>org.thingsboard</groupId>
94 90 <artifactId>dao</artifactId>
95 91 </dependency>
... ...
... ... @@ -62,7 +62,7 @@ public class DeviceActor extends ContextAwareActor {
62 62 processor.processAttributesUpdate(ctx, (DeviceAttributesEventNotificationMsg) msg);
63 63 break;
64 64 case DEVICE_CREDENTIALS_UPDATE_TO_DEVICE_ACTOR_MSG:
65   - processor.processCredentialsUpdate(msg);
  65 + processor.processCredentialsUpdate();
66 66 break;
67 67 case DEVICE_NAME_OR_TYPE_UPDATE_TO_DEVICE_ACTOR_MSG:
68 68 processor.processNameOrTypeUpdate((DeviceNameOrTypeUpdateMsg) msg);
... ...
... ... @@ -24,7 +24,6 @@ import lombok.extern.slf4j.Slf4j;
24 24 import org.apache.commons.collections.CollectionUtils;
25 25 import org.thingsboard.rule.engine.api.RpcError;
26 26 import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
27   -import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
28 27 import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg;
29 28 import org.thingsboard.server.actors.ActorSystemContext;
30 29 import org.thingsboard.server.actors.TbActorCtx;
... ... @@ -37,9 +36,6 @@ import org.thingsboard.server.common.data.kv.AttributeKey;
37 36 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
38 37 import org.thingsboard.server.common.data.kv.KvEntry;
39 38 import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody;
40   -import org.thingsboard.server.common.data.security.DeviceCredentials;
41   -import org.thingsboard.server.common.data.security.DeviceCredentialsType;
42   -import org.thingsboard.server.common.msg.TbActorMsg;
43 39 import org.thingsboard.server.common.msg.TbMsgMetaData;
44 40 import org.thingsboard.server.common.msg.queue.TbCallback;
45 41 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
... ... @@ -65,7 +61,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcResponseM
65 61 import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
66 62 import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg;
67 63 import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg;
68   -import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;
69 64 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
70 65 import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
71 66 import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg;
... ... @@ -455,19 +450,11 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
455 450 dumpSessions();
456 451 }
457 452
458   - void processCredentialsUpdate(TbActorMsg msg) {
459   - if (((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials().getCredentialsType() == DeviceCredentialsType.LWM2M_CREDENTIALS) {
460   - log.info("1) LwM2Mtype: ");
461   - sessions.forEach((k, v) -> {
462   - notifyTransportAboutProfileUpdate(k, v, ((DeviceCredentialsUpdateNotificationMsg) msg).getDeviceCredentials());
463   - });
464   - } else {
465   - sessions.forEach(this::notifyTransportAboutClosedSession);
466   - attributeSubscriptions.clear();
467   - rpcSubscriptions.clear();
468   - dumpSessions();
469   -
470   - }
  453 + void processCredentialsUpdate() {
  454 + sessions.forEach(this::notifyTransportAboutClosedSession);
  455 + attributeSubscriptions.clear();
  456 + rpcSubscriptions.clear();
  457 + dumpSessions();
471 458 }
472 459
473 460 private void notifyTransportAboutClosedSession(UUID sessionId, SessionInfoMetaData sessionMd) {
... ... @@ -478,18 +465,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
478 465 systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg);
479 466 }
480 467
481   - void notifyTransportAboutProfileUpdate(UUID sessionId, SessionInfoMetaData sessionMd, DeviceCredentials deviceCredentials) {
482   - log.info("2) LwM2Mtype: ");
483   - TransportProtos.ToTransportUpdateCredentialsProto.Builder notification = TransportProtos.ToTransportUpdateCredentialsProto.newBuilder();
484   - notification.addCredentialsId(deviceCredentials.getCredentialsId());
485   - notification.addCredentialsValue(deviceCredentials.getCredentialsValue());
486   - ToTransportMsg msg = ToTransportMsg.newBuilder()
487   - .setSessionIdMSB(sessionId.getMostSignificantBits())
488   - .setSessionIdLSB(sessionId.getLeastSignificantBits())
489   - .setToTransportUpdateCredentialsNotification(notification).build();
490   - systemContext.getTbCoreToTransportService().process(sessionMd.getSessionInfo().getNodeId(), msg);
491   - }
492   -
493 468 void processNameOrTypeUpdate(DeviceNameOrTypeUpdateMsg msg) {
494 469 this.deviceName = msg.getDeviceName();
495 470 this.deviceType = msg.getDeviceType();
... ...
... ... @@ -92,7 +92,6 @@ import org.thingsboard.server.queue.discovery.PartitionService;
92 92 import org.thingsboard.server.queue.provider.TbQueueProducerProvider;
93 93 import org.thingsboard.server.queue.util.TbCoreComponent;
94 94 import org.thingsboard.server.service.component.ComponentDiscoveryService;
95   -import org.thingsboard.server.service.lwm2m.LwM2MModelsRepository;
96 95 import org.thingsboard.server.service.profile.TbDeviceProfileCache;
97 96 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
98 97 import org.thingsboard.server.service.queue.TbClusterService;
... ... @@ -212,9 +211,6 @@ public abstract class BaseController {
212 211 @Autowired
213 212 protected TbDeviceProfileCache deviceProfileCache;
214 213
215   - @Autowired
216   - protected LwM2MModelsRepository lwM2MModelsRepository;
217   -
218 214 @Value("${server.log_controller_error_stack_trace}")
219 215 @Getter
220 216 private boolean logControllerErrorStackTrace;
... ...
... ... @@ -278,8 +278,9 @@ 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   - tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null);
  281 +
  282 + tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId()), null);
  283 +
283 284 logEntityAction(device.getId(), device,
284 285 device.getCustomerId(),
285 286 ActionType.CREDENTIALS_UPDATED, null, deviceCredentials);
... ...
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.controller;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.springframework.security.access.prepost.PreAuthorize;
20   -import org.springframework.web.bind.annotation.*;
21   -import org.thingsboard.server.common.data.exception.ThingsboardException;
22   -import org.thingsboard.server.common.data.lwm2m.LwM2mObject;
23   -import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
24   -import org.thingsboard.server.common.data.page.PageData;
25   -import org.thingsboard.server.common.data.page.PageLink;
26   -import org.thingsboard.server.queue.util.TbCoreComponent;
27   -
28   -import java.util.List;
29   -
30   -@Slf4j
31   -@RestController
32   -@TbCoreComponent
33   -@RequestMapping("/api")
34   -public class DeviceLwm2mController extends BaseController {
35   -
36   -
37   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
38   - @RequestMapping(value = "/lwm2m/deviceProfile/{objectIds}", method = RequestMethod.GET)
39   - @ResponseBody
40   - public List<LwM2mObject> getLwm2mListObjects(@PathVariable("objectIds") int[] objectIds) throws ThingsboardException {
41   - try {
42   - return lwM2MModelsRepository.getLwm2mObjects(objectIds, null);
43   - } catch (Exception e) {
44   - throw handleException(e);
45   - }
46   - }
47   -
48   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
49   - @RequestMapping(value = "/lwm2m/deviceProfile/objects", params = {"pageSize", "page"}, method = RequestMethod.GET)
50   - @ResponseBody
51   - public PageData<LwM2mObject> getLwm2mListObjects(@RequestParam int pageSize,
52   - @RequestParam int page,
53   - @RequestParam(required = false) String textSearch,
54   - @RequestParam(required = false) String sortProperty,
55   - @RequestParam(required = false) String sortOrder) throws ThingsboardException {
56   - try {
57   - PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
58   - return checkNotNull(lwM2MModelsRepository.findDeviceLwm2mObjects(getTenantId(), pageLink));
59   - } catch (Exception e) {
60   - throw handleException(e);
61   - }
62   - }
63   -
64   - @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
65   - @RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{securityMode}/{bootstrapServerIs}", method = RequestMethod.GET)
66   - @ResponseBody
67   - public ServerSecurityConfig getLwm2mBootstrapSecurityInfo(@PathVariable("securityMode") String securityMode,
68   - @PathVariable("bootstrapServerIs") boolean bootstrapServerIs) throws ThingsboardException {
69   - try {
70   - return lwM2MModelsRepository.getBootstrapSecurityInfo(securityMode, bootstrapServerIs);
71   - } catch (Exception e) {
72   - throw handleException(e);
73   - }
74   - }
75   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.service.lwm2m;
17   -
18   -
19   -import lombok.extern.slf4j.Slf4j;
20   -import org.eclipse.leshan.core.model.ObjectModel;
21   -import org.eclipse.leshan.core.util.Hex;
22   -import org.springframework.beans.factory.annotation.Autowired;
23   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
24   -import org.springframework.data.domain.PageImpl;
25   -import org.springframework.stereotype.Service;
26   -import org.thingsboard.server.common.data.lwm2m.*;
27   -import org.thingsboard.server.common.data.id.TenantId;
28   -import org.thingsboard.server.common.data.page.PageData;
29   -import org.thingsboard.server.common.data.page.PageLink;
30   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap;
31   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
32   -import org.thingsboard.server.dao.service.Validator;
33   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
34   -
35   -import java.math.BigInteger;
36   -import java.security.*;
37   -import java.security.cert.CertificateEncodingException;
38   -import java.security.cert.X509Certificate;
39   -import java.security.spec.ECGenParameterSpec;
40   -import java.security.spec.ECParameterSpec;
41   -import java.security.spec.ECPublicKeySpec;
42   -import java.security.spec.ECPoint;
43   -import java.security.spec.KeySpec;
44   -import java.util.List;
45   -import java.util.ArrayList;
46   -import java.util.function.Predicate;
47   -import java.util.stream.Collectors;
48   -import java.util.stream.IntStream;
49   -
50   -import static org.thingsboard.server.dao.service.Validator.validateId;
51   -
52   -@Slf4j
53   -@Service
54   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'")
55   -public class LwM2MModelsRepository {
56   -
57   - private static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
58   -
59   - @Autowired
60   - LwM2MTransportConfigServer contextServer;
61   -
62   -
63   - @Autowired
64   - LwM2MTransportConfigBootstrap contextBootStrap;
65   -
66   - /**
67   - * @param objectIds
68   - * @param textSearch
69   - * @return list of LwM2mObject
70   - * Filter by Predicate (uses objectIds, if objectIds is null then it uses textSearch,
71   - * if textSearch is null then it uses AllList from List<ObjectModel>)
72   - */
73   - public List<LwM2mObject> getLwm2mObjects(int[] objectIds, String textSearch) {
74   - return getLwm2mObjects((objectIds != null && objectIds.length > 0) ?
75   - (ObjectModel element) -> IntStream.of(objectIds).anyMatch(x -> x == element.id) :
76   - (textSearch != null && !textSearch.isEmpty()) ? (ObjectModel element) -> element.name.contains(textSearch) : null);
77   - }
78   -
79   - /**
80   - * @param predicate
81   - * @return list of LwM2mObject
82   - */
83   - private List<LwM2mObject> getLwm2mObjects(Predicate<? super ObjectModel> predicate) {
84   - List<LwM2mObject> lwM2mObjects = new ArrayList<>();
85   - List<ObjectModel> listObjects = (predicate == null) ? this.contextServer.getModelsValue() :
86   - contextServer.getModelsValue().stream()
87   - .filter(predicate)
88   - .collect(Collectors.toList());
89   - listObjects.forEach(obj -> {
90   - LwM2mObject lwM2mObject = new LwM2mObject();
91   - lwM2mObject.setId(obj.id);
92   - lwM2mObject.setName(obj.name);
93   - lwM2mObject.setMultiple(obj.multiple);
94   - lwM2mObject.setMandatory(obj.mandatory);
95   - LwM2mInstance instance = new LwM2mInstance();
96   - instance.setId(0);
97   - List<LwM2mResource> resources = new ArrayList<>();
98   - obj.resources.forEach((k, v) -> {
99   - if (!v.operations.isExecutable()) {
100   - LwM2mResource resource = new LwM2mResource(k, v.name, false, false, false);
101   - resources.add(resource);
102   - }
103   - });
104   - instance.setResources(resources.stream().toArray(LwM2mResource[]::new));
105   - lwM2mObject.setInstances(new LwM2mInstance[]{instance});
106   - lwM2mObjects.add(lwM2mObject);
107   - });
108   - return lwM2mObjects;
109   - }
110   -
111   - /**
112   - * @param tenantId
113   - * @param pageLink
114   - * @return List of LwM2mObject in PageData format
115   - */
116   - public PageData<LwM2mObject> findDeviceLwm2mObjects(TenantId tenantId, PageLink pageLink) {
117   - log.trace("Executing findDeviceProfileInfos tenantId [{}], pageLink [{}]", tenantId, pageLink);
118   - validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
119   - Validator.validatePageLink(pageLink);
120   - return this.findLwm2mListObjects(pageLink);
121   - }
122   -
123   - /**
124   - * @param pageLink
125   - * @return List of LwM2mObject in PageData format, filter == TextSearch
126   - * PageNumber = 1, PageSize = List<LwM2mObject>.size()
127   - */
128   - public PageData<LwM2mObject> findLwm2mListObjects(PageLink pageLink) {
129   - PageImpl page = new PageImpl(getLwm2mObjects(null, pageLink.getTextSearch()));
130   - PageData pageData = new PageData(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext());
131   - return pageData;
132   - }
133   -
134   - /**
135   - *
136   - * @param securityMode
137   - * @param bootstrapServerIs
138   - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey
139   - */
140   - public ServerSecurityConfig getBootstrapSecurityInfo(String securityMode, boolean bootstrapServerIs) {
141   - LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(securityMode.toLowerCase());
142   - return getBootstrapServer(bootstrapServerIs, lwM2MSecurityMode);
143   - }
144   -
145   - /**
146   - *
147   - * @param bootstrapServerIs
148   - * @param mode
149   - * @return ServerSecurityConfig more value is default: Important - port, host, publicKey
150   - */
151   - private ServerSecurityConfig getBootstrapServer(boolean bootstrapServerIs, LwM2MSecurityMode mode) {
152   - ServerSecurityConfig bsServ = new ServerSecurityConfig();
153   - if (bootstrapServerIs) {
154   - switch (mode) {
155   - case NO_SEC:
156   - bsServ.setHost(contextBootStrap.getBootstrapHost());
157   - bsServ.setPort(contextBootStrap.getBootstrapPort());
158   - bsServ.setServerPublicKey("");
159   - break;
160   - case PSK:
161   - bsServ.setHost(contextBootStrap.getBootstrapSecureHost());
162   - bsServ.setPort(contextBootStrap.getBootstrapSecurePort());
163   - bsServ.setServerPublicKey("");
164   - break;
165   - case RPK:
166   - bsServ.setHost(contextBootStrap.getBootstrapSecureHost());
167   - bsServ.setPort(contextBootStrap.getBootstrapSecurePort());
168   - bsServ.setServerPublicKey(getRPKPublicKey(this.contextBootStrap.getBootstrapPublicX(), this.contextBootStrap.getBootstrapPublicY()));
169   - break;
170   - case X509:
171   - bsServ.setHost(contextBootStrap.getBootstrapSecureHost());
172   - bsServ.setPort(contextBootStrap.getBootstrapSecurePortCert());
173   - bsServ.setServerPublicKey(getServerPublicKeyX509(contextBootStrap.getBootstrapAlias()));
174   - break;
175   - default:
176   - break;
177   - }
178   - } else {
179   - bsServ.setBootstrapServerIs(bootstrapServerIs);
180   - bsServ.setServerId(123);
181   - switch (mode) {
182   - case NO_SEC:
183   - bsServ.setHost(contextServer.getServerHost());
184   - bsServ.setPort(contextServer.getServerPort());
185   - bsServ.setServerPublicKey("");
186   - break;
187   - case PSK:
188   - bsServ.setHost(contextServer.getServerSecureHost());
189   - bsServ.setPort(contextServer.getServerSecurePort());
190   - bsServ.setServerPublicKey("");
191   - break;
192   - case RPK:
193   - bsServ.setHost(contextServer.getServerSecureHost());
194   - bsServ.setPort(contextServer.getServerSecurePort());
195   - bsServ.setServerPublicKey(getRPKPublicKey(this.contextServer.getServerPublicX(), this.contextServer.getServerPublicY()));
196   - break;
197   - case X509:
198   - bsServ.setHost(contextServer.getServerSecureHost());
199   - bsServ.setPort(contextServer.getServerSecurePortCert());
200   - bsServ.setServerPublicKey(getServerPublicKeyX509(contextServer.getServerAlias()));
201   - break;
202   - default:
203   - break;
204   - }
205   - }
206   - return bsServ;
207   - }
208   -
209   - /**
210   - *
211   - * @param alias
212   - * @return PublicKey format HexString or null
213   - */
214   - private String getServerPublicKeyX509 (String alias) {
215   - try {
216   - X509Certificate serverCertificate = (X509Certificate) contextServer.getKeyStoreValue().getCertificate(alias);
217   - return Hex.encodeHexString(serverCertificate.getEncoded());
218   - } catch (CertificateEncodingException | KeyStoreException e) {
219   - e.printStackTrace();
220   - }
221   - return null;
222   - }
223   -
224   - /**
225   - *
226   - * @param publicServerX
227   - * @param publicServerY
228   - * @return PublicKey format HexString or null
229   - */
230   - private String getRPKPublicKey(String publicServerX, String publicServerY) {
231   - try {
232   - /** Get Elliptic Curve Parameter spec for secp256r1 */
233   - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
234   - algoParameters.init(new ECGenParameterSpec("secp256r1"));
235   - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
236   - if (publicServerX != null && !publicServerX.isEmpty() && publicServerY != null && !publicServerY.isEmpty()) {
237   - /** Get point values */
238   - byte[] publicX = Hex.decodeHex(publicServerX.toCharArray());
239   - byte[] publicY = Hex.decodeHex(publicServerY.toCharArray());
240   - /** Create key specs */
241   - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
242   - parameterSpec);
243   - /** Get keys */
244   - PublicKey publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
245   - if (publicKey != null && publicKey.getEncoded().length > 0 ) {
246   - return Hex.encodeHexString(publicKey.getEncoded());
247   - }
248   - }
249   - } catch (GeneralSecurityException | IllegalArgumentException e) {
250   - log.error("[{}] Failed generate Server RPK for profile", e.getMessage());
251   - throw new RuntimeException(e);
252   - }
253   - return null;
254   - }
255   -}
256   -
... ... @@ -53,8 +53,6 @@ public class DefaultDeviceAuthService implements DeviceAuthService {
53 53 return DeviceAuthResult.of(credentials.getDeviceId());
54 54 case X509_CERTIFICATE:
55 55 return DeviceAuthResult.of(credentials.getDeviceId());
56   - case LWM2M_CREDENTIALS:
57   - return DeviceAuthResult.of(credentials.getDeviceId());
58 56 default:
59 57 return DeviceAuthResult.of("Credentials Type is not supported yet!");
60 58 }
... ... @@ -67,4 +65,4 @@ public class DefaultDeviceAuthService implements DeviceAuthService {
67 65 }
68 66 }
69 67
70   -}
  68 +}
\ No newline at end of file
... ...
... ... @@ -201,7 +201,6 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
201 201 }
202 202
203 203 @Override
204   -
205 204 public void saveAndNotify(TenantId tenantId, EntityId entityId, String scope, List<AttributeKvEntry> attributes, FutureCallback<Void> callback) {
206 205 saveAndNotify(tenantId, entityId, scope, attributes, true, callback);
207 206 }
... ...
... ... @@ -69,7 +69,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponse
69 69 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
70 70 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg;
71 71 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg;
72   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
73 72 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
74 73 import org.thingsboard.server.queue.util.TbCoreComponent;
75 74 import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
... ... @@ -150,13 +149,6 @@ public class DefaultTransportApiService implements TransportApiService {
150 149 } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) {
151 150 return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()),
152 151 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
153   - } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) {
154   - return Futures.transform(handle(transportApiRequestMsg.getLwM2MRequestMsg()),
155   - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
156   - } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) {
157   - ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg();
158   - return Futures.transform(validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS),
159   - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
160 152 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) {
161 153 return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()),
162 154 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
... ... @@ -404,40 +396,4 @@ public class DefaultTransportApiService implements TransportApiService {
404 396 return TransportApiResponseMsg.newBuilder()
405 397 .setValidateCredResponseMsg(ValidateDeviceCredentialsResponseMsg.getDefaultInstance()).build();
406 398 }
407   -
408   - private ListenableFuture<TransportApiResponseMsg> handle(TransportProtos.LwM2MRequestMsg requestMsg) {
409   - if (requestMsg.hasRegistrationMsg()) {
410   - return handleRegistration(requestMsg.getRegistrationMsg());
411   - } else {
412   - return Futures.immediateFailedFuture(new RuntimeException("Not supported!"));
413   - }
414   - }
415   -
416   - private ListenableFuture<TransportApiResponseMsg> handleRegistration(TransportProtos.LwM2MRegistrationRequestMsg msg) {
417   - TenantId tenantId = new TenantId(UUID.fromString(msg.getTenantId()));
418   - String deviceName = msg.getEndpoint();
419   - Lock deviceCreationLock = deviceCreationLocks.computeIfAbsent(deviceName, id -> new ReentrantLock());
420   - deviceCreationLock.lock();
421   - try {
422   - Device device = deviceService.findDeviceByTenantIdAndName(tenantId, deviceName);
423   - if (device == null) {
424   - device = new Device();
425   - device.setTenantId(tenantId);
426   - device.setName(deviceName);
427   - device.setType("LwM2M");
428   - device = deviceService.saveDevice(device);
429   - deviceStateService.onDeviceAdded(device);
430   - }
431   - TransportProtos.LwM2MRegistrationResponseMsg registrationResponseMsg =
432   - TransportProtos.LwM2MRegistrationResponseMsg.newBuilder()
433   - .setDeviceInfo(getDeviceInfoProto(device)).build();
434   - TransportProtos.LwM2MResponseMsg responseMsg = TransportProtos.LwM2MResponseMsg.newBuilder().setRegistrationMsg(registrationResponseMsg).build();
435   - return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setLwM2MResponseMsg(responseMsg).build());
436   - } catch (JsonProcessingException e) {
437   - log.warn("[{}][{}] Failed to lookup device by gateway id and name", tenantId, deviceName, e);
438   - throw new RuntimeException(e);
439   - } finally {
440   - deviceCreationLock.unlock();
441   - }
442   - }
443 399 }
... ...
1   - ______ __ _ __ __
2   - /_ __/ / /_ (_) ____ ____ _ _____ / /_ ____ ____ _ _____ ____/ /
3   - / / / __ \ / / / __ \ / __ `/ / ___/ / __ \ / __ \ / __ `/ / ___/ / __ /
4   - / / / / / / / / / / / / / /_/ / (__ ) / /_/ // /_/ // /_/ / / / / /_/ /
5   -/_/ /_/ /_/ /_/ /_/ /_/ \__, / /____/ /_.___/ \____/ \__,_/ /_/ \__,_/
6   - /____/
7   -
8 1 ===================================================
9 2 :: ${application.title} :: ${application.formatted-version}
10 3 ===================================================
... ...
... ... @@ -433,7 +433,7 @@ spring:
433 433 database-platform: "${SPRING_JPA_DATABASE_PLATFORM:org.hibernate.dialect.PostgreSQLDialect}"
434 434 datasource:
435 435 driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}"
436   - url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard_ce_3_2_2}"
  436 + url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}"
437 437 username: "${SPRING_DATASOURCE_USERNAME:postgres}"
438 438 password: "${SPRING_DATASOURCE_PASSWORD:postgres}"
439 439 hikari:
... ... @@ -488,7 +488,7 @@ js:
488 488 # Built-in JVM JavaScript environment properties
489 489 local:
490 490 # Use Sandboxed (secured) JVM JavaScript environment
491   - use_js_sandbox: "${USE_LOCAL_JS_SANDBOX:false}"
  491 + use_js_sandbox: "${USE_LOCAL_JS_SANDBOX:true}"
492 492 # Specify thread pool size for JavaScript sandbox resource monitor
493 493 monitor_thread_pool_size: "${LOCAL_JS_SANDBOX_MONITOR_THREAD_POOL_SIZE:4}"
494 494 # Maximum CPU time in milliseconds allowed for script execution
... ... @@ -565,74 +565,6 @@ transport:
565 565 bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}"
566 566 bind_port: "${COAP_BIND_PORT:5683}"
567 567 timeout: "${COAP_TIMEOUT:10000}"
568   - # Local LwM2M transport parameters
569   - lwm2m:
570   - # Enable/disable lvm2m transport protocol.
571   - enabled: "${LWM2M_ENABLED:true}"
572   - # We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to
573   - # send a Confirmable message to the time when an acknowledgement is no longer expected.
574   - # DEFAULT_TIMEOUT = 2 * 60 * 1000l; 2 min in ms
575   - timeout: "${LWM2M_TIMEOUT:120000}"
576   -# model_path_file: "${LWM2M_MODEL_PATH_FILE:./common/transport/lwm2m/src/main/resources/models/}"
577   - model_path_file: "${LWM2M_MODEL_PATH_FILE:}"
578   - support_deprecated_ciphers_enable: "${LWM2M_SUPPORT_DEPRECATED_CIPHERS_ENABLED:true}"
579   - secure:
580   - # Only Certificate_x509:
581   - # To get helps about files format and how to generate it, see: https://github.com/eclipse/leshan/wiki/Credential-files-format
582   - # Create new X509 Certificates: common/transport/lwm2m/src/main/resources/credentials/shell/lwM2M_credentials.sh
583   - key_store_type: "${LWM2M_KEYSTORE_TYPE:JKS}"
584   - # key_store_type: "${LWM2M_KEYSTORE_TYPE:PKCS12}"
585   -# key_store_path_file: "${KEY_STORE_PATH_FILE:/usr/share/thingsboard/conf/credentials/serverKeyStore.jks}"
586   - key_store_path_file: "${KEY_STORE_PATH_FILE:}"
587   - key_store_password: "${LWM2M_KEYSTORE_PASSWORD_SERVER:server_ks_password}"
588   - root_alias: "${LWM2M_SERVER_ROOT_CA:rootca}"
589   - enable_gen_psk_rpk: "${ENABLE_GEN_PSK_RPK:true}"
590   - server:
591   - bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
592   - bind_port: "${LWM2M_BIND_PORT:5685}"
593   - bind_port_cert: "${LWM2M_BIND_PORT_CERT:5687}"
594   - secure:
595   - start_all: "${START_SERVER_ALL:true}"
596   - #leshan.core (V1_1)
597   - #DTLS security modes:
598   - #0: Pre-Shared Key mode
599   - #1: Raw Public Key mode
600   - #2: Certificate mode X509
601   - #3: NoSec mode *
602   - #OMA-TS-LightweightM2M_Core-V1_1_1-20190617-A (add)
603   - #4: Certificate mode X509 with EST
604   - # If only startAll == false
605   - dtls_mode: "${LWM2M_SECURITY_MODE:1}"
606   - bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}"
607   - bind_port: "${LWM2M_BIND_PORT_SEC:5686}"
608   - bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT:5688}"
609   - # Only RPK: Public & Private Key
610   -# create_rpk: "${CREATE_RPK:}"
611   - public_x: "${LWM2M_SERVER_PUBLIC_X:405354ea8893471d9296afbc8b020a5c6201b0bb25812a53b849d4480fa5f069}"
612   - public_y: "${LWM2M_SERVER_PUBLIC_Y:30c9237e946a3a1692c1cafaa01a238a077f632c99371348337512363f28212b}"
613   - private_s: "${LWM2M_SERVER_PRIVATE_S:274671fe40ce937b8a6352cf0a418e8a39e4bf0bb9bf74c910db953c20c73802}"
614   - # Only Certificate_x509:
615   - alias: "${LWM2M_KEYSTORE_ALIAS_SERVER:server}"
616   - bootstrap:
617   - enable: "${BOOTSTRAP:true}"
618   - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
619   - bind_port: "${LWM2M_BIND_PORT_BS:5689}"
620   - bind_port_cert: "${LWM2M_BIND_PORT_SER_BS:5691}"
621   - secure:
622   - start_all: "${START_BOOTSTRAP_ALL:true}"
623   - # If only startAll == false
624   - dtls_mode: "${LWM2M_SECURITY_MODE_BS:1}"
625   - bind_address: "${LWM2M_BIND_ADDRESS_BS:0.0.0.0}"
626   - bind_port: "${LWM2M_BIND_PORT_SEC_BS:5690}"
627   - bind_port_cert: "${LWM2M_BIND_PORT_SEC_CERT_BS:5692}"
628   - # Only RPK: Public & Private Key
629   - public_x: "${LWM2M_SERVER_PUBLIC_X_BS:993ef2b698c6a9c0c1d8be78b13a9383c0854c7c7c7a504d289b403794648183}"
630   - public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:267412d5fc4e5ceb2257cb7fd7f76ebdac2fa9aa100afb162e990074cc0bfaa2}"
631   - private_s: "${LWM2M_SERVER_PRIVATE_S_BS:9dbdbb073fc63570693a9aaf1013414e261c571f27e27fc6a8c1c2ad9347875a}"
632   - # Only Certificate_x509:
633   - alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}"
634   - # Redis
635   - redis_url: "${LWM2M_REDIS_URL:''}"
636 568
637 569 swagger:
638 570 api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}"
... ...
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.data.lwm2m;
17   -
18   -import lombok.Data;
19   -
20   -@Data
21   -public class LwM2mInstance {
22   - int id;
23   - LwM2mResource [] resources;
24   -
25   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.data.lwm2m;
17   -
18   -import lombok.Data;
19   -
20   -@Data
21   -public class LwM2mObject {
22   - int id;
23   - String name;
24   - boolean multiple;
25   - boolean mandatory;
26   - LwM2mInstance [] instances;
27   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.data.lwm2m;
17   -
18   -import lombok.AllArgsConstructor;
19   -import lombok.Data;
20   -
21   -import java.util.stream.Stream;
22   -
23   -@Data
24   -@AllArgsConstructor
25   -public class LwM2mResource {
26   - int id;
27   - String name;
28   - boolean observe;
29   - boolean attribute;
30   - boolean telemetry;
31   - String keyName;
32   -
33   - public LwM2mResource(int id, String name, boolean observe, boolean attribute, boolean telemetry) {
34   - this.id = id;
35   - this.name = name;
36   - this.observe = observe;
37   - this.attribute = attribute;
38   - this.telemetry = telemetry;
39   - this.keyName = getCamelCase (this.name);
40   - }
41   -
42   - private String getCamelCase (String name) {
43   - name = name.replaceAll("-", " ");
44   - name = name.replaceAll("_", " ");
45   - String [] nameCamel1 = name.split(" ");
46   - String [] nameCamel2 = new String[nameCamel1.length];
47   - int[] idx = { 0 };
48   - Stream.of(nameCamel1).forEach((s -> {
49   - nameCamel2[idx[0]] = toProperCase(idx[0]++, s);
50   - }));
51   - return String.join("", nameCamel2);
52   - }
53   -
54   - private String toProperCase(int idx, String s) {
55   - if (!s.isEmpty() && s.length()> 0) {
56   - String s1 = (idx == 0) ? s.substring(0, 1).toLowerCase() : s.substring(0, 1).toUpperCase();
57   - String s2 = "";
58   - if (s.length()> 1) s2 = s.substring(1).toLowerCase();
59   - s = s1 + s2;
60   - }
61   - return s;
62   - }
63   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.common.data.lwm2m;
17   -
18   -import lombok.Builder;
19   -import lombok.Data;
20   -
21   -@Data
22   -public class ServerSecurityConfig {
23   - String host;
24   - Integer port;
25   - String serverPublicKey;
26   - @Builder.Default
27   - boolean bootstrapServerIs = true;
28   - @Builder.Default
29   - Integer clientHoldOffTime = 1;
30   - @Builder.Default
31   - Integer serverId = 111;
32   - @Builder.Default
33   - Integer bootstrapServerAccountTimeout = 0;
34   -}
... ... @@ -19,8 +19,6 @@ public enum DeviceCredentialsType {
19 19
20 20 ACCESS_TOKEN,
21 21 X509_CERTIFICATE,
22   - MQTT_BASIC,
23   - LWM2M_CREDENTIALS
24   -
  22 + MQTT_BASIC
25 23
26 24 }
... ...
... ... @@ -183,47 +183,6 @@ message GetEntityProfileRequestMsg {
183 183 int64 entityIdLSB = 3;
184 184 }
185 185
186   -message LwM2MRegistrationRequestMsg {
187   - string tenantId = 1;
188   - string endpoint = 2;
189   -}
190   -
191   -message LwM2MRegistrationResponseMsg {
192   - DeviceInfoProto deviceInfo = 1;
193   -}
194   -
195   -message LwM2MRequestMsg {
196   - LwM2MRegistrationRequestMsg registrationMsg = 1;
197   -}
198   -
199   -message LwM2MResponseMsg {
200   - LwM2MRegistrationResponseMsg registrationMsg = 1;
201   -}
202   -
203   -message ValidateDeviceLwM2MCredentialsRequestMsg {
204   - string credentialsId = 1;
205   -}
206   -
207   -message ToTransportUpdateCredentialsProto {
208   - repeated string credentialsId = 1;
209   - repeated string credentialsValue = 2;
210   -}
211   -
212   -message GetTenantRoutingInfoRequestMsg {
213   - int64 tenantIdMSB = 1;
214   - int64 tenantIdLSB = 2;
215   -}
216   -
217   -message GetTenantRoutingInfoResponseMsg {
218   - bool isolatedTbCore = 1;
219   - bool isolatedTbRuleEngine = 2;
220   -}
221   -
222   -message GetDeviceProfileRequestMsg {
223   - int64 profileIdMSB = 1;
224   - int64 profileIdLSB = 2;
225   -}
226   -
227 186 message GetEntityProfileResponseMsg {
228 187 string entityType = 1;
229 188 bytes data = 2;
... ... @@ -520,10 +479,8 @@ message TransportApiRequestMsg {
520 479 ValidateDeviceX509CertRequestMsg validateX509CertRequestMsg = 2;
521 480 GetOrCreateDeviceFromGatewayRequestMsg getOrCreateDeviceRequestMsg = 3;
522 481 GetEntityProfileRequestMsg entityProfileRequestMsg = 4;
523   - LwM2MRequestMsg lwM2MRequestMsg = 5;
524 482 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6;
525 483 ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7;
526   - ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8;
527 484 }
528 485
529 486 /* Response from ThingsBoard Core Service to Transport Service */
... ... @@ -532,7 +489,6 @@ message TransportApiResponseMsg {
532 489 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2;
533 490 GetEntityProfileResponseMsg entityProfileResponseMsg = 3;
534 491 ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4;
535   - LwM2MResponseMsg lwM2MResponseMsg = 6;
536 492 }
537 493
538 494 /* Messages that are handled by ThingsBoard Core Service */
... ... @@ -573,10 +529,10 @@ message ToTransportMsg {
573 529 AttributeUpdateNotificationMsg attributeUpdateNotification = 5;
574 530 ToDeviceRpcRequestMsg toDeviceRequest = 6;
575 531 ToServerRpcResponseMsg toServerResponse = 7;
  532 + /* For Tenant, TenantProfile and DeviceProfile */
576 533 EntityUpdateMsg entityUpdateMsg = 8;
577 534 EntityDeleteMsg entityDeleteMsg = 9;
578 535 ProvisionDeviceResponseMsg provisionResponse = 10;
579   - ToTransportUpdateCredentialsProto toTransportUpdateCredentialsNotification = 11;
580 536 }
581 537
582 538 message UsageStatsKVProto{
... ...
... ... @@ -24,7 +24,6 @@ import org.springframework.stereotype.Component;
24 24 import org.thingsboard.server.common.transport.TransportContext;
25 25 import org.thingsboard.server.transport.coap.adaptors.CoapTransportAdaptor;
26 26
27   -
28 27 /**
29 28 * Created by ashvayka on 18.10.18.
30 29 */
... ...
... ... @@ -16,15 +16,14 @@
16 16 package org.thingsboard.server.transport.coap;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.californium.core.CoapObserveRelation;
20 19 import org.eclipse.californium.core.CoapResource;
21   -import org.eclipse.californium.core.coap.CoAP;
22 20 import org.eclipse.californium.core.coap.CoAP.ResponseCode;
23 21 import org.eclipse.californium.core.coap.Request;
24   -import org.eclipse.californium.core.network.Endpoint;
25 22 import org.eclipse.californium.core.network.Exchange;
  23 +import org.eclipse.californium.core.network.ExchangeObserver;
26 24 import org.eclipse.californium.core.server.resources.CoapExchange;
27 25 import org.eclipse.californium.core.server.resources.Resource;
  26 +import org.springframework.util.ReflectionUtils;
28 27 import org.thingsboard.server.common.data.DataConstants;
29 28 import org.thingsboard.server.common.data.DeviceTransportType;
30 29 import org.thingsboard.server.common.data.security.DeviceTokenCredentials;
... ... @@ -41,26 +40,26 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
41 40 import org.thingsboard.server.gen.transport.TransportProtos;
42 41 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceResponseMsg;
43 42
  43 +import java.lang.reflect.Field;
44 44 import java.util.List;
45 45 import java.util.Optional;
46 46 import java.util.Set;
47 47 import java.util.UUID;
48   -import java.util.Timer;
49   -import java.util.TimerTask;
50 48 import java.util.concurrent.ConcurrentHashMap;
51 49 import java.util.concurrent.ConcurrentMap;
52   -import java.util.concurrent.ScheduledThreadPoolExecutor;
53 50 import java.util.concurrent.atomic.AtomicInteger;
54 51 import java.util.function.Consumer;
55 52
56 53 @Slf4j
57 54 public class CoapTransportResource extends CoapResource {
  55 + // coap://localhost:port/api/v1/DEVICE_TOKEN/[attributes|telemetry|rpc[/requestId]]
58 56 private static final int ACCESS_TOKEN_POSITION = 3;
59 57 private static final int FEATURE_TYPE_POSITION = 4;
60 58 private static final int REQUEST_ID_POSITION = 5;
61 59
62 60 private final CoapTransportContext transportContext;
63 61 private final TransportService transportService;
  62 + private final Field observerField;
64 63 private final long timeout;
65 64 private final ConcurrentMap<String, TransportProtos.SessionInfoProto> tokenToSessionIdMap = new ConcurrentHashMap<>();
66 65 private final Set<UUID> rpcSubscriptions = ConcurrentHashMap.newKeySet();
... ... @@ -74,20 +73,9 @@ public class CoapTransportResource extends CoapResource {
74 73 // This is important to turn off existing observable logic in
75 74 // CoapResource. We will have our own observe monitoring due to 1:1
76 75 // observe relationship.
77   - this.setObservable(true); // enable observing
78   - this.setObserveType(CoAP.Type.CON); // configure the notification type to CONs
79   - this.getAttributes().setObservable(); // mark observable in the Link-Format
80   - // schedule a periodic update task, otherwise let events call changed()
81   - Timer timer = new Timer();
82   - timer.schedule(new UpdateTask(), 0, 5000);
83   - }
84   -
85   - private class UpdateTask extends TimerTask {
86   - @Override
87   - public void run() {
88   - // .. periodic update of the resource
89   - changed(); // notify all observers
90   - }
  76 + this.setObservable(false);
  77 + observerField = ReflectionUtils.findField(Exchange.class, "observer");
  78 + observerField.setAccessible(true);
91 79 }
92 80
93 81 @Override
... ... @@ -199,7 +187,9 @@ public class CoapTransportResource extends CoapResource {
199 187 new CoapOkCallback(exchange));
200 188 break;
201 189 case SUBSCRIBE_ATTRIBUTES_REQUEST:
202   - transportService.registerSyncSession(sessionInfo, new CoapSessionListener(sessionId, exchange), transportContext.getTimeout());
  190 + attributeSubscriptions.add(sessionId);
  191 + advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced),
  192 + registerAsyncCoapSession(exchange, request, sessionInfo, sessionId)));
203 193 transportService.process(sessionInfo,
204 194 TransportProtos.SubscribeToAttributeUpdatesMsg.getDefaultInstance(),
205 195 new CoapNoOpCallback(exchange));
... ... @@ -216,6 +206,8 @@ public class CoapTransportResource extends CoapResource {
216 206 break;
217 207 case SUBSCRIBE_RPC_COMMANDS_REQUEST:
218 208 rpcSubscriptions.add(sessionId);
  209 + advanced.setObserver(new CoapExchangeObserverProxy((ExchangeObserver) observerField.get(advanced),
  210 + registerAsyncCoapSession(exchange, request, sessionInfo, sessionId)));
219 211 transportService.process(sessionInfo,
220 212 TransportProtos.SubscribeToRPCMsg.getDefaultInstance(),
221 213 new CoapNoOpCallback(exchange));
... ... @@ -251,6 +243,9 @@ public class CoapTransportResource extends CoapResource {
251 243 } catch (AdaptorException e) {
252 244 log.trace("[{}] Failed to decode message: ", sessionId, e);
253 245 exchange.respond(ResponseCode.BAD_REQUEST);
  246 + } catch (IllegalAccessException e) {
  247 + log.trace("[{}] Failed to process message: ", sessionId, e);
  248 + exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR);
254 249 }
255 250 }));
256 251 }
... ... @@ -464,17 +459,24 @@ public class CoapTransportResource extends CoapResource {
464 459 }
465 460 }
466 461
467   - public class CoapExchangeObserverProxy extends CoapObserveRelation {
468   -
469   - /**
470   - * Constructs a new CoapObserveRelation with the specified request.
471   - *
472   - * @param request the request
473   - * @param endpoint the endpoint
474   - * @param executor
475   - */
476   - protected CoapExchangeObserverProxy(Request request, Endpoint endpoint, ScheduledThreadPoolExecutor executor) {
477   - super(request, endpoint, executor);
  462 + public class CoapExchangeObserverProxy implements ExchangeObserver {
  463 +
  464 + private final ExchangeObserver proxy;
  465 + private final String token;
  466 +
  467 + CoapExchangeObserverProxy(ExchangeObserver proxy, String token) {
  468 + super();
  469 + this.proxy = proxy;
  470 + this.token = token;
  471 + }
  472 +
  473 + @Override
  474 + public void completed(Exchange exchange) {
  475 + proxy.completed(exchange);
  476 + TransportProtos.SessionInfoProto session = tokenToSessionIdMap.remove(token);
  477 + if (session != null) {
  478 + closeAndDeregister(session);
  479 + }
478 480 }
479 481 }
480 482
... ...
... ... @@ -18,9 +18,8 @@ package org.thingsboard.server.transport.coap;
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.californium.core.CoapResource;
20 20 import org.eclipse.californium.core.CoapServer;
21   -
22 21 import org.eclipse.californium.core.network.CoapEndpoint;
23   -import org.eclipse.californium.core.network.CoapEndpoint.Builder;
  22 +import org.eclipse.californium.core.network.config.NetworkConfig;
24 23 import org.springframework.beans.factory.annotation.Autowired;
25 24 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
26 25 import org.springframework.stereotype.Service;
... ... @@ -48,15 +47,11 @@ public class CoapTransportService {
48 47 public void init() throws UnknownHostException {
49 48 log.info("Starting CoAP transport...");
50 49 log.info("Starting CoAP transport server");
51   - this.server = new CoapServer();
  50 + this.server = new CoapServer(NetworkConfig.createStandardWithoutFile());
52 51 createResources();
53 52 InetAddress addr = InetAddress.getByName(coapTransportContext.getHost());
54 53 InetSocketAddress sockAddr = new InetSocketAddress(addr, coapTransportContext.getPort());
55   - Builder builder = new Builder();
56   - builder.setInetSocketAddress(sockAddr);
57   - CoapEndpoint coapEndpoint = builder.build();
58   -
59   - server.addEndpoint(coapEndpoint);
  54 + server.addEndpoint(new CoapEndpoint(sockAddr));
60 55 server.start();
61 56 log.info("CoAP transport started!");
62 57 }
... ...
... ... @@ -31,7 +31,6 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter;
31 31 import org.thingsboard.server.gen.transport.TransportProtos;
32 32 import org.thingsboard.server.transport.coap.CoapTransportResource;
33 33
34   -
35 34 import java.util.Arrays;
36 35 import java.util.HashSet;
37 36 import java.util.List;
... ...
... ... @@ -28,7 +28,6 @@ import org.eclipse.californium.core.CoapClient;
28 28 import org.eclipse.californium.core.CoapHandler;
29 29 import org.eclipse.californium.core.CoapResponse;
30 30 import org.eclipse.californium.core.coap.MediaTypeRegistry;
31   -import org.eclipse.californium.elements.exception.ConnectorException;
32 31 import org.thingsboard.server.common.msg.session.FeatureType;
33 32 import org.slf4j.Logger;
34 33 import org.slf4j.LoggerFactory;
... ... @@ -62,7 +61,7 @@ public class DeviceEmulator {
62 61 this.attributesClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.ATTRIBUTES));
63 62 this.telemetryClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.TELEMETRY));
64 63 this.rpcClient = new CoapClient(getFeatureTokenUrl(host, port, token, FeatureType.RPC));
65   - this.keys = (keys != null && !keys.isEmpty()) ? keys.split(",") : null;
  64 + this.keys = keys.split(",");
66 65 }
67 66
68 67 public void start() {
... ... @@ -73,8 +72,11 @@ public class DeviceEmulator {
73 72 try {
74 73 sendObserveRequest(rpcClient);
75 74 while (!Thread.interrupted()) {
  75 +
  76 +
76 77 sendRequest(attributesClient, createAttributesRequest());
77 78 sendRequest(telemetryClient, createTelemetryRequest());
  79 +
78 80 Thread.sleep(1000);
79 81 }
80 82 } catch (Exception e) {
... ... @@ -82,8 +84,8 @@ public class DeviceEmulator {
82 84 }
83 85 }
84 86
85   - private void sendRequest(CoapClient client, JsonNode request) throws IOException, ConnectorException {
86   - CoapResponse telemetryResponse = client.setTimeout((long) 60000).post(mapper.writeValueAsString(request),
  87 + private void sendRequest(CoapClient client, JsonNode request) throws JsonProcessingException {
  88 + CoapResponse telemetryResponse = client.setTimeout(60000).post(mapper.writeValueAsString(request),
87 89 MediaTypeRegistry.APPLICATION_JSON);
88 90 log.info("Response: {}, {}", telemetryResponse.getCode(), telemetryResponse.getResponseText());
89 91 }
... ... @@ -111,7 +113,6 @@ public class DeviceEmulator {
111 113
112 114 @Override
113 115 public void onError() {
114   - log.info("Command Response Ack Error, No connect");
115 116 //Do nothing
116 117 }
117 118 }, mapper.writeValueAsString(response), MediaTypeRegistry.APPLICATION_JSON);
... ... @@ -156,15 +157,6 @@ public class DeviceEmulator {
156 157 if (args.length != 4) {
157 158 System.out.println("Usage: java -jar " + DeviceEmulator.class.getSimpleName() + ".jar host port device_token keys");
158 159 }
159   - /**
160   - * DeviceEmulator(String host, int port, String token, String keys)
161   - * args[]:
162   - * host = "localhost",
163   - * port = 0,
164   - * token = "{Tokrn device from thingboard}"), kSzbDRGwaZqZ6Y25gTLF
165   - * keys = "{Telemetry}"
166   - *
167   - */
168 160 final DeviceEmulator emulator = new DeviceEmulator(args[0], Integer.parseInt(args[1]), args[2], args[3]);
169 161 emulator.start();
170 162 Runtime.getRuntime().addShutdownHook(new Thread() {
... ... @@ -175,6 +167,7 @@ public class DeviceEmulator {
175 167 });
176 168 }
177 169
  170 +
178 171 private String getFeatureTokenUrl(String host, int port, String token, FeatureType featureType) {
179 172 return getBaseUrl(host, port) + token + "/" + featureType.name().toLowerCase();
180 173 }
... ...
... ... @@ -327,7 +327,6 @@ public class DeviceApiController {
327 327 public void onToServerRpcResponse(ToServerRpcResponseMsg msg) {
328 328 responseWriter.setResult(new ResponseEntity<>(JsonConverter.toJson(msg).toString(), HttpStatus.OK));
329 329 }
330   -
331 330 }
332 331
333 332 private void reportActivity(SessionInfoProto sessionInfo) {
... ...
1   -
2   -<!--
3   -
4   - Copyright © 2016-2020 The Thingsboard Authors
5   -
6   - Licensed under the Apache License, Version 2.0 (the "License");
7   - you may not use this file except in compliance with the License.
8   - You may obtain a copy of the License at
9   -
10   - http://www.apache.org/licenses/LICENSE-2.0
11   -
12   - Unless required by applicable law or agreed to in writing, software
13   - distributed under the License is distributed on an "AS IS" BASIS,
14   - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   - See the License for the specific language governing permissions and
16   - limitations under the License.
17   -
18   --->
19   -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20   - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21   - <modelVersion>4.0.0</modelVersion>
22   - <parent>
23   - <groupId>org.thingsboard.common</groupId>
24   - <version>3.2.0-SNAPSHOT</version>
25   - <artifactId>transport</artifactId>
26   - </parent>
27   - <groupId>org.thingsboard.common.transport</groupId>
28   - <artifactId>lwm2m</artifactId>
29   - <packaging>jar</packaging>
30   -
31   - <name>Thingsboard LwM2M Transport Common</name>
32   - <url>https://thingsboard.io</url>
33   -
34   - <properties>
35   - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
36   - <main.dir>${basedir}/../../..</main.dir>
37   - </properties>
38   -
39   - <dependencies>
40   - <dependency>
41   - <groupId>org.thingsboard.common.transport</groupId>
42   - <artifactId>transport-api</artifactId>
43   - </dependency>
44   - <dependency>
45   - <groupId>org.springframework</groupId>
46   - <artifactId>spring-context-support</artifactId>
47   - </dependency>
48   - <dependency>
49   - <groupId>org.springframework</groupId>
50   - <artifactId>spring-context</artifactId>
51   - </dependency>
52   - <dependency>
53   - <groupId>org.slf4j</groupId>
54   - <artifactId>slf4j-api</artifactId>
55   - </dependency>
56   - <dependency>
57   - <groupId>org.slf4j</groupId>
58   - <artifactId>log4j-over-slf4j</artifactId>
59   - </dependency>
60   - <dependency>
61   - <groupId>ch.qos.logback</groupId>
62   - <artifactId>logback-core</artifactId>
63   - </dependency>
64   - <dependency>
65   - <groupId>ch.qos.logback</groupId>
66   - <artifactId>logback-classic</artifactId>
67   - </dependency>
68   - <!-- lechan start -->
69   - <dependency>
70   - <groupId>org.eclipse.leshan</groupId>
71   - <artifactId>leshan-server-cf</artifactId>
72   - </dependency>
73   -<!-- <dependency>-->
74   -<!-- <groupId>org.eclipse.leshan</groupId>-->
75   -<!-- <artifactId>leshan-server-cf</artifactId>-->
76   -<!-- </dependency> -->
77   - <dependency>
78   - <groupId>org.eclipse.leshan</groupId>
79   - <artifactId>leshan-client-cf</artifactId>
80   - </dependency>
81   -
82   - <dependency>
83   - <groupId>org.eclipse.leshan</groupId>
84   - <artifactId>leshan-server-redis</artifactId>
85   - </dependency>
86   -<!-- <dependency>-->
87   -<!-- <groupId>org.eclipse.californium</groupId>-->
88   -<!-- <artifactId>californium-core</artifactId>-->
89   -<!-- </dependency>-->
90   - <!-- leshan finish -->
91   -
92   - <dependency>
93   - <groupId>org.springframework.boot</groupId>
94   - <artifactId>spring-boot-starter-test</artifactId>
95   - <scope>test</scope>
96   - </dependency>
97   - <dependency>
98   - <groupId>junit</groupId>
99   - <artifactId>junit</artifactId>
100   - <scope>test</scope>
101   - </dependency>
102   - <dependency>
103   - <groupId>org.mockito</groupId>
104   - <artifactId>mockito-all</artifactId>
105   - <scope>test</scope>
106   - </dependency>
107   - <dependency>
108   - <groupId>org.eclipse.californium</groupId>
109   - <artifactId>californium-core</artifactId>
110   - <version>${californium.version}</version>
111   - <type>test-jar</type>
112   - <scope>test</scope>
113   - </dependency>
114   - <dependency>
115   - <groupId>org.eclipse.californium</groupId>
116   - <artifactId>element-connector</artifactId>
117   - <version>${californium.version}</version>
118   - <type>test-jar</type>
119   - <scope>test</scope>
120   - </dependency>
121   - </dependencies>
122   -
123   -</project>
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
20   -import org.eclipse.leshan.core.model.StaticModel;
21   -import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
22   -import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
23   -import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder;
24   -import org.springframework.beans.factory.annotation.Autowired;
25   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
26   -import org.springframework.context.annotation.Bean;
27   -import org.springframework.context.annotation.Primary;
28   -import org.springframework.stereotype.Component;
29   -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore;
30   -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore;
31   -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MSetSecurityStoreBootstrap;
32   -import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager;
33   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
34   -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer;
35   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509;
36   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK;
37   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig;
38   -
39   -@Slf4j
40   -@Component
41   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true'&& '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')")
42   -public class LwM2MTransportBootstrapServerConfiguration {
43   -
44   - @Autowired
45   - private LwM2MTransportContextBootstrap contextBs;
46   -
47   - @Autowired
48   - private LwM2MTransportContextServer contextS;
49   -
50   - @Autowired
51   - private LwM2MBootstrapSecurityStore lwM2MBootstrapSecurityStore;
52   -
53   - @Autowired
54   - private LwM2MInMemoryBootstrapConfigStore lwM2MInMemoryBootstrapConfigStore;
55   -
56   -
57   - @Primary
58   - @Bean(name = "leshanBootstrapCert")
59   - public LeshanBootstrapServer getLeshanBootstrapServerCert() {
60   - log.info("Prepare and start BootstrapServerCert... PostConstruct");
61   - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPortCert(), this.contextBs.getCtxBootStrap().getBootstrapSecurePortCert(), X509);
62   - }
63   -
64   - @Bean(name = "leshanBootstrapRPK")
65   - public LeshanBootstrapServer getLeshanBootstrapServerRPK() {
66   - log.info("Prepare and start BootstrapServerRPK... PostConstruct");
67   - return getLeshanBootstrapServer(this.contextBs.getCtxBootStrap().getBootstrapPort(), this.contextBs.getCtxBootStrap().getBootstrapSecurePort(), RPK);
68   - }
69   -
70   - public LeshanBootstrapServer getLeshanBootstrapServer(Integer bootstrapPort, Integer bootstrapSecurePort, LwM2MSecurityMode dtlsMode) {
71   - LeshanBootstrapServerBuilder builder = new LeshanBootstrapServerBuilder();
72   - builder.setLocalAddress(this.contextBs.getCtxBootStrap().getBootstrapHost(), bootstrapPort);
73   - builder.setLocalSecureAddress(this.contextBs.getCtxBootStrap().getBootstrapSecureHost(), bootstrapSecurePort);
74   -
75   - /** Create CoAP Config */
76   - builder.setCoapConfig(getCoapConfig ());
77   -
78   - /** ConfigStore */
79   - builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore);
80   -
81   - /** SecurityStore */
82   - builder.setSecurityStore(lwM2MBootstrapSecurityStore);
83   -
84   - /** Define model provider (Create Models )*/
85   - builder.setModel(new StaticModel(contextS.getCtxServer().getModelsValue()));
86   -
87   - /** Create and Set DTLS Config */
88   - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
89   - dtlsConfig.setRecommendedCipherSuitesOnly(contextS.getCtxServer().isSupportDeprecatedCiphersEnable());
90   - builder.setDtlsConfig(dtlsConfig);
91   -
92   - /** Create credentials */
93   - new LwM2MSetSecurityStoreBootstrap(builder, contextBs, contextS, dtlsMode);
94   -
95   - BootstrapSessionManager sessionManager = new LwM2mDefaultBootstrapSessionManager(lwM2MBootstrapSecurityStore);
96   - builder.setSessionManager(sessionManager);
97   -
98   - /** Create BootstrapServer */
99   - return builder.build();
100   - }
101   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap;
17   -import lombok.extern.slf4j.Slf4j;
18   -import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
19   -import org.springframework.beans.factory.annotation.Autowired;
20   -import org.springframework.beans.factory.annotation.Qualifier;
21   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
22   -import org.springframework.stereotype.Service;
23   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
24   -
25   -import javax.annotation.PostConstruct;
26   -import javax.annotation.PreDestroy;
27   -
28   -@Slf4j
29   -@Service
30   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')")
31   -public class LwM2MTransportBootstrapServerInitializer {
32   -
33   - @Autowired
34   - @Qualifier("leshanBootstrapCert")
35   - private LeshanBootstrapServer lhBServerCert;
36   -
37   - @Autowired
38   - @Qualifier("leshanBootstrapRPK")
39   - private LeshanBootstrapServer lhBServerRPK;
40   -
41   - @Autowired
42   - private LwM2MTransportContextBootstrap contextBS;
43   -
44   - @PostConstruct
45   - public void init() {
46   - if (this.contextBS.getCtxBootStrap().isBootstrapStartAll()) {
47   - this.lhBServerCert.start();
48   - this.lhBServerRPK.start();
49   - }
50   - else {
51   - if (this.contextBS.getCtxBootStrap().getBootStrapDtlsMode() == LwM2MSecurityMode.X509.code) {
52   - this.lhBServerCert.start();
53   - }
54   - else {
55   - this.lhBServerRPK.start();
56   - }
57   - }
58   - }
59   -
60   - @PreDestroy
61   - public void shutdown() throws InterruptedException {
62   - log.info("Stopping LwM2M transport Bootstrap Server!");
63   - try {
64   - lhBServerCert.destroy();
65   - lhBServerRPK.destroy();
66   - } finally {
67   - }
68   - log.info("LwM2M transport Bootstrap Server stopped!");
69   - }
70   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap;
17   -/**
18   - * Copyright © 2016-2020 The Thingsboard Authors
19   - *
20   - * Licensed under the Apache License, Version 2.0 (the "License");
21   - * you may not use this file except in compliance with the License.
22   - * You may obtain a copy of the License at
23   - *
24   - * http://www.apache.org/licenses/LICENSE-2.0
25   - *
26   - * Unless required by applicable law or agreed to in writing, software
27   - * distributed under the License is distributed on an "AS IS" BASIS,
28   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   - * See the License for the specific language governing permissions and
30   - * limitations under the License.
31   - */
32   -
33   -import lombok.extern.slf4j.Slf4j;
34   -import org.springframework.beans.factory.annotation.Autowired;
35   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
36   -import org.springframework.stereotype.Component;
37   -import org.thingsboard.server.common.transport.TransportContext;
38   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap;
39   -
40   -import javax.annotation.PostConstruct;
41   -
42   -
43   -@Slf4j
44   -@Component
45   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith'")
46   -public class LwM2MTransportContextBootstrap extends TransportContext {
47   -
48   - private LwM2MTransportConfigBootstrap ctxBootStrap;
49   - @Autowired
50   - LwM2MTransportConfigBootstrap lwM2MTransportConfigBootstarp;
51   -
52   - @PostConstruct
53   - public void init() {
54   - this.ctxBootStrap = lwM2MTransportConfigBootstarp;
55   - }
56   -
57   - public LwM2MTransportConfigBootstrap getCtxBootStrap() {
58   - return this.ctxBootStrap;
59   - }
60   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import lombok.Builder;
19   -import lombok.Data;
20   -import org.eclipse.leshan.core.SecurityMode;
21   -import org.eclipse.leshan.core.request.BindingMode;
22   -import org.eclipse.leshan.core.util.Hex;
23   -import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
24   -
25   -import java.nio.charset.StandardCharsets;
26   -
27   -@Data
28   -public class LwM2MBootstrapConfig {
29   - /**
30   - * interface BootstrapSecurityConfig
31   - * servers: BootstrapServersSecurityConfig,
32   - * bootstrapServer: ServerSecurityConfig,
33   - * lwm2mServer: ServerSecurityConfig
34   - * }
35   - */
36   - /** -servers
37   - * shortId: number,
38   - * lifetime: number,
39   - * defaultMinPeriod: number,
40   - * notifIfDisabled: boolean,
41   - * binding: string
42   - * */
43   - @Builder.Default
44   - LwM2MBootstrapServers servers;
45   -
46   - /** -bootstrapServer, lwm2mServer
47   - * interface ServerSecurityConfig
48   - * host?: string,
49   - * port?: number,
50   - * isBootstrapServer?: boolean,
51   - * securityMode: string,
52   - * clientPublicKeyOrId?: string,
53   - * clientSecretKey?: string,
54   - * serverPublicKey?: string;
55   - * clientHoldOffTime?: number,
56   - * serverId?: number,
57   - * bootstrapServerAccountTimeout: number
58   - * */
59   - LwM2MServerBootstrap bootstrapServer;
60   -
61   - LwM2MServerBootstrap lwm2mServer;
62   -
63   - public BootstrapConfig getLwM2MBootstrapConfig() {
64   - BootstrapConfig configBs = new BootstrapConfig();
65   - /** Delete old security objects */
66   - configBs.toDelete.add("/0");
67   - configBs.toDelete.add("/1");
68   - /** Server Configuration (object 1) as defined in LWM2M 1.0.x TS. */
69   - BootstrapConfig.ServerConfig server0 = new BootstrapConfig.ServerConfig();
70   - server0.shortId = servers.getShortId();
71   - server0.lifetime = servers.getLifetime();
72   - server0.defaultMinPeriod = servers.getDefaultMinPeriod();
73   - server0.notifIfDisabled = servers.isNotifIfDisabled();
74   - server0.binding = BindingMode.valueOf(servers.getBinding());
75   - configBs.servers.put(0, server0);
76   - /** Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */
77   - this.bootstrapServer.setBootstrapServerIs(true);
78   - configBs.security.put(0, setServerSecuruty(this.bootstrapServer.getHost(), this.bootstrapServer.getPort(), this.bootstrapServer.isBootstrapServerIs(), this.bootstrapServer.getSecurityMode(), this.bootstrapServer.getClientPublicKeyOrId(), this.bootstrapServer.getServerPublicKey(), this.bootstrapServer.getClientSecretKey(), this.bootstrapServer.getServerId()));
79   - /** Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Server instance = 1 */
80   - configBs.security.put(1, setServerSecuruty(this.lwm2mServer.getHost(), this.lwm2mServer.getPort(), this.lwm2mServer.isBootstrapServerIs(), this.lwm2mServer.getSecurityMode(), this.lwm2mServer.getClientPublicKeyOrId(), this.lwm2mServer.getServerPublicKey(), this.lwm2mServer.getClientSecretKey(), this.lwm2mServer.getServerId()));
81   - return configBs;
82   - }
83   -
84   - private BootstrapConfig.ServerSecurity setServerSecuruty(String host, Integer port, boolean bootstrapServer, String securityMode, String clientPublicKey, String serverPublicKey, String secretKey, int serverId) {
85   - BootstrapConfig.ServerSecurity serverSecurity = new BootstrapConfig.ServerSecurity();
86   - serverSecurity.uri = "coaps://" + host + ":" + Integer.toString(port);
87   - serverSecurity.bootstrapServer = bootstrapServer;
88   - serverSecurity.securityMode = SecurityMode.valueOf(securityMode);
89   - serverSecurity.publicKeyOrId = setPublicKeyOrId(clientPublicKey, securityMode);
90   - serverSecurity.serverPublicKey = (serverPublicKey != null && !serverPublicKey.isEmpty()) ? Hex.decodeHex(serverPublicKey.toCharArray()) : new byte[]{};
91   - serverSecurity.secretKey = (secretKey != null && !secretKey.isEmpty()) ? Hex.decodeHex(secretKey.toCharArray()) : new byte[]{};
92   - serverSecurity.serverId = serverId;
93   - return serverSecurity;
94   - }
95   -
96   - private byte[] setPublicKeyOrId(String publicKeyOrIdStr, String securityMode) {
97   - byte[] publicKey = (publicKeyOrIdStr == null || publicKeyOrIdStr.isEmpty()) ? new byte[]{} :
98   - SecurityMode.valueOf(securityMode).equals(SecurityMode.PSK) ? publicKeyOrIdStr.getBytes(StandardCharsets.UTF_8) :
99   - Hex.decodeHex(publicKeyOrIdStr.toCharArray());
100   - return publicKey;
101   - }
102   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import com.fasterxml.jackson.core.JsonProcessingException;
19   -import com.fasterxml.jackson.databind.ObjectMapper;
20   -import com.google.gson.JsonObject;
21   -import lombok.extern.slf4j.Slf4j;
22   -import org.eclipse.leshan.core.SecurityMode;
23   -import org.eclipse.leshan.core.util.Hex;
24   -import org.eclipse.leshan.core.util.SecurityUtil;
25   -import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
26   -import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore;
27   -import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException;
28   -import org.eclipse.leshan.server.security.BootstrapSecurityStore;
29   -import org.eclipse.leshan.server.security.SecurityInfo;
30   -import org.springframework.beans.factory.annotation.Autowired;
31   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
32   -import org.springframework.stereotype.Component;
33   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MGetSecurityInfo;
34   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
35   -import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore;
36   -import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
37   -
38   -import java.io.IOException;
39   -import java.security.GeneralSecurityException;
40   -import java.util.Arrays;
41   -import java.util.List;
42   -
43   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*;
44   -
45   -@Slf4j
46   -@Component("LwM2MBootstrapSecurityStore")
47   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true' && '${transport.lwm2m.bootstrap.enable}'=='true')")
48   -public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
49   -
50   - private final EditableBootstrapConfigStore bootstrapConfigStore;
51   -
52   - @Autowired
53   - LwM2MGetSecurityInfo lwM2MGetSecurityInfo;
54   -
55   - public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore) {
56   - this.bootstrapConfigStore = bootstrapConfigStore;
57   - }
58   -
59   - @Override
60   - public List<SecurityInfo> getAllByEndpoint(String endPoint) {
61   - String endPointKey = endPoint;
62   - ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(endPointKey, TypeServer.BOOTSTRAP);
63   - if (store.getBootstrapJsonCredential() != null) {
64   - /** add value to store from BootstrapJson */
65   - this.setBootstrapConfigScurityInfo(store);
66   - BootstrapConfig bsConfigNew = store.getBootstrapConfig();
67   - if (bsConfigNew != null) {
68   - try {
69   - for (String config : bootstrapConfigStore.getAll().keySet()) {
70   - if (config.equals(endPoint)) {
71   - bootstrapConfigStore.remove(config);
72   - }
73   - }
74   - bootstrapConfigStore.add(endPoint, bsConfigNew);
75   - } catch (InvalidConfigurationException e) {
76   - e.printStackTrace();
77   - }
78   - return store.getSecurityInfo() == null ? null : Arrays.asList(store.getSecurityInfo());
79   - }
80   - }
81   - return null;
82   - }
83   -
84   - @Override
85   - public SecurityInfo getByIdentity(String identity) {
86   - ReadResultSecurityStore store = lwM2MGetSecurityInfo.getSecurityInfo(identity, TypeServer.BOOTSTRAP);
87   - /** add value to store from BootstrapJson */
88   - this.setBootstrapConfigScurityInfo(store);
89   -
90   - if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) {
91   - BootstrapConfig bsConfig = store.getBootstrapConfig();
92   - if (bsConfig.security != null) {
93   - try {
94   - bootstrapConfigStore.add(store.getEndPoint(), bsConfig);
95   - } catch (InvalidConfigurationException e) {
96   - e.printStackTrace();
97   - }
98   - return store.getSecurityInfo();
99   - }
100   - }
101   - return null;
102   - }
103   -
104   - private void setBootstrapConfigScurityInfo(ReadResultSecurityStore store) {
105   - /** BootstrapConfig */
106   - LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store);
107   - if (lwM2MBootstrapConfig != null) {
108   - /** Security info */
109   - switch (SecurityMode.valueOf(lwM2MBootstrapConfig.getBootstrapServer().getSecurityMode())) {
110   - /** Use RPK only */
111   - case PSK:
112   - store.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(store.getEndPoint(),
113   - lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId(),
114   - Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientSecretKey().toCharArray())));
115   - store.setSecurityMode(SecurityMode.PSK.code);
116   - break;
117   - case RPK:
118   - try {
119   - store.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(store.getEndPoint(),
120   - SecurityUtil.publicKey.decode(Hex.decodeHex(lwM2MBootstrapConfig.getBootstrapServer().getClientPublicKeyOrId().toCharArray()))));
121   - store.setSecurityMode(SecurityMode.RPK.code);
122   - break;
123   - } catch (IOException | GeneralSecurityException e) {
124   - log.error("Unable to decode Client public key for [{}] [{}]", store.getEndPoint(), e.getMessage());
125   - }
126   - case X509:
127   - store.setSecurityInfo(SecurityInfo.newX509CertInfo(store.getEndPoint()));
128   - store.setSecurityMode(SecurityMode.X509.code);
129   - break;
130   - case NO_SEC:
131   - store.setSecurityMode(SecurityMode.NO_SEC.code);
132   - store.setSecurityInfo(null);
133   - break;
134   - default:
135   - }
136   - BootstrapConfig bootstrapConfig = lwM2MBootstrapConfig.getLwM2MBootstrapConfig();
137   - store.setBootstrapConfig(bootstrapConfig);
138   - }
139   - }
140   -
141   - private LwM2MBootstrapConfig getParametersBootstrap(ReadResultSecurityStore store) {
142   - try {
143   - JsonObject bootstrapJsonCredential = store.getBootstrapJsonCredential();
144   - ObjectMapper mapper = new ObjectMapper();
145   - LwM2MBootstrapConfig lwM2MBootstrapConfig = mapper.readValue(bootstrapJsonCredential.toString(), LwM2MBootstrapConfig.class);
146   - JsonObject bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile());
147   - lwM2MBootstrapConfig.servers = mapper.readValue(bootstrapObject.get(SERVERS).toString(), LwM2MBootstrapServers.class);
148   - LwM2MServerBootstrap profileServerBootstrap = mapper.readValue(bootstrapObject.get(BOOTSTRAP_SERVER).toString(), LwM2MServerBootstrap.class);
149   - LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class);
150   - if (getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {
151   - lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
152   - lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
153   - return lwM2MBootstrapConfig;
154   - }
155   - else {
156   - log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
157   - log.error(LOG_LW2M_ERROR + " getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", store.getEndPoint());
158   - String logMsg = String.format(LOG_LW2M_ERROR + " getParametersBootstrap: %s Different values SecurityMode between of client and profile.", store.getEndPoint());
159   -// sentLogsToThingsboard(logMsg, store.getEndPoint());
160   - return null;
161   - }
162   - } catch (JsonProcessingException e) {
163   - log.error("Unable to decode Json or Certificate for [{}] [{}]", store.getEndPoint(), e.getMessage());
164   - return null;
165   - }
166   - }
167   -
168   - /**
169   - * Bootstrap security have to sync between (bootstrapServer in credential and bootstrapServer in profile)
170   - * and (lwm2mServer in credential and lwm2mServer in profile
171   - * @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential
172   - * @param profileServerBootstrap - Bootstrap -> Security of bootstrapServer in profile
173   - * @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential
174   - * @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile
175   - * @return false if not sync between SecurityMode of Bootstrap credential and profile
176   - */
177   - private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) {
178   - return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) &&
179   - lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode()));
180   - }
181   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import lombok.Builder;
19   -import lombok.Data;
20   -
21   -@Data
22   -public class LwM2MBootstrapServers {
23   - @Builder.Default
24   - private Integer shortId = 123;
25   - @Builder.Default
26   - private Integer lifetime = 300;
27   - @Builder.Default
28   - private Integer defaultMinPeriod = 1;
29   - @Builder.Default
30   - private boolean notifIfDisabled = true;
31   - @Builder.Default
32   - private String binding = "U";
33   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
20   -import org.eclipse.leshan.server.bootstrap.InMemoryBootstrapConfigStore;
21   -import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException;
22   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23   -import org.springframework.stereotype.Component;
24   -import java.util.Map;
25   -import java.util.concurrent.locks.Lock;
26   -import java.util.concurrent.locks.ReadWriteLock;
27   -import java.util.concurrent.locks.ReentrantReadWriteLock;
28   -
29   -@Slf4j
30   -@Component("LwM2MInMemoryBootstrapConfigStore")
31   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' && '${transport.lwm2m.bootstrap.enable:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true'&& '${transport.lwm2m.bootstrap.enable}'=='true')")
32   -public class LwM2MInMemoryBootstrapConfigStore extends InMemoryBootstrapConfigStore {
33   - private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
34   - private final Lock readLock = readWriteLock.readLock();
35   - private final Lock writeLock = readWriteLock.writeLock();
36   -
37   - @Override
38   - public Map<String, BootstrapConfig> getAll() {
39   - readLock.lock();
40   - try {
41   - return super.getAll();
42   - } finally {
43   - readLock.unlock();
44   - }
45   - }
46   -
47   - @Override
48   - public void add(String endpoint, BootstrapConfig config) throws InvalidConfigurationException {
49   - writeLock.lock();
50   - try {
51   - addToStore(endpoint, config);
52   - } finally {
53   - writeLock.unlock();
54   - }
55   - }
56   -
57   - @Override
58   - public BootstrapConfig remove(String enpoint) {
59   - writeLock.lock();
60   - try {
61   - BootstrapConfig res = super.remove(enpoint);
62   - return res;
63   - } finally {
64   - writeLock.unlock();
65   - }
66   - }
67   -
68   - public void addToStore(String endpoint, BootstrapConfig config) throws InvalidConfigurationException {
69   - super.add(endpoint, config);
70   - }
71   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import lombok.Builder;
19   -import lombok.Data;
20   -import lombok.extern.slf4j.Slf4j;
21   -import org.eclipse.leshan.core.SecurityMode;
22   -
23   -@Slf4j
24   -@Data
25   -public class LwM2MServerBootstrap {
26   -
27   - @Builder.Default
28   - String clientPublicKeyOrId = "";
29   - @Builder.Default
30   - String clientSecretKey = "";
31   - @Builder.Default
32   - String serverPublicKey = "";
33   - @Builder.Default
34   - Integer clientHoldOffTime = 1;
35   - @Builder.Default
36   - Integer bootstrapServerAccountTimeout = 0;
37   -
38   - @Builder.Default
39   - String host = "0.0.0.0";
40   - @Builder.Default
41   - Integer port = 0;
42   -
43   - @Builder.Default
44   - String securityMode = SecurityMode.NO_SEC.name();
45   -
46   - @Builder.Default
47   - Integer serverId = 123;
48   - @Builder.Default
49   - boolean bootstrapServerIs = false;
50   -
51   - public LwM2MServerBootstrap(){};
52   -
53   - public LwM2MServerBootstrap(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap) {
54   - this.clientPublicKeyOrId = bootstrapFromCredential.getClientPublicKeyOrId();
55   - this.clientSecretKey = bootstrapFromCredential.getClientSecretKey();
56   - this.serverPublicKey = profileServerBootstrap.getServerPublicKey();
57   - this.clientHoldOffTime = profileServerBootstrap.getClientHoldOffTime();
58   - this.bootstrapServerAccountTimeout = profileServerBootstrap.getBootstrapServerAccountTimeout();
59   - this.host = (profileServerBootstrap.getHost().equals("0.0.0.0")) ? "localhost" : profileServerBootstrap.getHost();
60   - this.port = profileServerBootstrap.getPort();
61   - this.securityMode = profileServerBootstrap.getSecurityMode();
62   - this.serverId = profileServerBootstrap.getServerId();
63   - this.bootstrapServerIs = profileServerBootstrap.bootstrapServerIs;
64   - }
65   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import lombok.Data;
19   -import lombok.extern.slf4j.Slf4j;
20   -import org.eclipse.leshan.core.util.Hex;
21   -import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServerBuilder;
22   -import org.eclipse.leshan.server.security.EditableSecurityStore;
23   -import org.thingsboard.server.transport.lwm2m.bootstrap.LwM2MTransportContextBootstrap;
24   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
25   -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer;
26   -
27   -import java.math.BigInteger;
28   -import java.security.AlgorithmParameters;
29   -import java.security.KeyStore;
30   -import java.security.PublicKey;
31   -import java.security.PrivateKey;
32   -import java.security.KeyFactory;
33   -import java.security.GeneralSecurityException;
34   -import java.security.KeyStoreException;
35   -import java.security.cert.X509Certificate;
36   -import java.security.interfaces.ECPublicKey;
37   -import java.security.spec.ECGenParameterSpec;
38   -import java.security.spec.ECParameterSpec;
39   -import java.security.spec.ECPublicKeySpec;
40   -import java.security.spec.ECPoint;
41   -import java.security.spec.KeySpec;
42   -import java.security.spec.ECPrivateKeySpec;
43   -import java.util.Arrays;
44   -
45   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC;
46   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509;
47   -
48   -@Slf4j
49   -@Data
50   -public class LwM2MSetSecurityStoreBootstrap {
51   -
52   - private KeyStore keyStore;
53   - private PublicKey publicKey;
54   - private PrivateKey privateKey;
55   - private LwM2MTransportContextBootstrap contextBs;
56   - private LwM2MTransportContextServer contextS;
57   - private LeshanBootstrapServerBuilder builder;
58   - EditableSecurityStore securityStore;
59   -
60   - public LwM2MSetSecurityStoreBootstrap(LeshanBootstrapServerBuilder builder, LwM2MTransportContextBootstrap contextBs, LwM2MTransportContextServer contextS, LwM2MSecurityMode dtlsMode) {
61   - this.builder = builder;
62   - this.contextBs = contextBs;
63   - this.contextS = contextS;
64   - /** Set securityStore with new registrationStore */
65   -
66   - switch (dtlsMode) {
67   - /** Use No_Sec only */
68   - case NO_SEC:
69   - setServerWithX509Cert(NO_SEC.code);
70   - break;
71   - /** Use PSK/RPK */
72   - case PSK:
73   - case RPK:
74   - setRPK();
75   - break;
76   - case X509:
77   - setServerWithX509Cert(X509.code);
78   - break;
79   - /** Use X509_EST only */
80   - case X509_EST:
81   - // TODO support sentinel pool and make pool configurable
82   - break;
83   - /** Use ather X509, PSK, No_Sec ?? */
84   - default:
85   - break;
86   - }
87   - }
88   -
89   - private void setRPK() {
90   - try {
91   - /** Get Elliptic Curve Parameter spec for secp256r1 */
92   - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
93   - algoParameters.init(new ECGenParameterSpec("secp256r1"));
94   - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
95   - if (this.contextBs.getCtxBootStrap().getBootstrapPublicX() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicX().isEmpty() && this.contextBs.getCtxBootStrap().getBootstrapPublicY() != null && !this.contextBs.getCtxBootStrap().getBootstrapPublicY().isEmpty()) {
96   - /** Get point values */
97   - byte[] publicX = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicX().toCharArray());
98   - byte[] publicY = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPublicY().toCharArray());
99   - /** Create key specs */
100   - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
101   - parameterSpec);
102   - /** Get keys */
103   - this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
104   - }
105   - if (this.contextBs.getCtxBootStrap().getBootstrapPrivateS() != null && !this.contextBs.getCtxBootStrap().getBootstrapPrivateS().isEmpty()) {
106   - /** Get point values */
107   - byte[] privateS = Hex.decodeHex(this.contextBs.getCtxBootStrap().getBootstrapPrivateS().toCharArray());
108   - /** Create key specs */
109   - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec);
110   - /** Get keys */
111   - this.privateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);
112   - }
113   - if (this.publicKey != null && this.publicKey.getEncoded().length > 0 &&
114   - this.privateKey != null && this.privateKey.getEncoded().length > 0) {
115   - this.builder.setPublicKey(this.publicKey);
116   - this.builder.setPrivateKey(this.privateKey);
117   - this.contextBs.getCtxBootStrap().setBootstrapPublicKey(this.publicKey);
118   - getParamsRPK();
119   - }
120   - } catch (GeneralSecurityException | IllegalArgumentException e) {
121   - log.error("[{}] Failed generate Server PSK/RPK", e.getMessage());
122   - throw new RuntimeException(e);
123   - }
124   - }
125   -
126   - private void setServerWithX509Cert(int securityModeCode) {
127   - try {
128   - if (this.contextS.getCtxServer().getKeyStoreValue() != null) {
129   - KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue();
130   - setBuilderX509();
131   - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias());
132   - if (rootCAX509Cert != null && securityModeCode == X509.code) {
133   - X509Certificate[] trustedCertificates = new X509Certificate[1];
134   - trustedCertificates[0] = rootCAX509Cert;
135   - this.builder.setTrustedCertificates(trustedCertificates);
136   - } else {
137   - /** by default trust all */
138   - this.builder.setTrustedCertificates(new X509Certificate[0]);
139   - }
140   - }
141   - else {
142   - /** by default trust all */
143   - this.builder.setTrustedCertificates(new X509Certificate[0]);
144   - log.error("Unable to load X509 files for BootStrapServer");
145   - }
146   - } catch (KeyStoreException ex) {
147   - log.error("[{}] Unable to load X509 files server", ex.getMessage());
148   - }
149   -
150   - }
151   -
152   - private void setBuilderX509() {
153   - /**
154   - * For deb => KeyStorePathFile == yml or commandline: KEY_STORE_PATH_FILE
155   - * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks
156   - */
157   - try {
158   - X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias());
159   - this.privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray());
160   - if (this.privateKey != null && this.privateKey.getEncoded().length > 0) {
161   - this.builder.setPrivateKey(this.privateKey);
162   - }
163   - if (serverCertificate != null) {
164   - this.builder.setCertificateChain(new X509Certificate[]{serverCertificate});
165   - this.contextBs.getCtxBootStrap().setBootstrapCertificate(serverCertificate);
166   - }
167   - } catch (Exception ex) {
168   - log.error("[{}] Unable to load KeyStore files server", ex.getMessage());
169   - }
170   - }
171   -
172   - private void getParamsRPK() {
173   - if (this.publicKey instanceof ECPublicKey) {
174   - /** Get x coordinate */
175   - byte[] x = ((ECPublicKey) this.publicKey).getW().getAffineX().toByteArray();
176   - if (x[0] == 0)
177   - x = Arrays.copyOfRange(x, 1, x.length);
178   -
179   - /** Get Y coordinate */
180   - byte[] y = ((ECPublicKey) this.publicKey).getW().getAffineY().toByteArray();
181   - if (y[0] == 0)
182   - y = Arrays.copyOfRange(y, 1, y.length);
183   -
184   - /** Get Curves params */
185   - String params = ((ECPublicKey) this.publicKey).getParams().toString();
186   - log.info(
187   - " \nBootstrap uses RPK : \n Elliptic Curve parameters : [{}] \n Public x coord : [{}] \n Public y coord : [{}] \n Public Key (Hex): [{}] \n Private Key (Hex): [{}]",
188   - params, Hex.encodeHexString(x), Hex.encodeHexString(y),
189   - Hex.encodeHexString(this.publicKey.getEncoded()),
190   - Hex.encodeHexString(this.privateKey.getEncoded()));
191   - } else {
192   - throw new IllegalStateException("Unsupported Public Key Format (only ECPublicKey supported).");
193   - }
194   - }
195   -
196   -// private void getParamsX509() {
197   -// try {
198   -// log.info("BootStrap uses X509 : \n X509 Certificate (Hex): [{}] \n Private Key (Hex): [{}]",
199   -// Hex.encodeHexString(this.certificate.getEncoded()),
200   -// Hex.encodeHexString(this.privateKey.getEncoded()));
201   -// } catch (CertificateEncodingException e) {
202   -// e.printStackTrace();
203   -// }
204   -// }
205   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.leshan.core.request.Identity;
20   -import org.eclipse.leshan.server.bootstrap.BootstrapSession;
21   -import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSession;
22   -import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSessionManager;
23   -import org.eclipse.leshan.server.security.BootstrapSecurityStore;
24   -import org.eclipse.leshan.server.security.SecurityChecker;
25   -import org.eclipse.leshan.server.security.SecurityInfo;
26   -
27   -import java.util.Arrays;
28   -import java.util.List;
29   -
30   -@Slf4j
31   -public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager {
32   -
33   - private BootstrapSecurityStore bsSecurityStore;
34   - private SecurityChecker securityChecker;
35   -
36   - /**
37   - * Create a {@link DefaultBootstrapSessionManager} using a default {@link SecurityChecker} to accept or refuse new
38   - * {@link BootstrapSession}.
39   - *
40   - * @param bsSecurityStore the {@link BootstrapSecurityStore} used by default {@link SecurityChecker}.
41   - */
42   - public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore) {
43   - this(bsSecurityStore, new SecurityChecker());
44   - }
45   -
46   - public LwM2mDefaultBootstrapSessionManager(BootstrapSecurityStore bsSecurityStore, SecurityChecker securityChecker) {
47   - super(bsSecurityStore);
48   - this.bsSecurityStore = bsSecurityStore;
49   - this.securityChecker = securityChecker;
50   - }
51   -
52   - @Override
53   - public BootstrapSession begin(String endpoint, Identity clientIdentity) {
54   - boolean authorized;
55   - if (bsSecurityStore != null) {
56   - List<SecurityInfo> securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ? Arrays.asList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())) : bsSecurityStore.getAllByEndpoint(endpoint);
57   - log.info("Bootstrap session started securityInfos: [{}]", securityInfos);
58   - authorized = securityChecker.checkSecurityInfos(endpoint, clientIdentity, securityInfos);
59   - } else {
60   - authorized = true;
61   - }
62   - DefaultBootstrapSession session = new DefaultBootstrapSession(endpoint, clientIdentity, authorized);
63   - log.info("Bootstrap session started : {}", session);
64   - return session;
65   - }
66   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.secure;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.leshan.core.util.Hex;
20   -import java.security.SecureRandom;
21   -import java.security.KeyPairGenerator;
22   -import java.security.KeyPair;
23   -import java.security.PrivateKey;
24   -import java.security.PublicKey;
25   -import java.security.NoSuchAlgorithmException;
26   -import java.security.NoSuchProviderException;
27   -import java.security.InvalidAlgorithmParameterException;
28   -import java.security.interfaces.ECPublicKey;
29   -import java.security.spec.ECGenParameterSpec;
30   -import java.util.Arrays;
31   -
32   -@Slf4j
33   -public class LWM2MGenerationPSkRPkECC {
34   -
35   - public LWM2MGenerationPSkRPkECC(Integer dtlsMode) {
36   - switch (LwM2MSecurityMode.fromSecurityMode(dtlsMode)) {
37   - case PSK:
38   - generationPSkKey();
39   - break;
40   - case RPK:
41   - generationRPKECCKey();
42   - }
43   - }
44   -
45   - public LWM2MGenerationPSkRPkECC() {
46   - generationPSkKey();
47   - generationRPKECCKey();
48   - }
49   -
50   - private void generationPSkKey() {
51   - /** PSK */
52   - int lenPSkKey = 32;
53   - /** Start PSK
54   - * Clients and Servers MUST support PSK keys of up to 64 bytes in length, as required by [RFC7925]
55   - * SecureRandom object must be unpredictable, and all SecureRandom output sequences must be cryptographically strong, as described in [RFC4086]
56   - * */
57   - SecureRandom randomPSK = new SecureRandom();
58   - byte bytesPSK[] = new byte[lenPSkKey];
59   - randomPSK.nextBytes(bytesPSK);
60   - log.info("\nCreating new PSK: \n for the next start PSK -> security key: [{}]", Hex.encodeHexString(bytesPSK));
61   - }
62   -
63   - private void generationRPKECCKey() {
64   - /** RPK */
65   - String algorithm = "EC";
66   - String provider = "SunEC";
67   - String nameParameterSpec = "secp256r1";
68   -
69   - /** Start RPK
70   - * Elliptic Curve parameters : [secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)]
71   - * */
72   - KeyPairGenerator kpg = null;
73   - try {
74   - kpg = KeyPairGenerator.getInstance(algorithm, provider);
75   - } catch (NoSuchAlgorithmException e) {
76   - e.printStackTrace();
77   - } catch (NoSuchProviderException e) {
78   - e.printStackTrace();
79   - }
80   - ECGenParameterSpec ecsp = new ECGenParameterSpec(nameParameterSpec);
81   - try {
82   - kpg.initialize(ecsp);
83   - } catch (InvalidAlgorithmParameterException e) {
84   - e.printStackTrace();
85   - }
86   -
87   - KeyPair kp = kpg.genKeyPair();
88   - PrivateKey privKey = kp.getPrivate();
89   - PublicKey pubKey = kp.getPublic();
90   -
91   - if (pubKey instanceof ECPublicKey) {
92   - ECPublicKey ecPublicKey = (ECPublicKey) pubKey;
93   - /** Get x coordinate */
94   - byte[] x = ecPublicKey.getW().getAffineX().toByteArray();
95   - if (x[0] == 0)
96   - x = Arrays.copyOfRange(x, 1, x.length);
97   -
98   - /** Get Y coordinate */
99   - byte[] y = ecPublicKey.getW().getAffineY().toByteArray();
100   - if (y[0] == 0)
101   - y = Arrays.copyOfRange(y, 1, y.length);
102   -
103   - /** Get Curves params */
104   - String privHex = Hex.encodeHexString(privKey.getEncoded());
105   - log.info("\nCreating new RPK for the next start... \n" +
106   - " Elliptic Curve parameters : [{}] \n" +
107   - " public_x : [{}] \n" +
108   - " public_y : [{}] \n" +
109   - " private_s : [{}] \n" +
110   - " Public Key (Hex): [{}]\n" +
111   - " Private Key (Hex): [{}]",
112   - ecPublicKey.getParams().toString(),
113   - Hex.encodeHexString(x),
114   - Hex.encodeHexString(y),
115   - privHex.substring(privHex.length() - 64),
116   - Hex.encodeHexString(pubKey.getEncoded()),
117   - Hex.encodeHexString(privKey.getEncoded()));
118   - }
119   - }
120   -}
121   -
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.secure;
17   -
18   -import com.google.gson.JsonObject;
19   -import lombok.extern.slf4j.Slf4j;
20   -import org.eclipse.leshan.core.util.Hex;
21   -import org.eclipse.leshan.core.util.SecurityUtil;
22   -import org.eclipse.leshan.server.security.SecurityInfo;
23   -import org.springframework.beans.factory.annotation.Autowired;
24   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
25   -import org.springframework.stereotype.Component;
26   -import org.thingsboard.server.common.data.DeviceProfile;
27   -import org.thingsboard.server.common.transport.TransportServiceCallback;
28   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
29   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
30   -import org.thingsboard.server.transport.lwm2m.bootstrap.LwM2MTransportContextBootstrap;
31   -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer;
32   -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler;
33   -import org.thingsboard.server.transport.lwm2m.utils.TypeServer;
34   -
35   -import java.io.IOException;
36   -import java.security.GeneralSecurityException;
37   -import java.security.PublicKey;
38   -import java.util.Optional;
39   -import java.util.concurrent.CountDownLatch;
40   -import java.util.concurrent.TimeUnit;
41   -
42   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.*;
43   -
44   -@Slf4j
45   -@Component("LwM2MGetSecurityInfo")
46   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
47   -public class LwM2MGetSecurityInfo {
48   -
49   - @Autowired
50   - public LwM2MTransportContextServer contextS;
51   -
52   - @Autowired
53   - public LwM2MTransportContextBootstrap contextBS;
54   -
55   -
56   - public ReadResultSecurityStore getSecurityInfo(String endPoint, TypeServer keyValue) {
57   - CountDownLatch latch = new CountDownLatch(1);
58   - final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1];
59   - contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endPoint).build(),
60   - new TransportServiceCallback<ValidateDeviceCredentialsResponseMsg>() {
61   - @Override
62   - public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) {
63   - String credentialsBody = msg.getCredentialsBody();
64   - resultSecurityStore[0] = putSecurityInfo(endPoint, msg.getDeviceInfo().getDeviceName(), credentialsBody, keyValue);
65   - resultSecurityStore[0].setMsg(msg);
66   - Optional<DeviceProfile> deviceProfileOpt = LwM2MTransportHandler.decode(msg.getProfileBody().toByteArray());
67   - deviceProfileOpt.ifPresent(profile -> resultSecurityStore[0].setDeviceProfile(profile));
68   - latch.countDown();
69   - }
70   -
71   - @Override
72   - public void onError(Throwable e) {
73   - log.trace("[{}] Failed to process credentials PSK: {}", endPoint, e);
74   - resultSecurityStore[0] = putSecurityInfo(endPoint, null, null, null);
75   - latch.countDown();
76   - }
77   - });
78   - try {
79   - latch.await(contextS.getCtxServer().getTimeout(), TimeUnit.MILLISECONDS);
80   - } catch (InterruptedException e) {
81   - e.printStackTrace();
82   - }
83   - return resultSecurityStore[0];
84   - }
85   -
86   - private ReadResultSecurityStore putSecurityInfo(String endPoint, String deviceName, String jsonStr, TypeServer keyValue) {
87   - ReadResultSecurityStore result = new ReadResultSecurityStore();
88   - JsonObject objectMsg = LwM2MTransportHandler.validateJson(jsonStr);
89   - if (objectMsg != null && !objectMsg.isJsonNull()) {
90   - JsonObject object = (objectMsg.has(keyValue.type) && !objectMsg.get(keyValue.type).isJsonNull()) ? objectMsg.get(keyValue.type).getAsJsonObject() : null;
91   - /**
92   - * Only PSK
93   - */
94   - String endPointPsk = (objectMsg.has("client")
95   - && objectMsg.get("client").getAsJsonObject().has("endpoint")
96   - && objectMsg.get("client").getAsJsonObject().get("endpoint").isJsonPrimitive()) ? objectMsg.get("client").getAsJsonObject().get("endpoint").getAsString() : null;
97   - endPoint = (endPointPsk == null || endPointPsk.isEmpty()) ? endPoint : endPointPsk;
98   - if (object != null && !object.isJsonNull()) {
99   - if (keyValue.equals(TypeServer.BOOTSTRAP)) {
100   - result.setBootstrapJsonCredential(object);
101   - result.setEndPoint(endPoint);
102   - } else {
103   - LwM2MSecurityMode lwM2MSecurityMode = LwM2MSecurityMode.fromSecurityMode(object.get("securityConfigClientMode").getAsString().toLowerCase());
104   - switch (lwM2MSecurityMode) {
105   - case NO_SEC:
106   - getClientSecurityInfoNoSec(result);
107   - break;
108   - case PSK:
109   - getClientSecurityInfoPSK(result, endPoint, object);
110   - break;
111   - case RPK:
112   - getClientSecurityInfoRPK(result, endPoint, object);
113   - break;
114   - case X509:
115   - getClientSecurityInfoX509(result, endPoint);
116   - break;
117   - default:
118   - break;
119   - }
120   - }
121   - }
122   - }
123   - return result;
124   - }
125   -
126   - private void getClientSecurityInfoNoSec(ReadResultSecurityStore result) {
127   - result.setSecurityInfo(null);
128   - result.setSecurityMode(NO_SEC.code);
129   - }
130   -
131   - private void getClientSecurityInfoPSK(ReadResultSecurityStore result, String endPoint, JsonObject object) {
132   - /** PSK Deserialization */
133   - String identity = (object.has("identity") && object.get("identity").isJsonPrimitive()) ? object.get("identity").getAsString() : null;
134   - if (identity != null && !identity.isEmpty()) {
135   - try {
136   - byte[] key = (object.has("key") && object.get("key").isJsonPrimitive()) ? Hex.decodeHex(object.get("key").getAsString().toCharArray()) : null;
137   - if (key != null && key.length > 0) {
138   - if (endPoint != null && !endPoint.isEmpty()) {
139   - result.setSecurityInfo(SecurityInfo.newPreSharedKeyInfo(endPoint, identity, key));
140   - result.setSecurityMode(PSK.code);
141   - }
142   - }
143   - } catch (IllegalArgumentException e) {
144   - log.error("Missing PSK key: " + e.getMessage());
145   - }
146   - } else {
147   - log.error("Missing PSK identity");
148   - }
149   - }
150   -
151   - private void getClientSecurityInfoRPK(ReadResultSecurityStore result, String endpoint, JsonObject object) {
152   - try {
153   - if (object.has("key") && object.get("key").isJsonPrimitive()) {
154   - byte[] rpkkey = Hex.decodeHex(object.get("key").getAsString().toLowerCase().toCharArray());
155   - PublicKey key = SecurityUtil.publicKey.decode(rpkkey);
156   - result.setSecurityInfo(SecurityInfo.newRawPublicKeyInfo(endpoint, key));
157   - result.setSecurityMode(RPK.code);
158   - } else {
159   - log.error("Missing RPK key");
160   - }
161   - } catch (IllegalArgumentException | IOException | GeneralSecurityException e) {
162   - log.error("RPK: Invalid security info content: " + e.getMessage());
163   - }
164   - }
165   -
166   - private void getClientSecurityInfoX509(ReadResultSecurityStore result, String endpoint) {
167   - result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint));
168   - result.setSecurityMode(X509.code);
169   - }
170   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.secure;
17   -
18   -public enum LwM2MSecurityMode {
19   -
20   - PSK(0, "psk"),
21   - RPK(1, "rpk"),
22   - X509(2, "x509"),
23   - NO_SEC(3, "no_sec"),
24   - X509_EST(4, "x509_est"),
25   - REDIS(7, "redis"),
26   - DEFAULT_MODE(255, "default_mode");
27   -
28   - public int code;
29   - public String subEndpoint;
30   -
31   - LwM2MSecurityMode(int code, String subEndpoint) {
32   - this.code = code;
33   - this.subEndpoint = subEndpoint;
34   - }
35   -
36   - public static LwM2MSecurityMode fromSecurityMode(long code) {
37   - return fromSecurityMode((int) code);
38   - }
39   -
40   - public static LwM2MSecurityMode fromSecurityMode(int code) {
41   - for (LwM2MSecurityMode sm : LwM2MSecurityMode.values()) {
42   - if (sm.code == code) {
43   - return sm;
44   - }
45   - }
46   - throw new IllegalArgumentException(String.format("Unsupported security code : %d", code));
47   - }
48   -
49   -
50   - public static LwM2MSecurityMode fromSecurityMode(String subEndpoint) {
51   - for (LwM2MSecurityMode sm : LwM2MSecurityMode.values()) {
52   - if (sm.subEndpoint.equals(subEndpoint)) {
53   - return sm;
54   - }
55   - }
56   - throw new IllegalArgumentException(String.format("Unsupported security subEndpoint : %d", subEndpoint));
57   - }
58   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.secure;
17   -
18   -import lombok.Data;
19   -import lombok.extern.slf4j.Slf4j;
20   -import org.eclipse.leshan.core.util.Hex;
21   -import java.math.BigInteger;
22   -import java.security.PrivateKey;
23   -import java.security.PublicKey;
24   -import java.security.AlgorithmParameters;
25   -import java.security.KeyFactory;
26   -import java.security.GeneralSecurityException;
27   -import java.security.cert.Certificate;
28   -import java.security.cert.X509Certificate;
29   -import java.security.spec.ECGenParameterSpec;
30   -import java.security.spec.ECParameterSpec;
31   -import java.security.spec.ECPublicKeySpec;
32   -import java.security.spec.KeySpec;
33   -import java.security.spec.ECPrivateKeySpec;
34   -import java.security.spec.ECPoint;
35   -import java.util.List;
36   -
37   -@Slf4j
38   -@Data
39   -public class LwM2mRPkCredentials {
40   - private PublicKey serverPublicKey;
41   - private PrivateKey serverPrivateKey;
42   - private X509Certificate certificate;
43   - private List<Certificate> trustStore;
44   -
45   - /**
46   - * create All key RPK credentials
47   - * @param publX
48   - * @param publY
49   - * @param privS
50   - */
51   - public LwM2mRPkCredentials(String publX, String publY, String privS) {
52   - generatePublicKeyRPK(publX, publY, privS);
53   - }
54   -
55   - private void generatePublicKeyRPK(String publX, String publY, String privS) {
56   - try {
57   - /**Get Elliptic Curve Parameter spec for secp256r1 */
58   - AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC");
59   - algoParameters.init(new ECGenParameterSpec("secp256r1"));
60   - ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class);
61   - if (publX != null && !publX.isEmpty() && publY != null && !publY.isEmpty()) {
62   - // Get point values
63   - byte[] publicX = Hex.decodeHex(publX.toCharArray());
64   - byte[] publicY = Hex.decodeHex(publY.toCharArray());
65   - /** Create key specs */
66   - KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)),
67   - parameterSpec);
68   - /** Get keys */
69   - this.serverPublicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec);
70   - }
71   - if (privS != null && !privS.isEmpty()) {
72   - /** Get point values */
73   - byte[] privateS = Hex.decodeHex(privS.toCharArray());
74   - /** Create key specs */
75   - KeySpec privateKeySpec = new ECPrivateKeySpec(new BigInteger(privateS), parameterSpec);
76   - /** Get keys */
77   - this.serverPrivateKey = KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);
78   - }
79   - } catch (GeneralSecurityException | IllegalArgumentException e) {
80   - log.error("[{}] Failed generate Server KeyRPK", e.getMessage());
81   - throw new RuntimeException(e);
82   - }
83   - }
84   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.secure;
17   -
18   -import com.google.gson.JsonObject;
19   -import lombok.Builder;
20   -import lombok.Data;
21   -import org.eclipse.leshan.server.bootstrap.BootstrapConfig;
22   -import org.eclipse.leshan.server.security.SecurityInfo;
23   -import org.thingsboard.server.common.data.DeviceProfile;
24   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
25   -
26   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.DEFAULT_MODE;
27   -
28   -@Data
29   -public class ReadResultSecurityStore {
30   - private ValidateDeviceCredentialsResponseMsg msg;
31   - private SecurityInfo securityInfo;
32   - @Builder.Default
33   - private int securityMode = DEFAULT_MODE.code;
34   -
35   - /** bootstrap */
36   - DeviceProfile deviceProfile;
37   - JsonObject bootstrapJsonCredential;
38   - String endPoint;
39   - BootstrapConfig bootstrapConfig;
40   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import io.netty.util.concurrent.Future;
19   -import io.netty.util.concurrent.GenericFutureListener;
20   -import lombok.extern.slf4j.Slf4j;
21   -import org.thingsboard.server.common.data.Device;
22   -import org.thingsboard.server.common.data.DeviceProfile;
23   -import org.thingsboard.server.common.transport.SessionMsgListener;
24   -import org.thingsboard.server.gen.transport.TransportProtos;
25   -import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
26   -import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
27   -import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
28   -import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
29   -import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
30   -import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;
31   -
32   -import java.util.Optional;
33   -
34   -@Slf4j
35   -public class LwM2MSessionMsgListener implements GenericFutureListener<Future<? super Void>>, SessionMsgListener {
36   - private LwM2MTransportService service;
37   - private TransportProtos.SessionInfoProto sessionInfo;
38   -
39   - LwM2MSessionMsgListener(LwM2MTransportService service, TransportProtos.SessionInfoProto sessionInfo) {
40   - this.service = service;
41   - this.sessionInfo = sessionInfo;
42   - }
43   -
44   - @Override
45   - public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) {
46   - log.info("[{}] attributesResponse", getAttributesResponse);
47   - }
48   -
49   - @Override
50   - public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) {
51   - this.service.onAttributeUpdate(attributeUpdateNotification, this.sessionInfo);
52   - }
53   -
54   - @Override
55   - public void onRemoteSessionCloseCommand(SessionCloseNotificationProto sessionCloseNotification) {
56   - log.info("[{}] sessionCloseNotification", sessionCloseNotification);
57   - }
58   -
59   - @Override
60   - public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) {
61   - this.service.onToTransportUpdateCredentials(updateCredentials);
62   - }
63   -
64   - @Override
65   - public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
66   - this.service.onDeviceProfileUpdate(sessionInfo, deviceProfile);
67   - }
68   -
69   - @Override
70   - public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {
71   - this.service.onDeviceUpdate(sessionInfo, device, deviceProfileOpt);
72   - }
73   -
74   - @Override
75   - public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
76   - log.info("[{}] toDeviceRpcRequest", toDeviceRequest);
77   - }
78   -
79   - @Override
80   - public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) {
81   - log.info("[{}] toServerRpcResponse", toServerResponse);
82   - }
83   -
84   - @Override
85   - public void operationComplete(Future<? super Void> future) throws Exception {
86   - log.info("[{}] operationComplete", future);
87   - }
88   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -/**
18   - * Copyright © 2016-2020 The Thingsboard Authors
19   - *
20   - * Licensed under the Apache License, Version 2.0 (the "License");
21   - * you may not use this file except in compliance with the License.
22   - * You may obtain a copy of the License at
23   - *
24   - * http://www.apache.org/licenses/LICENSE-2.0
25   - *
26   - * Unless required by applicable law or agreed to in writing, software
27   - * distributed under the License is distributed on an "AS IS" BASIS,
28   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   - * See the License for the specific language governing permissions and
30   - * limitations under the License.
31   - */
32   -
33   -import lombok.extern.slf4j.Slf4j;
34   -import org.springframework.beans.factory.annotation.Autowired;
35   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
36   -import org.springframework.stereotype.Component;
37   -import org.thingsboard.server.common.transport.TransportContext;
38   -import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
39   -
40   -import javax.annotation.PostConstruct;
41   -
42   -@Slf4j
43   -@Component
44   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
45   -public class LwM2MTransportContextServer extends TransportContext {
46   -
47   - private LwM2MTransportConfigServer ctxServer;
48   -
49   - @Autowired
50   - LwM2MTransportConfigServer lwM2MTransportConfigServer;
51   -
52   - @PostConstruct
53   - public void init() {
54   - this.ctxServer = lwM2MTransportConfigServer;
55   - }
56   -
57   - public LwM2MTransportConfigServer getCtxServer () {
58   - return this.ctxServer;
59   - }
60   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import com.fasterxml.jackson.databind.ObjectMapper;
19   -import com.google.gson.Gson;
20   -import com.google.gson.JsonObject;
21   -import com.google.gson.JsonParser;
22   -import com.google.gson.JsonSyntaxException;
23   -import lombok.extern.slf4j.Slf4j;
24   -import org.apache.commons.lang3.StringUtils;
25   -import org.eclipse.californium.core.network.config.NetworkConfig;
26   -import org.eclipse.leshan.core.model.ResourceModel;
27   -import org.eclipse.leshan.core.node.LwM2mNode;
28   -import org.eclipse.leshan.core.node.LwM2mObject;
29   -import org.eclipse.leshan.core.node.LwM2mObjectInstance;
30   -import org.eclipse.leshan.core.node.LwM2mSingleResource;
31   -import org.eclipse.leshan.core.node.LwM2mMultipleResource;
32   -import org.eclipse.leshan.core.util.Hex;
33   -import org.eclipse.leshan.server.californium.LeshanServer;
34   -import org.eclipse.leshan.server.californium.LeshanServerBuilder;
35   -import org.nustaq.serialization.FSTConfiguration;
36   -import org.springframework.beans.factory.annotation.Autowired;
37   -import org.springframework.beans.factory.annotation.Qualifier;
38   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
39   -import org.springframework.stereotype.Component;
40   -import org.thingsboard.server.common.data.DeviceProfile;
41   -import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
42   -import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue;
43   -
44   -import javax.annotation.PostConstruct;
45   -import java.io.File;
46   -import java.io.IOException;
47   -import java.text.DateFormat;
48   -import java.text.SimpleDateFormat;
49   -import java.util.Date;
50   -import java.util.Optional;
51   -import java.util.Map;
52   -import java.util.Arrays;
53   -import java.util.List;
54   -import java.util.ArrayList;
55   -import java.util.LinkedList;
56   -import java.util.Collections;
57   -
58   -@Slf4j
59   -@Component("LwM2MTransportHandler")
60   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
61   -public class LwM2MTransportHandler{
62   -
63   - // We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to
64   - // send a Confirmable message to the time when an acknowledgement is no longer expected.
65   - public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000l; // 2min in ms
66   - public static final String OBSERVE_ATTRIBUTE_TELEMETRY = "observeAttr";
67   - public static final String KEYNAME = "keyName";
68   - public static final String ATTRIBUTE = "attribute";
69   - public static final String TELEMETRY = "telemetry";
70   - public static final String OBSERVE = "observe";
71   - public static final String BOOTSTRAP = "bootstrap";
72   - public static final String SERVERS = "servers";
73   - public static final String LWM2M_SERVER = "lwm2mServer";
74   - public static final String BOOTSTRAP_SERVER = "bootstrapServer";
75   - public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me";
76   - public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + "/attributes";
77   - public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + "/telemetry";
78   - public static final String LOG_LW2M_TELEMETRY = "logLwm2m";
79   - public static final String LOG_LW2M_INFO = "info";
80   - public static final String LOG_LW2M_ERROR = "error";
81   - public static final String LOG_LW2M_WARN = "warn";
82   -
83   -
84   - public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized";
85   -
86   - public static final String GET_TYPE_OPER_READ = "read";
87   - public static final String GET_TYPE_OPER_DISCOVER = "discover";
88   - public static final String GET_TYPE_OPER_OBSERVE = "observe";
89   - public static final String POST_TYPE_OPER_OBSERVE_CANCEL = "observeCancel";
90   - public static final String POST_TYPE_OPER_EXECUTE = "execute";
91   - /**
92   - * Replaces the Object Instance or the Resource(s) with the new value provided in the “Write” operation. (see
93   - * section 5.3.3 of the LW M2M spec).
94   - */
95   - public static final String POST_TYPE_OPER_WRITE_REPLACE = "replace";
96   - /**
97   - * Adds or updates Resources provided in the new value and leaves other existing Resources unchanged. (see section
98   - * 5.3.3 of the LW M2M spec).
99   - */
100   - public static final String PUT_TYPE_OPER_WRITE_UPDATE = "update";
101   - public static final String PUT_TYPE_OPER_WRITE_ATTRIBUTES = "wright-attributes";
102   -
103   - public static final String EVENT_AWAKE = "AWAKE";
104   -
105   - private static Gson gson = null;
106   -
107   - @Autowired
108   - @Qualifier("LeshanServerCert")
109   - private LeshanServer lhServerCert;
110   -
111   - @Autowired
112   - @Qualifier("leshanServerNoSecPskRpk")
113   - private LeshanServer lhServerNoSecPskRpk;
114   -
115   - @Autowired
116   - private LwM2MTransportService service;
117   -
118   -
119   - @PostConstruct
120   - public void init() {
121   - LwM2mServerListener lwM2mServerListener = new LwM2mServerListener(lhServerCert, service);
122   - this.lhServerCert.getRegistrationService().addListener(lwM2mServerListener.registrationListener);
123   - this.lhServerCert.getPresenceService().addListener(lwM2mServerListener.presenceListener);
124   - this.lhServerCert.getObservationService().addListener(lwM2mServerListener.observationListener);
125   - lwM2mServerListener = new LwM2mServerListener(lhServerNoSecPskRpk, service);
126   - this.lhServerNoSecPskRpk.getRegistrationService().addListener(lwM2mServerListener.registrationListener);
127   - this.lhServerNoSecPskRpk.getPresenceService().addListener(lwM2mServerListener.presenceListener);
128   - this.lhServerNoSecPskRpk.getObservationService().addListener(lwM2mServerListener.observationListener);
129   - }
130   -
131   - public static NetworkConfig getCoapConfig() {
132   - NetworkConfig coapConfig;
133   - File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME);
134   - if (configFile.isFile()) {
135   - coapConfig = new NetworkConfig();
136   - coapConfig.load(configFile);
137   - } else {
138   - coapConfig = LeshanServerBuilder.createDefaultNetworkConfig();
139   - coapConfig.store(configFile);
140   - }
141   - return coapConfig;
142   - }
143   -
144   - public static String getValueTypeToString (Object value, ResourceModel.Type type) {
145   - switch (type) {
146   - case STRING: // String
147   - case OBJLNK: // ObjectLink
148   - return value.toString();
149   - case INTEGER: // Long
150   - return Long.toString((long) value);
151   - case BOOLEAN: // Boolean
152   - return Boolean.toString((Boolean) value);
153   - case FLOAT: // Double
154   - return Double.toString((Float)value);
155   - case TIME: // Date
156   - String DATE_FORMAT = "MMM d, yyyy HH:mm a";
157   - DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
158   - return formatter.format(new Date((Long) Integer.toUnsignedLong(Integer.valueOf((Integer) value))));
159   - case OPAQUE: // byte[] value, base64
160   - return Hex.encodeHexString((byte[])value);
161   - default:
162   - return null;
163   - }
164   - }
165   -
166   - public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
167   - if (content instanceof LwM2mObject) {
168   - return (LwM2mObject) content;
169   - } else if (content instanceof LwM2mObjectInstance) {
170   - return (LwM2mObjectInstance) content;
171   - } else if (content instanceof LwM2mSingleResource) {
172   - return (LwM2mSingleResource) content;
173   - } else if (content instanceof LwM2mMultipleResource) {
174   - return (LwM2mMultipleResource) content;
175   - }
176   - return null;
177   - }
178   -
179   - public static AttrTelemetryObserveValue getNewProfileParameters(JsonObject profilesConfigData) {
180   - AttrTelemetryObserveValue attrTelemetryObserveValue = new AttrTelemetryObserveValue();
181   - attrTelemetryObserveValue.setPostKeyNameProfile(profilesConfigData.get(KEYNAME).getAsJsonObject());
182   - attrTelemetryObserveValue.setPostAttributeProfile(profilesConfigData.get(ATTRIBUTE).getAsJsonArray());
183   - attrTelemetryObserveValue.setPostTelemetryProfile(profilesConfigData.get(TELEMETRY).getAsJsonArray());
184   - attrTelemetryObserveValue.setPostObserveProfile(profilesConfigData.get(OBSERVE).getAsJsonArray());
185   - return attrTelemetryObserveValue;
186   - }
187   -
188   - /**
189   -
190   - * @return deviceProfileBody with Observe&Attribute&Telemetry From Thingsboard
191   - * Example: with pathResource (use only pathResource)
192   - * property: "observeAttr"
193   - * {"keyName": {
194   - * "/3/0/1": "modelNumber",
195   - * "/3/0/0": "manufacturer",
196   - * "/3/0/2": "serialNumber"
197   - * },
198   - * "attribute":["/2/0/1","/3/0/9"],
199   - * "telemetry":["/1/0/1","/2/0/1","/6/0/1"],
200   - * "observe":["/2/0","/2/0/0","/4/0/2"]}
201   - */
202   - public static JsonObject getObserveAttrTelemetryFromThingsboard(DeviceProfile deviceProfile) {
203   - if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
204   - Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
205   - Object observeAttr = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
206   - try {
207   - ObjectMapper mapper = new ObjectMapper();
208   - String observeAttrStr = mapper.writeValueAsString(observeAttr);
209   - JsonObject objectMsg = (observeAttrStr != null) ? validateJson(observeAttrStr) : null;
210   - return (getValidateCredentialsBodyFromThingsboard(objectMsg)) ? objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject() : null;
211   - } catch (IOException e) {
212   - e.printStackTrace();
213   - }
214   - }
215   - return null;
216   - }
217   -
218   - public static JsonObject getBootstrapParametersFromThingsboard(DeviceProfile deviceProfile) {
219   - if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) {
220   - Lwm2mDeviceProfileTransportConfiguration lwm2mDeviceProfileTransportConfiguration = (Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
221   - Object bootstrap = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties();
222   - try {
223   - ObjectMapper mapper = new ObjectMapper();
224   - String bootstrapStr = mapper.writeValueAsString(bootstrap);
225   - JsonObject objectMsg = (bootstrapStr != null) ? validateJson(bootstrapStr) : null;
226   - return (getValidateBootstrapProfileFromThingsboard(objectMsg)) ? objectMsg.get(BOOTSTRAP).getAsJsonObject() : null;
227   - } catch (IOException e) {
228   - e.printStackTrace();
229   - }
230   - }
231   - return null;
232   - }
233   -
234   - private static boolean getValidateCredentialsBodyFromThingsboard(JsonObject objectMsg) {
235   - return (objectMsg != null &&
236   - !objectMsg.isJsonNull() &&
237   - objectMsg.has(OBSERVE_ATTRIBUTE_TELEMETRY) &&
238   - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonNull() &&
239   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).isJsonObject() &&
240   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(KEYNAME) &&
241   - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEYNAME).isJsonNull() &&
242   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEYNAME).isJsonObject() &&
243   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(ATTRIBUTE) &&
244   - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonNull() &&
245   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).isJsonArray() &&
246   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(TELEMETRY) &&
247   - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonNull() &&
248   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(TELEMETRY).isJsonArray() &&
249   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().has(OBSERVE) &&
250   - !objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonNull() &&
251   - objectMsg.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(OBSERVE).isJsonArray());
252   - }
253   -
254   - private static boolean getValidateBootstrapProfileFromThingsboard(JsonObject objectMsg) {
255   - return (objectMsg != null &&
256   - !objectMsg.isJsonNull() &&
257   - objectMsg.has(BOOTSTRAP) &&
258   - objectMsg.get(BOOTSTRAP).isJsonObject() &&
259   - !objectMsg.get(BOOTSTRAP).isJsonNull() &&
260   - objectMsg.get(BOOTSTRAP).getAsJsonObject().has(SERVERS) &&
261   - !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonNull() &&
262   - objectMsg.get(BOOTSTRAP).getAsJsonObject().get(SERVERS).isJsonObject() &&
263   - objectMsg.get(BOOTSTRAP).getAsJsonObject().has(BOOTSTRAP_SERVER) &&
264   - !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonNull() &&
265   - objectMsg.get(BOOTSTRAP).getAsJsonObject().get(BOOTSTRAP_SERVER).isJsonObject() &&
266   - objectMsg.get(BOOTSTRAP).getAsJsonObject().has(LWM2M_SERVER) &&
267   - !objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonNull() &&
268   - objectMsg.get(BOOTSTRAP).getAsJsonObject().get(LWM2M_SERVER).isJsonObject());
269   - }
270   -
271   -
272   - public static JsonObject validateJson(String jsonStr) {
273   - JsonObject object = null;
274   - if (jsonStr != null && !jsonStr.isEmpty()) {
275   - String jsonValidFlesh = jsonStr.replaceAll("\\\\", "");
276   - jsonValidFlesh = jsonValidFlesh.replaceAll("\n", "");
277   - jsonValidFlesh = jsonValidFlesh.replaceAll("\t", "");
278   - jsonValidFlesh = jsonValidFlesh.replaceAll(" ", "");
279   - String jsonValid = (jsonValidFlesh.substring(0, 1).equals("\"") && jsonValidFlesh.substring(jsonValidFlesh.length() - 1).equals("\"")) ? jsonValidFlesh.substring(1, jsonValidFlesh.length() - 1) : jsonValidFlesh;
280   - try {
281   - object = new JsonParser().parse(jsonValid).getAsJsonObject();
282   - } catch (JsonSyntaxException e) {
283   - log.error("[{}] Fail validateJson [{}]", jsonStr, e.getMessage());
284   - }
285   - }
286   - return object;
287   - }
288   -
289   - public static <T> Optional<T> decode(byte[] byteArray) {
290   - try {
291   - FSTConfiguration config = FSTConfiguration.createDefaultConfiguration();;
292   - T msg = (T) config.asObject(byteArray);
293   - return Optional.ofNullable(msg);
294   - } catch (IllegalArgumentException e) {
295   - log.error("Error during deserialization message, [{}]", e.getMessage());
296   - return Optional.empty();
297   - }
298   - }
299   -
300   - /**
301   - * Equals to Map for values
302   - * @param map1
303   - * @param map2
304   - * @param <V>
305   - * @return
306   - */
307   - public static <V extends Comparable<V>> boolean mapsEquals(Map<?,V> map1, Map<?,V> map2) {
308   - List<V> values1 = new ArrayList<V>(map1.values());
309   - List<V> values2 = new ArrayList<V>(map2.values());
310   - Collections.sort(values1);
311   - Collections.sort(values2);
312   - return values1.equals(values2);
313   - }
314   -
315   - public static String convertCamelCase (String str) {
316   - str = str.toLowerCase().replace("/[^a-z ]+/g", " ");
317   - str = str.replace("/^(.)|\\s(.)/g", "$1");
318   - str = str.replace("/[^a-zA-Z]+/g", "");
319   - return str;
320   - }
321   -
322   - public static String splitCamelCaseString(String s){
323   - LinkedList<String> linkedListOut = new LinkedList<String>();
324   - LinkedList<String> linkedList = new LinkedList<String>((Arrays.asList(s.split(" "))));
325   - linkedList.stream().forEach(str-> {
326   - String strOut = str.replaceAll("\\W", "").replaceAll("_", "").toUpperCase();
327   - if (strOut.length()>1) linkedListOut.add(strOut.substring(0, 1) + strOut.substring(1).toLowerCase());
328   - else linkedListOut.add(strOut);
329   - });
330   - linkedListOut.set(0, (linkedListOut.get(0).substring(0, 1).toLowerCase() + linkedListOut.get(0).substring(1)));
331   - return StringUtils.join(linkedListOut, "");
332   - }
333   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.californium.core.coap.Response;
20   -import org.eclipse.leshan.core.attributes.Attribute;
21   -import org.eclipse.leshan.core.attributes.AttributeSet;
22   -import org.eclipse.leshan.core.model.ResourceModel;
23   -import org.eclipse.leshan.core.node.LwM2mSingleResource;
24   -import org.eclipse.leshan.core.node.ObjectLink;
25   -import org.eclipse.leshan.core.observation.Observation;
26   -import org.eclipse.leshan.core.request.ContentFormat;
27   -import org.eclipse.leshan.core.request.WriteRequest;
28   -import org.eclipse.leshan.core.request.DiscoverRequest;
29   -import org.eclipse.leshan.core.request.DownlinkRequest;
30   -import org.eclipse.leshan.core.request.ObserveRequest;
31   -import org.eclipse.leshan.core.request.CancelObservationRequest;
32   -import org.eclipse.leshan.core.request.ReadRequest;
33   -import org.eclipse.leshan.core.request.ExecuteRequest;
34   -import org.eclipse.leshan.core.request.WriteAttributesRequest;
35   -import org.eclipse.leshan.core.response.ResponseCallback;
36   -import org.eclipse.leshan.core.response.LwM2mResponse;
37   -import org.eclipse.leshan.core.response.ObserveResponse;
38   -import org.eclipse.leshan.core.response.ReadResponse;
39   -import org.eclipse.leshan.core.response.CancelObservationResponse;
40   -import org.eclipse.leshan.core.response.DeleteResponse;
41   -import org.eclipse.leshan.core.response.ExecuteResponse;
42   -import org.eclipse.leshan.core.response.DiscoverResponse;
43   -import org.eclipse.leshan.core.response.WriteAttributesResponse;
44   -import org.eclipse.leshan.core.response.WriteResponse;
45   -import org.eclipse.leshan.core.util.Hex;
46   -import org.eclipse.leshan.core.util.NamedThreadFactory;
47   -import org.eclipse.leshan.server.californium.LeshanServer;
48   -import org.eclipse.leshan.server.registration.Registration;
49   -import org.springframework.beans.factory.annotation.Autowired;
50   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
51   -import org.springframework.stereotype.Service;
52   -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient;
53   -
54   -import javax.annotation.PostConstruct;
55   -import java.util.ArrayList;
56   -import java.util.Collection;
57   -import java.util.Date;
58   -import java.util.Iterator;
59   -import java.util.concurrent.ExecutorService;
60   -import java.util.concurrent.Executors;
61   -
62   -import static org.eclipse.californium.core.coap.CoAP.ResponseCode.isSuccess;
63   -import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD;
64   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEFAULT_TIMEOUT;
65   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_DISCOVER;
66   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_OBSERVE;
67   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ;
68   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES;
69   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE;
70   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_EXECUTE;
71   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_OBSERVE_CANCEL;
72   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_WRITE_REPLACE;
73   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR;
74   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO;
75   -
76   -@Slf4j
77   -@Service("LwM2MTransportRequest")
78   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
79   -public class LwM2MTransportRequest {
80   - private final ExecutorService executorService;
81   - private static final String RESPONSE_CHANNEL = "THINGSBOARD_RESP";
82   -
83   - @Autowired
84   - LwM2MTransportService service;
85   -
86   - public LwM2MTransportRequest() {
87   - executorService = Executors.newCachedThreadPool(
88   - new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL)));
89   - }
90   -
91   -
92   - @PostConstruct
93   - public void init() {
94   - }
95   -
96   - public Collection<Registration> doGetRegistrations(LeshanServer lwServer) {
97   - Collection<Registration> registrations = new ArrayList<>();
98   - for (Iterator<Registration> iterator = lwServer.getRegistrationService().getAllRegistrations(); iterator
99   - .hasNext(); ) {
100   - registrations.add(iterator.next());
101   - }
102   - return registrations;
103   - }
104   -
105   - /**
106   - * Device management and service enablement, including Read, Write, Execute, Discover, Create, Delete and Write-Attributes
107   - *
108   - * @param lwServer
109   - * @param registration
110   - * @param target
111   - * @param typeOper
112   - * @param contentFormatParam
113   - * @param lwM2MClient
114   - * @param observation
115   - */
116   - public void sendAllRequest(LeshanServer lwServer, Registration registration, String target, String typeOper,
117   - String contentFormatParam, LwM2MClient lwM2MClient, Observation observation, Object params, long timeoutInMs) {
118   - ResultIds resultIds = new ResultIds(target);
119   - if (registration != null && resultIds.getObjectId() >= 0) {
120   - DownlinkRequest request = null;
121   - 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;
124   - ResourceModel.Type resType = (resource == null) ? null : resource.type;
125   - boolean resMultiple = (resource == null) ? false : resource.multiple;
126   - timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
127   - switch (typeOper) {
128   - case GET_TYPE_OPER_READ:
129   - request = new ReadRequest(contentFormat, target);
130   - break;
131   - case GET_TYPE_OPER_DISCOVER:
132   - request = new DiscoverRequest(target);
133   - break;
134   - 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());
139   - } else if (resultIds.getObjectId() >= 0) {
140   - request = new ObserveRequest(resultIds.getObjectId());
141   - }
142   - break;
143   - case POST_TYPE_OPER_OBSERVE_CANCEL:
144   - request = new CancelObservationRequest(observation);
145   - break;
146   - case POST_TYPE_OPER_EXECUTE:
147   - if (params != null && !resMultiple) {
148   - request = new ExecuteRequest(target, LwM2MTransportHandler.getValueTypeToString(params, resType));
149   - } else {
150   - request = new ExecuteRequest(target);
151   - }
152   - break;
153   - case POST_TYPE_OPER_WRITE_REPLACE:
154   - // Request to write a <b>String Single-Instance Resource</b> using the TLV content format.
155   - if (contentFormat.equals(ContentFormat.TLV) && !resMultiple) {
156   - request = this.getWriteRequestSingleResource(null, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType);
157   - }
158   - // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON)
159   - else if (!contentFormat.equals(ContentFormat.TLV) && !resMultiple) {
160   - request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, resType);
161   - }
162   - break;
163   - case PUT_TYPE_OPER_WRITE_UPDATE:
164   - if (resultIds.getResourceId() >= 0) {
165   - ResourceModel resourceModel = lwServer.getModelProvider().getObjectModel(registration).getObjectModel(resultIds.getObjectId()).resources.get(resultIds.getResourceId());
166   - ResourceModel.Type typeRes = resourceModel.type;
167   -// request = getWriteRequestResource(resultIds.getObjectId(), resultIds.getInstanceId(), resultIds.getResourceId(), params, typeRes);
168   - }
169   - break;
170   - case PUT_TYPE_OPER_WRITE_ATTRIBUTES:
171   - /**
172   - * As example:
173   - * a)Write-Attributes/3/0/9?pmin=1 means the Battery Level value will be notified
174   - * to the Server with a minimum interval of 1sec;
175   - * this value is set at theResource level.
176   - * b)Write-Attributes/3/0/9?pmin means the Battery Level will be notified
177   - * to the Server with a minimum value (pmin) given by the default one
178   - * (resource 2 of Object Server ID=1),
179   - * or with another value if this Attribute has been set at another level
180   - * (Object or Object Instance: see section5.1.1).
181   - * c)Write-Attributes/3/0?pmin=10 means that all Resources of Instance 0 of the Object ‘Device (ID:3)’
182   - * will be notified to the Server with a minimum interval of 10 sec;
183   - * this value is set at the Object Instance level.
184   - * d)Write-Attributes /3/0/9?gt=45&st=10 means the Battery Level will be notified to the Server
185   - * when:
186   - * a.old value is 20 and new value is 35 due to step condition
187   - * b.old value is 45 and new value is 50 due to gt condition
188   - * c.old value is 50 and new value is 40 due to both gt and step conditions
189   - * d.old value is 35 and new value is 20 due to step conditione)
190   - * Write-Attributes /3/0/9?lt=20&gt=85&st=10 means the Battery Level will be notified to the Server
191   - * when:
192   - * a.old value is 17 and new value is 24 due to lt condition
193   - * b.old value is 75 and new value is 90 due to both gt and step conditions
194   - * String uriQueries = "pmin=10&pmax=60";
195   - * AttributeSet attributes = AttributeSet.parse(uriQueries);
196   - * WriteAttributesRequest request = new WriteAttributesRequest(target, attributes);
197   - * Attribute gt = new Attribute(GREATER_THAN, Double.valueOf("45"));
198   - * Attribute st = new Attribute(LESSER_THAN, Double.valueOf("10"));
199   - * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
200   - * Attribute [] attrs = {gt, st};
201   - */
202   - Attribute pmin = new Attribute(MINIMUM_PERIOD, Integer.toUnsignedLong(Integer.valueOf("1")));
203   - Attribute[] attrs = {pmin};
204   - 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   - } else if (resultIds.getObjectId() >= 0) {
210   - request = new WriteAttributesRequest(resultIds.getObjectId(), attrSet);
211   - }
212   - break;
213   - default:
214   - }
215   - if (request != null) sendRequest(lwServer, registration, request, lwM2MClient, timeoutInMs);
216   - }
217   - }
218   -
219   - /**
220   - *
221   - * @param lwServer
222   - * @param registration
223   - * @param request
224   - * @param lwM2MClient
225   - * @param timeoutInMs
226   - */
227   - private void sendRequest(LeshanServer lwServer, Registration registration, DownlinkRequest request, LwM2MClient lwM2MClient, long timeoutInMs) {
228   - lwServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
229   - if (isSuccess(((Response)response.getCoapResponse()).getCode())) {
230   - this.handleResponse(registration, request.getPath().toString(), response, request, lwM2MClient);
231   - if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) {
232   - String msg = String.format(LOG_LW2M_INFO + " sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client",
233   - ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString(),
234   - ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue().toString());
235   - service.sentLogsToThingsboard(msg, registration.getId());
236   - log.info("[{}] - [{}] [{}] [{}] Update SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString(), ((LwM2mSingleResource)((WriteRequest) request).getNode()).getValue());
237   - }
238   - }
239   - else {
240   - String msg = String.format(LOG_LW2M_ERROR + " sendRequest: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client",
241   - ((Response)response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());
242   - service.sentLogsToThingsboard(msg, registration.getId());
243   - log.error("[{}] - [{}] [{}] error SendRequest", ((Response)response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
244   - }
245   - }, e -> {
246   - String msg = String.format(LOG_LW2M_ERROR + " sendRequest: Resource path - %s msg error - %s SendRequest to Client",
247   - request.getPath().toString(), e.toString());
248   - service.sentLogsToThingsboard(msg, registration.getId());
249   - log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString());
250   - });
251   - }
252   -
253   - private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, Integer resourceId, Object value, ResourceModel.Type type) {
254   - try {
255   - switch (type) {
256   - case STRING: // String
257   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, value.toString()) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, value.toString());
258   - case INTEGER: // Long
259   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Integer.toUnsignedLong(Integer.valueOf(value.toString()))) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Integer.toUnsignedLong(Integer.valueOf(value.toString())));
260   - case OBJLNK: // ObjectLink
261   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, ObjectLink.fromPath(value.toString()));
262   - case BOOLEAN: // Boolean
263   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Boolean.valueOf(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Boolean.valueOf(value.toString()));
264   - case FLOAT: // Double
265   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Double.valueOf(value.toString())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Double.valueOf(value.toString()));
266   - case TIME: // Date
267   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString())))) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, new Date((Long) Integer.toUnsignedLong(Integer.valueOf(value.toString()))));
268   - case OPAQUE: // byte[] value, base64
269   - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray()));
270   - default:
271   - }
272   - return null;
273   - } catch (NumberFormatException e) {
274   - String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;
275   - log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());
276   - return null;
277   - }
278   - }
279   -
280   - private void handleResponse(Registration registration, final String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient) {
281   - executorService.submit(new Runnable() {
282   - @Override
283   - public void run() {
284   -
285   - try {
286   - sendResponse(registration, path, response, request, lwM2MClient);
287   - } catch (RuntimeException t) {
288   - log.error("[{}] endpoint [{}] path [{}] error Unable to after send response.", registration.getEndpoint(), path, t.toString());
289   - }
290   - }
291   - });
292   - }
293   -
294   - /**
295   - * processing a response from a client
296   - * @param registration -
297   - * @param path -
298   - * @param response -
299   - * @param lwM2MClient -
300   - */
301   - private void sendResponse(Registration registration, String path, LwM2mResponse response, DownlinkRequest request, LwM2MClient lwM2MClient) {
302   - if (response instanceof ObserveResponse) {
303   - service.onObservationResponse(registration, path, (ReadResponse) response);
304   - } else if (response instanceof CancelObservationResponse) {
305   - log.info("[{}] Path [{}] CancelObservationResponse 3_Send", path, response);
306   - } else if (response instanceof ReadResponse) {
307   - /**
308   - * Use only at the first start after registration
309   - * Fill with data -> Model client
310   - */
311   - if (lwM2MClient != null) {
312   - if (lwM2MClient.getPendingRequests().size() > 0) {
313   - lwM2MClient.onSuccessHandler(path, response);
314   - }
315   - }
316   - /**
317   - * Use after registration on request
318   - */
319   - else {
320   - service.onObservationResponse(registration, path, (ReadResponse) response);
321   - }
322   - } else if (response instanceof DeleteResponse) {
323   - log.info("[{}] Path [{}] DeleteResponse 5_Send", path, response);
324   - } else if (response instanceof DiscoverResponse) {
325   - log.info("[{}] Path [{}] DiscoverResponse 6_Send", path, response);
326   - } else if (response instanceof ExecuteResponse) {
327   - log.info("[{}] Path [{}] ExecuteResponse 7_Send", path, response);
328   - } else if (response instanceof WriteAttributesResponse) {
329   - log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", path, response);
330   - } else if (response instanceof WriteResponse) {
331   - log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", path, response);
332   - service.onAttributeUpdateOk(registration, path, (WriteRequest) request);
333   - }
334   - }
335   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
20   -import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder;
21   -import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder;
22   -import org.eclipse.leshan.core.node.codec.LwM2mNodeDecoder;
23   -import org.eclipse.leshan.server.californium.LeshanServer;
24   -import org.eclipse.leshan.server.californium.LeshanServerBuilder;
25   -import org.eclipse.leshan.server.model.LwM2mModelProvider;
26   -import org.eclipse.leshan.server.model.VersionedModelProvider;
27   -import org.springframework.beans.factory.annotation.Autowired;
28   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
29   -import org.springframework.context.annotation.Bean;
30   -import org.springframework.context.annotation.ComponentScan;
31   -import org.springframework.context.annotation.Configuration;
32   -import org.springframework.context.annotation.Primary;
33   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
34   -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2MSetSecurityStoreServer;
35   -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore;
36   -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
37   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509;
38   -import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RPK;
39   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig;
40   -
41   -
42   -@Slf4j
43   -@ComponentScan("org.thingsboard.server.transport.lwm2m.server")
44   -@ComponentScan("org.thingsboard.server.transport.lwm2m.utils")
45   -@Configuration("LwM2MTransportServerConfiguration")
46   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
47   -public class LwM2MTransportServerConfiguration {
48   -
49   - @Autowired
50   - private LwM2MTransportContextServer context;
51   -
52   - @Autowired
53   - private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore;
54   -
55   - @Primary
56   - @Bean(name = "LeshanServerCert")
57   - public LeshanServer getLeshanServerCert() {
58   - log.info("Starting LwM2M transport ServerCert... PostConstruct");
59   - return getLeshanServer(this.context.getCtxServer().getServerPortCert(), this.context.getCtxServer().getServerSecurePortCert(), X509);
60   - }
61   -
62   - @Bean(name = "leshanServerNoSecPskRpk")
63   - public LeshanServer getLeshanServerNoSecPskRpk() {
64   - log.info("Starting LwM2M transport ServerNoSecPskRpk... PostConstruct");
65   - return getLeshanServer(this.context.getCtxServer().getServerPort(), this.context.getCtxServer().getServerSecurePort(), RPK);
66   - }
67   -
68   - private LeshanServer getLeshanServer(Integer serverPort, Integer serverSecurePort, LwM2MSecurityMode dtlsMode) {
69   -
70   - LeshanServerBuilder builder = new LeshanServerBuilder();
71   - builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPort);
72   - builder.setLocalSecureAddress(this.context.getCtxServer().getServerSecureHost(), serverSecurePort);
73   - builder.setEncoder(new DefaultLwM2mNodeEncoder());
74   - LwM2mNodeDecoder decoder = new DefaultLwM2mNodeDecoder();
75   - builder.setDecoder(decoder);
76   - builder.setEncoder(new DefaultLwM2mNodeEncoder(new LwM2mValueConverterImpl()));
77   -
78   - /** Create CoAP Config */
79   - builder.setCoapConfig(getCoapConfig());
80   -
81   - /** Define model provider (Create Models )*/
82   - LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getCtxServer().getModelsValue());
83   - builder.setObjectModelProvider(modelProvider);
84   -
85   - /** Create DTLS Config */
86   - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
87   - dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isSupportDeprecatedCiphersEnable());
88   - /** Set DTLS Config */
89   - builder.setDtlsConfig(dtlsConfig);
90   -
91   - /** Use a magic converter to support bad type send by the UI. */
92   - builder.setEncoder(new DefaultLwM2mNodeEncoder(new LwM2mValueConverterImpl()));
93   -
94   - /** Create DTLS security mode
95   - * There can be only one DTLS security mode
96   - */
97   - new LwM2MSetSecurityStoreServer(builder, context, lwM2mInMemorySecurityStore, dtlsMode);
98   -
99   - /** Create LWM2M server */
100   - return builder.build();
101   - }
102   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.leshan.server.californium.LeshanServer;
20   -import org.springframework.beans.factory.annotation.Autowired;
21   -import org.springframework.beans.factory.annotation.Qualifier;
22   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
23   -import org.springframework.stereotype.Service;
24   -import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
25   -import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
26   -import javax.annotation.PostConstruct;
27   -import javax.annotation.PreDestroy;
28   -
29   -@Slf4j
30   -@Service("LwM2MTransportServerInitializer")
31   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
32   -public class LwM2MTransportServerInitializer {
33   -
34   - @Autowired
35   - @Qualifier("LeshanServerCert")
36   - private LeshanServer lhServerCert;
37   -
38   - @Autowired
39   - @Qualifier("leshanServerNoSecPskRpk")
40   - private LeshanServer lhServerNoSecPskRpk;
41   -
42   - @Autowired
43   - private LwM2MTransportContextServer context;
44   -
45   - @PostConstruct
46   - public void init() {
47   - if (this.context.getCtxServer().getEnableGenPskRpk()) new LWM2MGenerationPSkRPkECC();
48   - if (this.context.getCtxServer().isServerStartAll()) {
49   - this.lhServerCert.start();
50   - this.lhServerNoSecPskRpk.start();
51   - }
52   - else {
53   - if (this.context.getCtxServer().getServerDtlsMode() == LwM2MSecurityMode.X509.code) {
54   - this.lhServerCert.start();
55   - }
56   - else {
57   - this.lhServerNoSecPskRpk.start();
58   - }
59   - }
60   - }
61   -
62   - @PreDestroy
63   - public void shutdown() {
64   - log.info("Stopping LwM2M transport Server!");
65   - try {
66   - lhServerCert.destroy();
67   - lhServerNoSecPskRpk.destroy();
68   - } finally {
69   - }
70   - log.info("LwM2M transport Server stopped!");
71   - }
72   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import com.google.gson.*;
19   -import lombok.SneakyThrows;
20   -import lombok.extern.slf4j.Slf4j;
21   -import org.eclipse.leshan.core.model.ResourceModel;
22   -import org.eclipse.leshan.core.node.LwM2mMultipleResource;
23   -import org.eclipse.leshan.core.node.LwM2mObject;
24   -import org.eclipse.leshan.core.node.LwM2mObjectInstance;
25   -import org.eclipse.leshan.core.node.LwM2mSingleResource;
26   -import org.eclipse.leshan.core.node.LwM2mResource;
27   -import org.eclipse.leshan.core.node.LwM2mPath;
28   -import org.eclipse.leshan.core.observation.Observation;
29   -import org.eclipse.leshan.core.request.ContentFormat;
30   -import org.eclipse.leshan.core.request.WriteRequest;
31   -import org.eclipse.leshan.core.response.ReadResponse;
32   -import org.eclipse.leshan.core.util.Hex;
33   -import org.eclipse.leshan.server.californium.LeshanServer;
34   -import org.eclipse.leshan.server.registration.Registration;
35   -import org.springframework.beans.factory.annotation.Autowired;
36   -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
37   -import org.springframework.stereotype.Service;
38   -import org.thingsboard.server.common.data.Device;
39   -import org.thingsboard.server.common.data.DeviceProfile;
40   -import org.thingsboard.server.common.transport.TransportService;
41   -import org.thingsboard.server.common.transport.TransportServiceCallback;
42   -import org.thingsboard.server.common.transport.adaptor.AdaptorException;
43   -import org.thingsboard.server.common.transport.adaptor.JsonConverter;
44   -import org.thingsboard.server.common.transport.service.DefaultTransportService;
45   -import org.thingsboard.server.gen.transport.TransportProtos;
46   -import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCredentialsProto;
47   -import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent;
48   -import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
49   -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
50   -import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
51   -import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
52   -import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
53   -import org.thingsboard.server.transport.lwm2m.server.client.AttrTelemetryObserveValue;
54   -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient;
55   -import org.thingsboard.server.transport.lwm2m.server.client.ModelObject;
56   -import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters;
57   -import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
58   -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore;
59   -
60   -import javax.annotation.PostConstruct;
61   -import java.util.Collection;
62   -import java.util.UUID;
63   -import java.util.Random;
64   -import java.util.Map;
65   -import java.util.HashMap;
66   -import java.util.Arrays;
67   -import java.util.Set;
68   -import java.util.HashSet;
69   -import java.util.NoSuchElementException;
70   -import java.util.Optional;
71   -import java.util.concurrent.ConcurrentHashMap;
72   -import java.util.concurrent.ConcurrentMap;
73   -import java.util.concurrent.CountDownLatch;
74   -import java.util.concurrent.TimeUnit;
75   -import java.util.concurrent.atomic.AtomicBoolean;
76   -import java.util.function.Predicate;
77   -import java.util.stream.Collectors;
78   -import java.util.stream.Stream;
79   -
80   -import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
81   -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.*;
82   -
83   -@Slf4j
84   -@Service("LwM2MTransportService")
85   -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
86   -public class LwM2MTransportService {
87   -
88   - @Autowired
89   - private LwM2MJsonAdaptor adaptor;
90   -
91   - @Autowired
92   - private TransportService transportService;
93   -
94   - @Autowired
95   - public LwM2MTransportContextServer context;
96   -
97   - @Autowired
98   - private LwM2MTransportRequest lwM2MTransportRequest;
99   -
100   - @Autowired
101   - LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore;
102   -
103   -
104   - @PostConstruct
105   - public void init() {
106   - context.getScheduler().scheduleAtFixedRate(() -> checkInactivityAndReportActivity(), new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS);
107   - }
108   -
109   - /**
110   - * Start registration device
111   - * Create session: Map<String <registrationId >, LwM2MClient>
112   - * 1. replaceNewRegistration -> (solving the problem of incorrect termination of the previous session with this endpoint)
113   - * 1.1 When we initialize the registration, we register the session by endpoint.
114   - * 1.2 If the server has incomplete requests (canceling the registration of the previous session),
115   - * delete the previous session only by the previous registration.getId
116   - * 1.2 Add Model (Entity) for client (from registration & observe) by registration.getId
117   - * 1.2 Remove from sessions Model by enpPoint
118   - * Next -> Create new LwM2MClient for current session -> setModelClient...
119   - *
120   - * @param lwServer - LeshanServer
121   - * @param registration - Registration LwM2M Client
122   - * @param previousObsersations - may be null
123   - */
124   - public void onRegistered(LeshanServer lwServer, Registration registration, Collection<Observation> previousObsersations) {
125   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(lwServer, registration);
126   - if (lwM2MClient != null) {
127   - lwM2MClient.setLwM2MTransportService(this);
128   - lwM2MClient.setLwM2MTransportService(this);
129   - lwM2MClient.setSessionUuid(UUID.randomUUID());
130   - this.setLwM2MClient(lwServer, registration, lwM2MClient);
131   - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId());
132   - if (sessionInfo != null) {
133   - lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB()));
134   - lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
135   - lwM2MClient.setDeviceName(sessionInfo.getDeviceName());
136   - lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType());
137   - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo));
138   - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null);
139   - transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null);
140   - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client registration", registration.getId());
141   - } else {
142   - log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo);
143   - }
144   - } else {
145   - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), lwM2MClient);
146   - }
147   - }
148   -
149   - /**
150   - * @param lwServer - LeshanServer
151   - * @param registration - Registration LwM2M Client
152   - */
153   - public void updatedReg(LeshanServer lwServer, Registration registration) {
154   - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId());
155   - if (sessionInfo != null) {
156   - log.info("Client: [{}] updatedReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
157   - } else {
158   - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo);
159   - }
160   - }
161   -
162   - /**
163   - * @param registration - Registration LwM2M Client
164   - * @param observations - All paths observations before unReg
165   - * !!! Warn: if have not finishing unReg, then this operation will be finished on next Client`s connect
166   - */
167   - public void unReg(Registration registration, Collection<Observation> observations) {
168   - this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
169   - this.closeClientSession(registration);
170   - }
171   -
172   - private void closeClientSession(Registration registration) {
173   - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration.getId());
174   - if (sessionInfo != null) {
175   - transportService.deregisterSession(sessionInfo);
176   - this.doCloseSession(sessionInfo);
177   - lwM2mInMemorySecurityStore.delRemoveSessionAndListener(registration.getId());
178   - if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) {
179   - this.syncSessionsAndProfiles();
180   - }
181   - log.info("Client: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
182   - } else {
183   - log.error("Client: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), sessionInfo);
184   - }
185   - }
186   -
187   - public void onSleepingDev(Registration registration) {
188   - log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint());
189   - //TODO: associate endpointId with device information.
190   - }
191   -
192   - /**
193   - * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay,
194   - * * if you need to do long time processing use a dedicated thread pool.
195   - *
196   - * @param registration
197   - */
198   -
199   - public void onAwakeDev(Registration registration) {
200   - log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
201   - //TODO: associate endpointId with device information.
202   - }
203   -
204   - /**
205   - * This method is used to sync with sessions
206   - * Removes a profile if not used in sessions
207   - */
208   - private void syncSessionsAndProfiles() {
209   - Map<UUID, AttrTelemetryObserveValue> profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet()
210   - .stream()
211   - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
212   - profilesClone.forEach((k, v) -> {
213   - String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet()
214   - .stream()
215   - .filter(e -> e.getValue().getProfileUuid().equals(k))
216   - .findFirst()
217   - .map(Map.Entry::getKey) // return the key of the matching entry if found
218   - .orElse("");
219   - if (registrationId.isEmpty()) {
220   - lwM2mInMemorySecurityStore.getProfiles().remove(k);
221   - }
222   - });
223   - }
224   -
225   - /**
226   - * Create new LwM2MClient for current session -> setModelClient...
227   - * #1 Add all ObjectLinks (instance) to control the process of executing requests to the client
228   - * to get the client model with current values
229   - * #2 Get the client model with current values. Analyze the response in -> lwM2MTransportRequest.sendResponse
230   - *
231   - * @param lwServer - LeshanServer
232   - * @param registration - Registration LwM2M Client
233   - * @param lwM2MClient - object with All parameters off client
234   - */
235   - private void setLwM2MClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) {
236   - // #1
237   - Arrays.stream(registration.getObjectLinks()).forEach(url -> {
238   - ResultIds pathIds = new ResultIds(url.getUrl());
239   - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) {
240   - lwM2MClient.getPendingRequests().add(url.getUrl());
241   - }
242   - });
243   - // #2
244   - Arrays.stream(registration.getObjectLinks()).forEach(url -> {
245   - ResultIds pathIds = new ResultIds(url.getUrl());
246   - if (pathIds.instanceId > -1 && pathIds.resourceId == -1) {
247   - lwM2MTransportRequest.sendAllRequest(lwServer, registration, url.getUrl(), GET_TYPE_OPER_READ,
248   - ContentFormat.TLV.getName(), lwM2MClient, null, null, this.context.getCtxServer().getTimeout());
249   - }
250   - });
251   - }
252   -
253   - /**
254   - * @param registrationId - Id of Registration LwM2M Client
255   - * @return - sessionInfo after access connect client
256   - */
257   - private SessionInfoProto getValidateSessionInfo(String registrationId) {
258   - SessionInfoProto sessionInfo = null;
259   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registrationId);
260   - if (lwM2MClient != null) {
261   - ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse();
262   - if (msg == null || msg.getDeviceInfo() == null) {
263   - log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED);
264   - this.closeClientSession(lwM2MClient.getRegistration());
265   - } else {
266   - sessionInfo = SessionInfoProto.newBuilder()
267   - .setNodeId(this.context.getNodeId())
268   - .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits())
269   - .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits())
270   - .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB())
271   - .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB())
272   - .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB())
273   - .setTenantIdLSB(msg.getDeviceInfo().getTenantIdLSB())
274   - .setDeviceName(msg.getDeviceInfo().getDeviceName())
275   - .setDeviceType(msg.getDeviceInfo().getDeviceType())
276   - .setDeviceProfileIdLSB(msg.getDeviceInfo().getDeviceProfileIdLSB())
277   - .setDeviceProfileIdMSB(msg.getDeviceInfo().getDeviceProfileIdMSB())
278   - .build();
279   - }
280   - }
281   - return sessionInfo;
282   - }
283   -
284   - /**
285   - * Add attribute/telemetry information from Client and credentials/Profile to client model and start observe
286   - * !!! if the resource has an observation, but no telemetry or attribute - the observation will not use
287   - * #1 Client`s starting info to send to thingsboard
288   - * #2 Sending Attribute Telemetry with value to thingsboard only once at the start of the connection
289   - * #3 Start observe
290   - *
291   - * @param lwServer - LeshanServer
292   - * @param registration - Registration LwM2M Client
293   - */
294   -
295   - public void updatesAndSentModelParameter(LeshanServer lwServer, Registration registration) {
296   - // #1
297   -// this.setParametersToModelClient(registration, modelClient, deviceProfile);
298   - // #2
299   - this.updateAttrTelemetry(registration, true, null);
300   - // #3
301   - this.onSentObserveToClient(lwServer, registration);
302   - }
303   -
304   -
305   - /**
306   - * Sent Attribute and Telemetry to Thingsboard
307   - * #1 - get AttrName/TelemetryName with value:
308   - * #1.1 from Client
309   - * #1.2 from LwM2MClient:
310   - * -- resourceId == path from AttrTelemetryObserveValue.postAttributeProfile/postTelemetryProfile/postObserveProfile
311   - * -- AttrName/TelemetryName == resourceName from ModelObject.objectModel, value from ModelObject.instance.resource(resourceId)
312   - * #2 - set Attribute/Telemetry
313   - *
314   - * @param registration - Registration LwM2M Client
315   - */
316   - private void updateAttrTelemetry(Registration registration, boolean start, Set<String> paths) {
317   - JsonObject attributes = new JsonObject();
318   - JsonObject telemetrys = new JsonObject();
319   - if (start) {
320   - // #1.1
321   - JsonObject attributeClient = this.getAttributeClient(registration);
322   - if (attributeClient != null) {
323   - attributeClient.entrySet().forEach(p -> {
324   - attributes.add(p.getKey(), p.getValue());
325   - });
326   - }
327   - }
328   - // #1.2
329   - CountDownLatch cancelLatch = new CountDownLatch(1);
330   - this.getParametersFromProfile(attributes, telemetrys, registration, paths);
331   - cancelLatch.countDown();
332   - try {
333   - cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
334   - } catch (InterruptedException e) {
335   - log.error("[{}] updateAttrTelemetry", e.toString());
336   - }
337   - if (attributes.getAsJsonObject().entrySet().size() > 0)
338   - this.updateParametersOnThingsboard(attributes, DEVICE_ATTRIBUTES_TOPIC, registration.getId());
339   - if (telemetrys.getAsJsonObject().entrySet().size() > 0)
340   - this.updateParametersOnThingsboard(telemetrys, DEVICE_TELEMETRY_TOPIC, registration.getId());
341   - }
342   -
343   - /**
344   - * get AttrName/TelemetryName with value from Client
345   - *
346   - * @param registration -
347   - * @return - JsonObject, format: {name: value}}
348   - */
349   - private JsonObject getAttributeClient(Registration registration) {
350   - if (registration.getAdditionalRegistrationAttributes().size() > 0) {
351   - JsonObject resNameValues = new JsonObject();
352   - registration.getAdditionalRegistrationAttributes().entrySet().forEach(entry -> {
353   - resNameValues.addProperty(entry.getKey(), entry.getValue());
354   - });
355   - return resNameValues;
356   - }
357   - return null;
358   - }
359   -
360   - /**
361   - * @param attributes - new JsonObject
362   - * @param telemetry - new JsonObject
363   - * @param registration - Registration LwM2M Client
364   - * result: add to JsonObject those resources to which the user is subscribed and they have a value
365   - * if path==null add All resources else only one
366   - * (attributes/telemetry): new {name(Attr/Telemetry):value}
367   - */
368   - private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set<String> path) {
369   - AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid());
370   - attrTelemetryObserveValue.getPostAttributeProfile().forEach(p -> {
371   - ResultIds pathIds = new ResultIds(p.getAsString().toString());
372   - if (pathIds.getResourceId() > -1) {
373   - if (path == null || path.contains(p.getAsString())) {
374   - this.addParameters(pathIds, p.getAsString().toString(), attributes, registration);
375   - }
376   - }
377   - });
378   - attrTelemetryObserveValue.getPostTelemetryProfile().forEach(p -> {
379   - ResultIds pathIds = new ResultIds(p.getAsString().toString());
380   - if (pathIds.getResourceId() > -1) {
381   - if (path == null || path.contains(p.getAsString())) {
382   - this.addParameters(pathIds, p.getAsString().toString(), telemetry, registration);
383   - }
384   - }
385   - });
386   - }
387   -
388   - /**
389   - * @param pathIds - path resource
390   - * @param parameters - JsonObject attributes/telemetry
391   - * @param registration - Registration LwM2M Client
392   - */
393   - private void addParameters(ResultIds pathIds, String path, JsonObject parameters, Registration registration) {
394   - ModelObject modelObject = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getModelObjects().get(pathIds.getObjectId());
395   - JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid()).getPostKeyNameProfile();
396   - String resName = String.valueOf(names.get(path));
397   - if (modelObject != null && resName != null && !resName.isEmpty()) {
398   - String resValue = this.getResourceValue(modelObject, pathIds);
399   - if (resValue != null) {
400   - parameters.addProperty(resName, resValue);
401   - }
402   - }
403   - }
404   -
405   - /**
406   - * @param modelObject - ModelObject of Client
407   - * @param pathIds - path resource
408   - * @return - value of Resource or null
409   - */
410   - private String getResourceValue(ModelObject modelObject, ResultIds pathIds) {
411   - String resValue = null;
412   - if (modelObject.getInstances().get(pathIds.getInstanceId()) != null) {
413   - LwM2mObjectInstance instance = modelObject.getInstances().get(pathIds.getInstanceId());
414   - if (instance.getResource(pathIds.getResourceId()) != null) {
415   - resValue = instance.getResource(pathIds.getResourceId()).getType() == OPAQUE ?
416   - Hex.encodeHexString((byte[]) instance.getResource(pathIds.getResourceId()).getValue()).toLowerCase() :
417   - (instance.getResource(pathIds.getResourceId()).isMultiInstances()) ?
418   - instance.getResource(pathIds.getResourceId()).getValues().toString() :
419   - instance.getResource(pathIds.getResourceId()).getValue().toString();
420   - }
421   - }
422   - return resValue;
423   - }
424   -
425   - /**
426   - * Prepare Sent to Thigsboard callback - Attribute or Telemetry
427   - *
428   - * @param msg - JsonArray: [{name: value}]
429   - * @param topicName - Api Attribute or Telemetry
430   - * @param registrationId - Id of Registration LwM2M Client
431   - */
432   - public void updateParametersOnThingsboard(JsonElement msg, String topicName, String registrationId) {
433   - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId);
434   - if (sessionInfo != null) {
435   - try {
436   - if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) {
437   - PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg);
438   - TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postAttributeMsg);
439   - transportService.process(sessionInfo, postAttributeMsg, call);
440   - } else if (topicName.equals(LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC)) {
441   - PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg);
442   - TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(-1, postTelemetryMsg);
443   - transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(-1, call));
444   - }
445   - } catch (AdaptorException e) {
446   - log.error("[{}] Failed to process publish msg [{}]", topicName, e);
447   - log.info("[{}] Closing current session due to invalid publish", topicName);
448   - }
449   - } else {
450   - log.error("Client: [{}] updateParametersOnThingsboard [{}] sessionInfo ", registrationId, sessionInfo);
451   - }
452   - }
453   -
454   - /**
455   - * Sent to Thingsboard Attribute || Telemetry
456   - *
457   - * @param msgId - always == -1
458   - * @param msg - JsonObject: [{name: value}]
459   - * @return - dummy
460   - */
461   - private <T> TransportServiceCallback<Void> getPubAckCallbackSentAttrTelemetry(final int msgId, final T msg) {
462   - return new TransportServiceCallback<Void>() {
463   - @Override
464   - public void onSuccess(Void dummy) {
465   - log.trace("Success to publish msg: {}, dummy: {}", msg, dummy);
466   - }
467   -
468   - @Override
469   - public void onError(Throwable e) {
470   - log.trace("[{}] Failed to publish msg: {}", msg, e);
471   - }
472   - };
473   - }
474   -
475   -
476   - /**
477   - * Start observe
478   - * #1 - Analyze:
479   - * #1.1 path in observe == (attribute or telemetry)
480   - * #1.2 recourseValue notNull
481   - * #2 Analyze after sent request (response):
482   - * #2.1 First: lwM2MTransportRequest.sendResponse -> ObservationListener.newObservation
483   - * #2.2 Next: ObservationListener.onResponse *
484   - *
485   - * @param lwServer - LeshanServer
486   - * @param registration - Registration LwM2M Client
487   - */
488   - private void onSentObserveToClient(LeshanServer lwServer, Registration registration) {
489   - if (lwServer.getObservationService().getObservations(registration).size() > 0) {
490   - this.setCancelObservations(lwServer, registration);
491   - }
492   - UUID profileUUid = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getProfileUuid();
493   - AttrTelemetryObserveValue attrTelemetryObserveValue = lwM2mInMemorySecurityStore.getProfiles().get(profileUUid);
494   - attrTelemetryObserveValue.getPostObserveProfile().forEach(p -> {
495   - // #1.1
496   - String target = (getValidateObserve(attrTelemetryObserveValue.getPostAttributeProfile(), p.getAsString().toString())) ?
497   - p.getAsString().toString() : (getValidateObserve(attrTelemetryObserveValue.getPostTelemetryProfile(), p.getAsString().toString())) ?
498   - p.getAsString().toString() : null;
499   - if (target != null) {
500   - // #1.2
501   - ResultIds pathIds = new ResultIds(target);
502   - ModelObject modelObject = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()).getModelObjects().get(pathIds.getObjectId());
503   - // #2
504   - if (modelObject != null) {
505   - if (getResourceValue(modelObject, pathIds) != null) {
506   - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, GET_TYPE_OPER_OBSERVE,
507   - null, null, null, null, this.context.getCtxServer().getTimeout());
508   - }
509   - }
510   - }
511   - });
512   - }
513   -
514   - public void setCancelObservations(LeshanServer lwServer, Registration registration) {
515   - if (registration != null) {
516   - Set<Observation> observations = lwServer.getObservationService().getObservations(registration);
517   - observations.forEach(observation -> {
518   - this.setCancelObservationRecourse(lwServer, registration, observation.getPath().toString());
519   - });
520   - }
521   - }
522   -
523   - /**
524   - * lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_OBSERVE_CANCEL, null, null, null, null, context.getTimeout());
525   - * At server side this will not remove the observation from the observation store, to do it you need to use
526   - * {@code ObservationService#cancelObservation()}
527   - */
528   - public void setCancelObservationRecourse(LeshanServer lwServer, Registration registration, String path) {
529   - CountDownLatch cancelLatch = new CountDownLatch(1);
530   - lwServer.getObservationService().cancelObservations(registration, path);
531   - cancelLatch.countDown();
532   - try {
533   - cancelLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
534   - } catch (InterruptedException e) {
535   - }
536   - }
537   -
538   - /**
539   - * @param parameters - JsonArray postAttributeProfile/postTelemetryProfile
540   - * @param path - recourse from postObserveProfile
541   - * @return rez - true if path observe is in attribute/telemetry
542   - */
543   - private boolean getValidateObserve(JsonElement parameters, String path) {
544   - AtomicBoolean rez = new AtomicBoolean(false);
545   - if (parameters.isJsonArray()) {
546   - parameters.getAsJsonArray().forEach(p -> {
547   - if (p.getAsString().toString().equals(path)) rez.set(true);
548   - }
549   - );
550   - } else if (parameters.isJsonObject()) {
551   - rez.set((parameters.getAsJsonObject().entrySet()).stream().map(json -> json.toString())
552   - .filter(path::equals).findAny().orElse(null) != null);
553   - }
554   - return rez.get();
555   - }
556   -
557   - /**
558   - * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource
559   - *
560   - * @param registration - Registration LwM2M Client
561   - * @param path - observe
562   - * @param response - observe
563   - */
564   - @SneakyThrows
565   - public void onObservationResponse(Registration registration, String path, ReadResponse response) {
566   - if (response.getContent() != null) {
567   - if (response.getContent() instanceof LwM2mObject) {
568   - LwM2mObject content = (LwM2mObject) response.getContent();
569   - String target = "/" + content.getId();
570   - } else if (response.getContent() instanceof LwM2mObjectInstance) {
571   - LwM2mObjectInstance content = (LwM2mObjectInstance) response.getContent();
572   - } else if (response.getContent() instanceof LwM2mSingleResource) {
573   - LwM2mSingleResource content = (LwM2mSingleResource) response.getContent();
574   - this.onObservationSetResourcesValue(registration, content.getValue(), null, path);
575   - } else if (response.getContent() instanceof LwM2mMultipleResource) {
576   - LwM2mSingleResource content = (LwM2mSingleResource) response.getContent();
577   - this.onObservationSetResourcesValue(registration, null, content.getValues(), path);
578   - }
579   - }
580   - }
581   -
582   - /**
583   - * Sending observe value of resources to thingsboard
584   - * #1 Return old Resource from ModelObject
585   - * #2 Create new Resource with value from observation
586   - * #3 Create new Resources from old Resources
587   - * #4 Update new Resources (replace old Resource on new Resource)
588   - * #5 Remove old Instance from modelClient
589   - * #6 Create new Instance with new Resources values
590   - * #7 Update modelClient.getModelObjects(idObject) (replace old Instance on new Instance)
591   - *
592   - * @param registration - Registration LwM2M Client
593   - * @param value - LwM2mSingleResource response.getContent()
594   - * @param values - LwM2mSingleResource response.getContent()
595   - * @param path - resource
596   - */
597   - private void onObservationSetResourcesValue(Registration registration, Object value, Map<Integer, ?> values, String path) {
598   - ResultIds resultIds = new ResultIds(path);
599   - // #1
600   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId());
601   - ModelObject modelObject = lwM2MClient.getModelObjects().get(resultIds.getObjectId());
602   - Map<Integer, LwM2mObjectInstance> instancesModelObject = modelObject.getInstances();
603   - LwM2mObjectInstance instanceOld = (instancesModelObject.get(resultIds.instanceId) != null) ? instancesModelObject.get(resultIds.instanceId) : null;
604   - Map<Integer, LwM2mResource> resourcesOld = (instanceOld != null) ? instanceOld.getResources() : null;
605   - LwM2mResource resourceOld = (resourcesOld != null && resourcesOld.get(resultIds.getResourceId()) != null) ? resourcesOld.get(resultIds.getResourceId()) : null;
606   - // #2
607   - LwM2mResource resourceNew;
608   - if (resourceOld.isMultiInstances()) {
609   - resourceNew = LwM2mMultipleResource.newResource(resultIds.getResourceId(), values, resourceOld.getType());
610   - } else {
611   - resourceNew = LwM2mSingleResource.newResource(resultIds.getResourceId(), value, resourceOld.getType());
612   - }
613   - //#3
614   - Map<Integer, LwM2mResource> resourcesNew = new HashMap<>(resourcesOld);
615   - // #4
616   - resourcesNew.remove(resourceOld);
617   - // #5
618   - resourcesNew.put(resultIds.getResourceId(), resourceNew);
619   - // #6
620   - LwM2mObjectInstance instanceNew = new LwM2mObjectInstance(resultIds.instanceId, resourcesNew.values());
621   - // #7
622   - CountDownLatch respLatch = new CountDownLatch(1);
623   - lwM2MClient.getModelObjects().get(resultIds.getObjectId()).removeInstance(resultIds.instanceId);
624   - instancesModelObject.put(resultIds.instanceId, instanceNew);
625   - respLatch.countDown();
626   - try {
627   - respLatch.await(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
628   - } catch (InterruptedException ex) {
629   - }
630   - Set<String> paths = new HashSet<String>();
631   - paths.add(path);
632   - this.updateAttrTelemetry(registration, false, paths);
633   - }
634   -
635   - /**
636   - * @param updateCredentials - Credentials include config only security Client (without config attr/telemetry...)
637   - * config attr/telemetry... in profile
638   - */
639   - public void onToTransportUpdateCredentials(ToTransportUpdateCredentialsProto updateCredentials) {
640   - log.info("[{}] idList [{}] valueList updateCredentials", updateCredentials.getCredentialsIdList(), updateCredentials.getCredentialsValueList());
641   - }
642   -
643   - /**
644   - * Update - sent request in change value resources in Client (path to resources from profile by keyName)
645   - * Only fo resources W
646   - * Delete - nothing
647   - *
648   - * @param msg -
649   - * @param sessionInfo -
650   - */
651   - public void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, SessionInfoProto sessionInfo) {
652   - if (msg.getSharedUpdatedCount() > 0) {
653   - JsonElement el = JsonConverter.toJson(msg);
654   - el.getAsJsonObject().entrySet().forEach(de -> {
655   - String profilePath = lwM2mInMemorySecurityStore.getProfiles().get(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()))
656   - .getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
657   - .filter(e -> e.getValue().getAsString().equals(de.getKey())).findFirst().map(Map.Entry::getKey)
658   - .orElse("");
659   - String path = !profilePath.isEmpty() ? profilePath : this.getPathAttributeUpdate(sessionInfo, de.getKey());
660   - if (path != null) {
661   - ResultIds resultIds = new ResultIds(path);
662   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue();
663   - ResourceModel.Operations operations = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getObjectModel().resources.get(resultIds.getResourceId()).operations;
664   - String value = ((JsonPrimitive) de.getValue()).getAsString();
665   - if (operations.isWritable()) {
666   - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE,
667   - ContentFormat.TLV.getName(), lwM2MClient, null, value, this.context.getCtxServer().getTimeout());
668   - log.info("[{}] path onAttributeUpdate", path);
669   - }
670   - else {
671   - log.error(LOG_LW2M_ERROR + ": Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value);
672   - String logMsg = String.format(LOG_LW2M_ERROR + " attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", path, value);
673   - this.sentLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
674   - }
675   - }
676   - });
677   - } else if (msg.getSharedDeletedCount() > 0) {
678   - log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
679   - }
680   - }
681   -
682   - private String getPathAttributeUpdate(SessionInfoProto sessionInfo, String keyName) {
683   - try {
684   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue();
685   - Predicate<Map.Entry<Integer, ResourceModel>> predicateRes = res -> keyName.equals(splitCamelCaseString(res.getValue().name));
686   - Predicate<Map.Entry<Integer, ModelObject>> predicateObj = (obj -> {
687   - return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateRes).findFirst().isPresent();
688   - });
689   - Stream<Map.Entry<Integer, ModelObject>> objectStream = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObj);
690   - Predicate<Map.Entry<Integer, ResourceModel>> predicateResFinal = (objectStream.count() > 0) ? predicateRes : res -> keyName.equals(res.getValue().name);
691   - Predicate<Map.Entry<Integer, ModelObject>> predicateObjFinal = (obj -> {
692   - return obj.getValue().getObjectModel().resources.entrySet().stream().filter(predicateResFinal).findFirst().isPresent();
693   - });
694   - Map.Entry<Integer, ModelObject> object = lwM2MClient.getModelObjects().entrySet().stream().filter(predicateObjFinal).findFirst().get();
695   - ModelObject modelObject = object.getValue();
696   - LwM2mObjectInstance instance = modelObject.getInstances().entrySet().stream().findFirst().get().getValue();
697   - ResourceModel resource = modelObject.getObjectModel().resources.entrySet().stream().filter(predicateResFinal).findFirst().get().getValue();
698   - return new LwM2mPath(object.getKey(), instance.getId(), resource.id).toString();
699   - } catch (NoSuchElementException e) {
700   - log.error("[{}] keyName [{}]", keyName, e.toString());
701   - return null;
702   - }
703   - }
704   -
705   - public void onAttributeUpdateOk(Registration registration, String path, WriteRequest request) {
706   - ResultIds resultIds = new ResultIds(path);
707   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId());
708   - LwM2mResource resource = lwM2MClient.getModelObjects().get(resultIds.getObjectId()).getInstances().get(resultIds.getInstanceId()).getResource(resultIds.getResourceId());
709   - if (resource.isMultiInstances()) {
710   - this.onObservationSetResourcesValue(registration, null, ((LwM2mSingleResource) request.getNode()).getValues(), path);
711   - } else {
712   - this.onObservationSetResourcesValue(registration, ((LwM2mSingleResource) request.getNode()).getValue(), null, path);
713   - }
714   - }
715   -
716   - /**
717   - * @param sessionInfo -
718   - * @param deviceProfile -
719   - */
720   - public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
721   - String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet()
722   - .stream()
723   - .filter(e -> e.getValue().getDeviceUuid().equals(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())))
724   - .findFirst()
725   - .map(Map.Entry::getKey)
726   - .orElse("");
727   - if (!registrationId.isEmpty()) {
728   - this.onDeviceUpdateChangeProfile(registrationId, deviceProfile);
729   - }
730   - }
731   -
732   - /**
733   - * @param sessionInfo -
734   - * @param device -
735   - * @param deviceProfileOpt -
736   - */
737   - public void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, Optional<DeviceProfile> deviceProfileOpt) {
738   - Optional<String> registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream()
739   - .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid()))
740   - .map(Map.Entry::getKey)
741   - .findFirst();
742   - registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt));
743   - }
744   -
745   - /**
746   - * Update parameters device in LwM2MClient
747   - * If new deviceProfile != old deviceProfile => update deviceProfile
748   - *
749   - * @param registrationId -
750   - * @param device -
751   - */
752   - private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional<DeviceProfile> deviceProfileOpt) {
753   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId);
754   - lwM2MClient.setDeviceName(device.getName());
755   - if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) {
756   - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationId, deviceProfile));
757   - }
758   - }
759   -
760   - /**
761   - * #1 Read new, old Value (Attribute, Telemetry, Observe, KeyName)
762   - * #2 Update in lwM2MClient: ...Profile
763   - * #3 Equivalence test: old <> new Value (Attribute, Telemetry, Observe, KeyName)
764   - * #3.1 Attribute isChange (add&del)
765   - * #3.2 Telemetry isChange (add&del)
766   - * #3.3 KeyName isChange (add)
767   - * #4 update
768   - * #4.1 add If #3 isChange, then analyze and update Value in Transport form Client and sent Value ti thingsboard
769   - * #4.2 del
770   - * -- if add attributes includes del telemetry - result del for observe
771   - * #5
772   - * #5.1 Observe isChange (add&del)
773   - * #5.2 Observe.add
774   - * -- path Attr/Telemetry includes newObserve and does not include oldObserve: sent Request observe to Client
775   - * #5.3 Observe.del
776   - * -- different between newObserve and oldObserve: sent Request cancel observe to client
777   - *
778   - * @param registrationId -
779   - * @param deviceProfile -
780   - */
781   - public void onDeviceUpdateChangeProfile(String registrationId, DeviceProfile deviceProfile) {
782   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registrationId);
783   - AttrTelemetryObserveValue attrTelemetryObserveValueOld = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid());
784   - if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) {
785   - LeshanServer lwServer = lwM2MClient.getLwServer();
786   - Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId);
787   - // #1
788   - JsonArray attributeOld = attrTelemetryObserveValueOld.getPostAttributeProfile();
789   - Set<String> attributeSetOld = new Gson().fromJson(attributeOld, Set.class);
790   - JsonArray telemetryOld = attrTelemetryObserveValueOld.getPostTelemetryProfile();
791   - Set<String> telemetrySetOld = new Gson().fromJson(telemetryOld, Set.class);
792   - JsonArray observeOld = attrTelemetryObserveValueOld.getPostObserveProfile();
793   - JsonObject keyNameOld = attrTelemetryObserveValueOld.getPostKeyNameProfile();
794   -
795   - AttrTelemetryObserveValue attrTelemetryObserveValueNew = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId());
796   - JsonArray attributeNew = attrTelemetryObserveValueNew.getPostAttributeProfile();
797   - Set<String> attributeSetNew = new Gson().fromJson(attributeNew, Set.class);
798   - JsonArray telemetryNew = attrTelemetryObserveValueNew.getPostTelemetryProfile();
799   - Set<String> telemetrySetNew = new Gson().fromJson(telemetryNew, Set.class);
800   - JsonArray observeNew = attrTelemetryObserveValueNew.getPostObserveProfile();
801   - JsonObject keyNameNew = attrTelemetryObserveValueNew.getPostKeyNameProfile();
802   - // #2
803   - lwM2MClient.setDeviceProfileName(deviceProfile.getName());
804   - lwM2MClient.setProfileUuid(deviceProfile.getUuidId());
805   -
806   - // #3
807   - ResultsAnalyzerParameters sentAttrToThingsboard = new ResultsAnalyzerParameters();
808   - // #3.1
809   - if (!attributeOld.equals(attributeNew)) {
810   - ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, Set.class), attributeSetNew);
811   - sentAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd());
812   - sentAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel());
813   - }
814   - // #3.2
815   - if (!attributeOld.equals(attributeNew)) {
816   - ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, Set.class), telemetrySetNew);
817   - sentAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd());
818   - sentAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel());
819   - }
820   - // #3.3
821   - if (!keyNameOld.equals(keyNameNew)) {
822   - ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), ConcurrentHashMap.class),
823   - new Gson().fromJson(keyNameNew.toString(), ConcurrentHashMap.class));
824   - sentAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd());
825   - }
826   -
827   - // #4.1 add
828   - if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) {
829   - // update value in Resources
830   - this.updateResourceValueObserve(lwServer, registration, lwM2MClient, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ);
831   - // sent attr/telemetry to tingsboard for new path
832   - this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd());
833   - }
834   - // #4.2 del
835   - if (sentAttrToThingsboard.getPathPostParametersDel().size() > 0) {
836   - ResultsAnalyzerParameters sentAttrToThingsboardDel = this.getAnalyzerParameters(sentAttrToThingsboard.getPathPostParametersAdd(), sentAttrToThingsboard.getPathPostParametersDel());
837   - sentAttrToThingsboard.setPathPostParametersDel(sentAttrToThingsboardDel.getPathPostParametersDel());
838   - }
839   -
840   - // #5.1
841   - if (!observeOld.equals(observeNew)) {
842   - Set<String> observeSetOld = new Gson().fromJson(observeOld, Set.class);
843   - Set<String> observeSetNew = new Gson().fromJson(observeNew, Set.class);
844   - //#5.2 add
845   - // path Attr/Telemetry includes newObserve
846   - attributeSetOld.addAll(telemetrySetOld);
847   - ResultsAnalyzerParameters sentObserveToClientOld = this.getAnalyzerParametersIn(attributeSetOld, observeSetOld); // add observe
848   - attributeSetNew.addAll(telemetrySetNew);
849   - ResultsAnalyzerParameters sentObserveToClientNew = this.getAnalyzerParametersIn(attributeSetNew, observeSetNew); // add observe
850   - // does not include oldObserve
851   - ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd());
852   - // sent Request observe to Client
853   - this.updateResourceValueObserve(lwServer, registration, lwM2MClient, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE);
854   - // 5.3 del
855   - // sent Request cancel observe to Client
856   - this.cancelObserveIsValue(lwServer, registration, postObserveAnalyzer.getPathPostParametersDel());
857   - }
858   - }
859   - }
860   -
861   - /**
862   - * Compare old list with new list after change AttrTelemetryObserve in config Profile
863   - *
864   - * @param parametersOld -
865   - * @param parametersNew -
866   - * @return ResultsAnalyzerParameters: add && new
867   - */
868   - private ResultsAnalyzerParameters getAnalyzerParameters(Set<String> parametersOld, Set<String> parametersNew) {
869   - ResultsAnalyzerParameters analyzerParameters = null;
870   - if (!parametersOld.equals(parametersNew)) {
871   - analyzerParameters = new ResultsAnalyzerParameters();
872   - analyzerParameters.setPathPostParametersAdd(parametersNew
873   - .stream().filter(p -> !parametersOld.contains(p)).collect(Collectors.toSet()));
874   - analyzerParameters.setPathPostParametersDel(parametersOld
875   - .stream().filter(p -> !parametersNew.contains(p)).collect(Collectors.toSet()));
876   - }
877   - return analyzerParameters;
878   - }
879   -
880   - private ResultsAnalyzerParameters getAnalyzerKeyName(ConcurrentMap<String, String> keyNameOld, ConcurrentMap<String, String> keyNameNew) {
881   - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
882   - Set<String> paths = keyNameNew.entrySet()
883   - .stream()
884   - .filter(e -> !e.getValue().equals(keyNameOld.get(e.getKey())))
885   - .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())).keySet();
886   - analyzerParameters.setPathPostParametersAdd(paths);
887   - return analyzerParameters;
888   - }
889   -
890   - private ResultsAnalyzerParameters getAnalyzerParametersIn(Set<String> parametersObserve, Set<String> parameters) {
891   - ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
892   - analyzerParameters.setPathPostParametersAdd(parametersObserve
893   - .stream().filter(p -> parameters.contains(p)).collect(Collectors.toSet()));
894   - return analyzerParameters;
895   - }
896   -
897   - /**
898   - * Update Resource value after change RezAttrTelemetry in config Profile
899   - * sent response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue()
900   - *
901   - * @param lwServer - LeshanServer
902   - * @param registration - Registration LwM2M Client
903   - * @param lwM2MClient - object with All parameters off client
904   - * @param targets - path Resources == [ "/2/0/0", "/2/0/1"]
905   - */
906   - private void updateResourceValueObserve(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, Set<String> targets, String typeOper) {
907   - targets.stream().forEach(target -> {
908   - ResultIds pathIds = new ResultIds(target);
909   - if (pathIds.resourceId >= 0 && lwM2MClient.getModelObjects().get(pathIds.getObjectId())
910   - .getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId()).getValue() != null) {
911   - if (GET_TYPE_OPER_READ.equals(typeOper)) {
912   - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper,
913   - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout());
914   - } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) {
915   - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper,
916   - null, null, null, null, this.context.getCtxServer().getTimeout());
917   - }
918   - }
919   - });
920   - }
921   -
922   - private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set<String> paramAnallyzer) {
923   - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getlwM2MClient(registration.getId());
924   - paramAnallyzer.forEach(p -> {
925   - if (this.getResourceValue(lwM2MClient, p) != null) {
926   - this.setCancelObservationRecourse(lwServer, registration, p);
927   - }
928   - }
929   - );
930   - }
931   -
932   - private ResourceValue getResourceValue(LwM2MClient lwM2MClient, String path) {
933   - ResourceValue resourceValue = null;
934   - ResultIds pathIds = new ResultIds(path);
935   - if (pathIds.getResourceId() > -1) {
936   - LwM2mResource resource = lwM2MClient.getModelObjects().get(pathIds.getObjectId()).getInstances().get(pathIds.getInstanceId()).getResource(pathIds.getResourceId());
937   - if (resource.isMultiInstances()) {
938   - Map<Integer, ?> values = resource.getValues();
939   - if (resource.getValues().size() > 0) {
940   - resourceValue = new ResourceValue();
941   - resourceValue.setMultiInstances(resource.isMultiInstances());
942   - resourceValue.setValues(resource.getValues());
943   - }
944   - } else {
945   - if (resource.getValue() != null) {
946   - resourceValue = new ResourceValue();
947   - resourceValue.setMultiInstances(resource.isMultiInstances());
948   - resourceValue.setValue(resource.getValue());
949   - }
950   - }
951   - }
952   - return resourceValue;
953   - }
954   -
955   - /**
956   - * Trigger Server path = "/1/0/8"
957   - *
958   - * Trigger bootStrap path = "/1/0/9" - have to implemented on client
959   - */
960   - public void doTrigger(LeshanServer lwServer, Registration registration, String path) {
961   - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE,
962   - ContentFormat.TLV.getName(), null, null, null, this.context.getCtxServer().getTimeout());
963   - }
964   -
965   - /**
966   - * Session device in thingsboard is closed
967   - *
968   - * @param sessionInfo - lwm2m client
969   - */
970   - private void doCloseSession(SessionInfoProto sessionInfo) {
971   - TransportProtos.SessionEvent event = SessionEvent.CLOSED;
972   - TransportProtos.SessionEventMsg msg = TransportProtos.SessionEventMsg.newBuilder()
973   - .setSessionType(TransportProtos.SessionType.ASYNC)
974   - .setEvent(event).build();
975   - transportService.process(sessionInfo, msg, null);
976   - }
977   -
978   - /**
979   - * Deregister session in transport
980   - * @param sessionInfo - lwm2m client
981   - */
982   - private void doDisconnect(SessionInfoProto sessionInfo) {
983   - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null);
984   - transportService.deregisterSession(sessionInfo);
985   - }
986   -
987   - private void checkInactivityAndReportActivity() {
988   - lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> transportService.reportActivity(this.getValidateSessionInfo(key)));
989   - }
990   -
991   - public void sentLogsToThingsboard(String msg, String registrationId) {
992   - if (msg != null) {
993   - JsonObject telemetrys = new JsonObject();
994   - telemetrys.addProperty(LOG_LW2M_TELEMETRY, msg);
995   - this.updateParametersOnThingsboard(telemetrys, LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, registrationId);
996   - }
997   - }
998   -
999   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import lombok.extern.slf4j.Slf4j;
19   -import org.eclipse.leshan.core.observation.Observation;
20   -import org.eclipse.leshan.core.response.ObserveResponse;
21   -import org.eclipse.leshan.server.californium.LeshanServer;
22   -import org.eclipse.leshan.server.observation.ObservationListener;
23   -import org.eclipse.leshan.server.queue.PresenceListener;
24   -import org.eclipse.leshan.server.registration.Registration;
25   -import org.eclipse.leshan.server.registration.RegistrationListener;
26   -import org.eclipse.leshan.server.registration.RegistrationUpdate;
27   -
28   -import java.util.Collection;
29   -
30   -@Slf4j
31   -public class LwM2mServerListener {
32   - private LeshanServer lhServer;
33   - private LwM2MTransportService service;
34   -
35   - public LwM2mServerListener(LeshanServer lhServer, LwM2MTransportService service) {
36   - this.lhServer = lhServer;
37   - this.service = service;
38   - }
39   -
40   - public final RegistrationListener registrationListener = new RegistrationListener() {
41   - /**
42   - * Register – запрос, представленный в виде POST /rd?…
43   - */
44   - @Override
45   - public void registered(Registration registration, Registration previousReg,
46   - Collection<Observation> previousObsersations) {
47   -
48   - service.onRegistered(lhServer, registration, previousObsersations);
49   - }
50   -
51   - /**
52   - * Update – представляет из себя CoAP POST запрос на URL, полученный в ответ на Register.
53   - */
54   - @Override
55   - public void updated(RegistrationUpdate update, Registration updatedRegistration,
56   - Registration previousRegistration) {
57   - service.updatedReg(lhServer, updatedRegistration);
58   - }
59   -
60   - /**
61   - * De-register (CoAP DELETE) – отправляется клиентом в случае инициирования процедуры выключения.
62   - */
63   - @Override
64   - public void unregistered(Registration registration, Collection<Observation> observations, boolean expired,
65   - Registration newReg) {
66   - service.unReg(registration, observations);
67   - }
68   -
69   - };
70   -
71   - public final PresenceListener presenceListener = new PresenceListener() {
72   - @Override
73   - public void onSleeping(Registration registration) {
74   - service.onSleepingDev(registration);
75   - }
76   -
77   - @Override
78   - public void onAwake(Registration registration) {
79   - service.onAwakeDev(registration);
80   - }
81   - };
82   -
83   - public final ObservationListener observationListener = new ObservationListener() {
84   -
85   - @Override
86   - public void cancelled(Observation observation) {
87   - log.info("Received notification cancelled from [{}] ", observation.getPath());
88   - }
89   -
90   - @Override
91   - public void onResponse(Observation observation, Registration registration, ObserveResponse response) {
92   - if (registration != null) {
93   - try {
94   - service.onObservationResponse(registration, observation.getPath().toString(), response);
95   - } catch (java.lang.NullPointerException e) {
96   - log.error(e.toString());
97   - }
98   - }
99   - }
100   -
101   - @Override
102   - public void onError(Observation observation, Registration registration, Exception error) {
103   - log.error(String.format("Unable to handle notification of [%s:%s]", observation.getRegistrationId(), observation.getPath()), error);
104   - }
105   -
106   - @Override
107   - public void newObservation(Observation observation, Registration registration) {
108   - log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint());
109   - }
110   - };
111   -}
1   -/**
2   - * Copyright © 2016-2020 The Thingsboard Authors
3   - *
4   - * Licensed under the Apache License, Version 2.0 (the "License");
5   - * you may not use this file except in compliance with the License.
6   - * You may obtain a copy of the License at
7   - *
8   - * http://www.apache.org/licenses/LICENSE-2.0
9   - *
10   - * Unless required by applicable law or agreed to in writing, software
11   - * distributed under the License is distributed on an "AS IS" BASIS,
12   - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   - * See the License for the specific language governing permissions and
14   - * limitations under the License.
15   - */
16   -package org.thingsboard.server.transport.lwm2m.server;
17   -
18   -import lombok.Builder;
19   -import lombok.Data;
20   -
21   -@Data
22   -public class ResultIds {
23   - @Builder.Default
24   - int objectId = -1;
25   - @Builder.Default
26   - int instanceId = -1;
27   - @Builder.Default
28   - int resourceId = -1;
29   -
30   - public ResultIds (String path) {
31   - String[] paths = path.split("/");
32   - if (paths != null && paths.length > 1) {
33   - this.objectId = (paths.length > 1) ? Integer.parseInt(paths[1]) : this.objectId;
34   - this.instanceId = (paths.length > 2) ? Integer.parseInt(paths[2]) : this.instanceId;
35   - this.resourceId = (paths.length > 3) ? Integer.parseInt(paths[3]) : this.resourceId;
36   - }
37   - }
38   -}