diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index b812c2f07e..95125b331a 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -452,6 +452,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { .setRequestId(requestId) .setSharedStateMsg(true) .addAllSharedAttributeList(toTsKvProtos(result)) + .setIsMultipleAttributesRequest(request.getSharedAttributeNamesCount() > 1) .build(); sendToTransport(responseMsg, sessionInfo); } @@ -473,6 +474,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { .setRequestId(requestId) .addAllClientAttributeList(toTsKvProtos(result.get(0))) .addAllSharedAttributeList(toTsKvProtos(result.get(1))) + .setIsMultipleAttributesRequest( + request.getSharedAttributeNamesCount() + request.getClientAttributeNamesCount() > 1) .build(); sendToTransport(responseMsg, sessionInfo); } diff --git a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java index 17fad5d750..86380ea57a 100644 --- a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java +++ b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java @@ -96,8 +96,7 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS } }); ruleEngineStats.getTenantExceptions().forEach((tenantId, e) -> { - TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry("ruleEngineException", - JacksonUtil.toString(JacksonUtil.newObjectNode().put("message", e.getMessage())))); + TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry("ruleEngineException", e.toJsonString())); try { tsService.saveAndNotifyInternal(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), CALLBACK); } catch (DataValidationException e2) { diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java index 6ffe4324a0..c4ce4e49b2 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java @@ -28,6 +28,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @Service public class EdgeEventsCleanUpService extends AbstractCleanUpService { + public static final String RANDOM_DELAY_INTERVAL_MS_EXPRESSION = + "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.edge_events.execution_interval_ms})}"; + @Value("${sql.ttl.edge_events.edge_events_ttl}") private long ttl; @@ -41,7 +44,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { this.edgeEventService = edgeEventService; } - @Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") + @Scheduled(initialDelayString = RANDOM_DELAY_INTERVAL_MS_EXPRESSION, fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") public void cleanUp() { if (ttlTaskExecutionEnabled && isSystemTenantPartitionMine()) { edgeEventService.cleanupEvents(ttl); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java index f44664c256..cc648d52d5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java @@ -52,6 +52,8 @@ import static org.junit.Assert.assertNotNull; @Slf4j public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest { + protected final byte[] EMPTY_PAYLOAD = new byte[0]; + protected CoapClient client; @Override diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java index d4dea4382a..3cf1884bc5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java @@ -25,15 +25,13 @@ import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.gen.transport.TransportProtos; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertTrue; @Slf4j @@ -88,7 +86,7 @@ public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends } protected void validateEmptyCurrentStateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException { - assertNull(callback.getPayloadBytes()); + assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes()); assertNotNull(callback.getObserve()); assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode()); assertEquals(0, callback.getObserve().intValue()); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java index 4ba151c857..d598a82ccb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java @@ -31,13 +31,12 @@ import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; -import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -186,7 +185,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC } private void validateCurrentStateNotification(TestCoapCallback callback) { - assertNull(callback.getPayloadBytes()); + assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes()); assertNotNull(callback.getObserve()); assertEquals(callback.getResponseCode(), CoAP.ResponseCode.VALID); assertEquals(0, callback.getObserve().intValue()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 44f9f3d52d..fd4c748f85 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.io.IOUtils; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.leshan.client.object.Security; import org.junit.After; import org.junit.Assert; @@ -174,7 +174,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest public void basicTestConnectionObserveTelemetry(Security security, LwM2MClientCredential credentials, - NetworkConfig coapConfig, + Configuration coapConfig, String endpoint) throws Exception { createDeviceProfile(TRANSPORT_CONFIGURATION); Device device = createDevice(credentials); @@ -259,7 +259,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.resources = resources; } - public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc, String endpoint) throws Exception { + public void createNewClient(Security security, Configuration coapConfig, boolean isRpc, String endpoint) throws Exception { clientDestroy(); client = new LwM2MTestClient(this.executor, endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 29771e1db8..2d10c50bc4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -15,9 +15,11 @@ */ package org.thingsboard.server.transport.lwm2m; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.leshan.client.object.Security; +import static org.eclipse.californium.core.config.CoapConfig.COAP_PORT; +import static org.eclipse.californium.core.config.CoapConfig.COAP_SECURE_PORT; import static org.eclipse.leshan.client.object.Security.noSec; public class Lwm2mTestHelper { @@ -32,10 +34,10 @@ public class Lwm2mTestHelper { public static final int SHORT_SERVER_ID = 123; public static final int SHORT_SERVER_ID_BS = 111; - public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); + public static final Configuration SECURE_COAP_CONFIG = new Configuration().set(COAP_SECURE_PORT, SECURE_PORT); public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT; public static final Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID); - public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); + public static final Configuration COAP_CONFIG = new Configuration().set(COAP_PORT, PORT); // Models public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"}; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index 2b9df30df9..81159e6584 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -131,10 +131,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { scheduler.schedule(() -> { try { state.set(1); - fireResourcesChange(3); + fireResourceChange(3); Thread.sleep(100); state.set(2); - fireResourcesChange(3); + fireResourceChange(3); } catch (Exception e) { } }, 100, TimeUnit.MILLISECONDS); @@ -144,10 +144,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { scheduler.schedule(() -> { try { state.set(3); - fireResourcesChange(3); + fireResourceChange(3); Thread.sleep(100); updateResult.set(1); - fireResourcesChange(5); + fireResourceChange(5); } catch (Exception e) { } }, 100, TimeUnit.MILLISECONDS); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 41248efd56..9180617846 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -17,10 +17,7 @@ package org.thingsboard.server.transport.lwm2m.client; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.core.network.CoapEndpoint; -import org.eclipse.californium.core.network.config.NetworkConfig; -import org.eclipse.californium.core.observe.ObservationStore; -import org.eclipse.californium.scandium.DTLSConnector; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.client.californium.LeshanClient; import org.eclipse.leshan.client.californium.LeshanClientBuilder; @@ -32,7 +29,6 @@ import org.eclipse.leshan.client.resource.DummyInstanceEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.client.servers.ServerIdentity; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.californium.EndpointFactory; import org.eclipse.leshan.core.model.InvalidDDFFileException; import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.ObjectLoader; @@ -44,15 +40,15 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.io.IOException; -import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; @@ -61,10 +57,10 @@ import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @@ -84,7 +80,7 @@ public class LwM2MTestClient { private LwM2MLocationParams locationParams; private LwM2mTemperatureSensor lwM2MTemperatureSensor; - public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { + public void init(Security security, Configuration coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); List models = new ArrayList<>(); for (String resourceName : resources) { @@ -106,44 +102,19 @@ public class LwM2MTestClient { initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, OBJECT_INSTANCE_ID_0)); initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_0), new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_12)); - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedCipherSuitesOnly(true); - dtlsConfig.setClientOnly(); + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(coapConfig); + dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true); DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory(); engineFactory.setReconnectOnUpdate(false); engineFactory.setResumeOnConnect(true); - EndpointFactory endpointFactory = new EndpointFactory() { - - @Override - public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, - ObservationStore store) { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - builder.setInetSocketAddress(address); - builder.setNetworkConfig(coapConfig); - return builder.build(); - } - - @Override - public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, - ObservationStore store) { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig); - builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build())); - builder.setNetworkConfig(coapConfig); - return builder.build(); - } - }; - - LeshanClientBuilder builder = new LeshanClientBuilder(endpoint); builder.setLocalAddress("0.0.0.0", port); builder.setObjects(initializer.createAll()); builder.setCoapConfig(coapConfig); builder.setDtlsConfig(dtlsConfig); builder.setRegistrationEngineFactory(engineFactory); - builder.setEndpointFactory(endpointFactory); builder.setSharedExecutor(executor); builder.setDecoder(new DefaultLwM2mDecoder(false)); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java index d8a54b59bd..a88c795f9c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java @@ -81,8 +81,11 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); - executorService.scheduleWithFixedDelay(() -> - fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN + executorService.scheduleWithFixedDelay(() -> { + fireResourceChange(0); + fireResourceChange(2); + } + , 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN } catch (Throwable e) { log.error("[{}]Throwable", e.toString()); e.printStackTrace(); @@ -126,23 +129,23 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements } case 1: setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue())); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 2: setTimestamp(((Date) value.getValue()).getTime()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 3: setDescription((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 4: setDataFormat((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 5: setAppID((Integer) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); default: return super.write(identity, replace, resourceId, value); @@ -185,7 +188,7 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements try { if (value instanceof LwM2mMultipleResource) { if (replace || this.data == null) { - this.data = new HashMap<>(); + this.data = new HashMap<>(); } value.getInstances().values().forEach(v -> { this.data.put(v.getId(), (byte[]) v.getValue()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java index 590f35e7e0..d9fef9eab3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java @@ -74,8 +74,10 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { } this.scaleFactor = scaleFactor; timestamp = new Date(); - executorService.scheduleWithFixedDelay(() -> - fireResourcesChange(0, 1), 10000, 10000, TimeUnit.MILLISECONDS); + executorService.scheduleWithFixedDelay(() -> { + fireResourceChange(0); + fireResourceChange(1); + }, 10000, 10000, TimeUnit.MILLISECONDS); } catch (Throwable e) { log.error("[{}]Throwable", e.toString()); e.printStackTrace(); @@ -117,13 +119,16 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { private void moveLatitude(float delta) { latitude = latitude + delta * scaleFactor; timestamp = new Date(); - fireResourcesChange(0, 5); + fireResourceChange(0); + fireResourceChange(5); } private void moveLongitude(float delta) { longitude = longitude + delta * scaleFactor; timestamp = new Date(); - fireResourcesChange(1, 5); + fireResourceChange(1); + fireResourceChange(5); + } public float getLatitude() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java index 53060096f7..919d69d919 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java @@ -93,10 +93,9 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr float delta = (RANDOM.nextInt(20) - 10) / 10f; currentTemp += delta; Integer changedResource = adjustMinMaxMeasuredValue(currentTemp); + fireResourceChange(5700); if (changedResource != null) { - fireResourcesChange(5700, changedResource); - } else { - fireResourcesChange(5700); + fireResourceChange(changedResource); } } @@ -127,5 +126,4 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr } - } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java index c14a473d63..37d93279bf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.client; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.servers.ServerIdentity; +import org.eclipse.leshan.core.Destroyable; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mResource; @@ -25,7 +26,6 @@ import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; -import javax.security.auth.Destroyable; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; @@ -103,11 +103,11 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl return WriteResponse.notFound(); case 14: setUtcOffset((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 15: setTimezone((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); default: return super.write(identity, replace, resourceId, value); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index 0d3400c959..b623f4fa19 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -128,16 +128,17 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { try { state.set(1); updateResult.set(1); - fireResourcesChange(7, 9); + fireResourceChange(7); + fireResourceChange(9); Thread.sleep(100); state.set(2); - fireResourcesChange(7); + fireResourceChange(7); Thread.sleep(100); state.set(3); - fireResourcesChange(7); + fireResourceChange(7); Thread.sleep(100); updateResult.set(3); - fireResourcesChange(9); + fireResourceChange(9); } catch (Exception e) { } @@ -148,7 +149,8 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { scheduler.schedule(() -> { state.set(4); updateResult.set(2); - fireResourcesChange(7, 9); + fireResourceChange(7); + fireResourceChange(9); }, 100, TimeUnit.MILLISECONDS); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index f3cb4e5770..3095f28f28 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -201,9 +201,9 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testSoftwareUpdateByObject9() throws Exception { createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9); + NoSecClientCredential credentials = createNoSecClientCredentials(CLIENT_ENDPOINT_OTA9); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA9); + createNewClient(SECURITY, COAP_CONFIG, false, CLIENT_ENDPOINT_OTA9); Thread.sleep(1000); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index 9cea6a8380..a4870b3486 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -52,8 +52,8 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration Set actualObjects = ConcurrentHashMap.newKeySet(); Set actualInstances = ConcurrentHashMap.newKeySet(); rpcActualValue.forEach(node -> { - if (!node.get("url").asText().equals("/")) { - LwM2mPath path = new LwM2mPath(node.get("url").asText()); + if (!node.get("uriReference").asText().equals("/")) { + LwM2mPath path = new LwM2mPath(node.get("uriReference").asText()); actualObjects.add("/" + path.getObjectId()); if (path.isObjectInstance()) { actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId()); diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 469e8a8efd..a9d517f4dd 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -149,6 +149,7 @@ message GetAttributeResponseMsg { int32 requestId = 1; repeated TsKvProto clientAttributeList = 2; repeated TsKvProto sharedAttributeList = 3; + bool isMultipleAttributesRequest = 4; string error = 5; bool sharedStateMsg = 6; } diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java index 1f312da533..8dbbc5a620 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.coapserver; import org.eclipse.californium.core.CoapServer; +import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.concurrent.ConcurrentMap; @@ -24,7 +25,7 @@ public interface CoapServerService { CoapServer getCoapServer() throws UnknownHostException; - ConcurrentMap getDtlsSessionsMap(); + ConcurrentMap getDtlsSessionsMap(); long getTimeout(); diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java index 25dfade5a3..3aa0d0c122 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java @@ -18,8 +18,9 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapServer; import org.eclipse.californium.core.network.CoapEndpoint; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.core.config.CoapConfig; import org.eclipse.californium.core.server.resources.Resource; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.springframework.beans.factory.annotation.Autowired; @@ -37,7 +38,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; +import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS; @Slf4j @Component @@ -78,8 +79,8 @@ public class DefaultCoapServerService implements CoapServerService { } @Override - public ConcurrentMap getDtlsSessionsMap() { - return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionIdsMap() : null; + public ConcurrentMap getDtlsSessionsMap() { + return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionsMap() : null; } @Override @@ -88,16 +89,16 @@ public class DefaultCoapServerService implements CoapServerService { } private CoapServer createCoapServer() throws UnknownHostException { - NetworkConfig networkConfig = new NetworkConfig(); - networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); - networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); - networkConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); - networkConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); - networkConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); - networkConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); - networkConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); - networkConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4); - networkConfig.setInt(NetworkConfig.Keys.COAP_PORT, coapServerContext.getPort()); + Configuration networkConfig = new Configuration(); + networkConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true); + networkConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); + networkConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS); + networkConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); + networkConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED); + networkConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024); + networkConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024); + networkConfig.set(CoapConfig.MAX_RETRANSMIT, 4); + networkConfig.set(CoapConfig.COAP_PORT, coapServerContext.getPort()); server = new CoapServer(networkConfig); CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder(); @@ -105,15 +106,15 @@ public class DefaultCoapServerService implements CoapServerService { InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort()); noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr); - noSecCoapEndpointBuilder.setNetworkConfig(networkConfig); + noSecCoapEndpointBuilder.setConfiguration(networkConfig); CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build(); server.addEndpoint(noSecCoapEndpoint); if (isDtlsEnabled()) { CoapEndpoint.Builder dtlsCoapEndpointBuilder = new CoapEndpoint.Builder(); TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings(); - DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(); - networkConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort()); - dtlsCoapEndpointBuilder.setNetworkConfig(networkConfig); + DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(networkConfig); + networkConfig.set(CoapConfig.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort()); + dtlsCoapEndpointBuilder.setConfiguration(networkConfig); DTLSConnector connector = new DTLSConnector(dtlsConnectorConfig); dtlsCoapEndpointBuilder.setConnector(connector); CoapEndpoint dtlsCoapEndpoint = dtlsCoapEndpointBuilder.build(); diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java index 1954ae900e..ce8b093b4d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java @@ -23,7 +23,6 @@ import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.ConnectionId; -import org.eclipse.californium.scandium.dtls.DTLSSession; import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; @@ -34,13 +33,13 @@ import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; -import org.thingsboard.server.common.transport.auth.SessionInfoCreator; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import javax.security.auth.x500.X500Principal; +import java.net.InetSocketAddress; import java.security.cert.CertPath; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateExpiredException; @@ -48,7 +47,6 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.List; -import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -71,12 +69,12 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri } @Override - public List getSupportedCertificateType() { + public List getSupportedCertificateTypes() { return Collections.singletonList(CertificateType.X_509); } @Override - public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, CertificateMessage message) { try { CertPath certpath = message.getCertificateChain(); X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]); @@ -111,7 +109,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri if (msg != null && strCert.equals(msg.getCredentials())) { DeviceProfile deviceProfile = msg.getDeviceProfile(); if (msg.hasDeviceInfo() && deviceProfile != null) { - tbCoapDtlsSessionInMemoryStorage.put(session.getSessionIdentifier().toString(), new TbCoapDtlsSessionInfo(msg, deviceProfile)); + tbCoapDtlsSessionInMemoryStorage.put(remotePeer, new TbCoapDtlsSessionInfo(msg, deviceProfile)); } break; } @@ -120,8 +118,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri CertificateExpiredException | CertificateNotYetValidException e) { log.error(e.getMessage(), e); - AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE, - session.getPeer()); + AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE); throw new HandshakeException("Certificate chain could not be validated", alert); } } @@ -141,8 +138,8 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri public void setResultHandler(HandshakeResultHandler resultHandler) { } - public ConcurrentMap getTbCoapDtlsSessionIdsMap() { - return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionIdMap(); + public ConcurrentMap getTbCoapDtlsSessionsMap() { + return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionsMap(); } public void evictTimeoutSessions() { diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java index 085bd035ca..8584246f0d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java @@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import java.net.InetSocketAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -25,7 +26,7 @@ import java.util.concurrent.ConcurrentMap; @Data public class TbCoapDtlsSessionInMemoryStorage { - private final ConcurrentMap dtlsSessionIdMap = new ConcurrentHashMap<>(); + private final ConcurrentMap dtlsSessionsMap = new ConcurrentHashMap<>(); private long dtlsSessionInactivityTimeout; private long dtlsSessionReportTimeout; @@ -35,14 +36,14 @@ public class TbCoapDtlsSessionInMemoryStorage { this.dtlsSessionReportTimeout = dtlsSessionReportTimeout; } - public void put(String dtlsSessionId, TbCoapDtlsSessionInfo dtlsSessionInfo) { - log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", dtlsSessionId, dtlsSessionInfo.getLastActivityTime()); - dtlsSessionIdMap.putIfAbsent(dtlsSessionId, dtlsSessionInfo); + public void put(InetSocketAddress remotePeer, TbCoapDtlsSessionInfo dtlsSessionInfo) { + log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", remotePeer, dtlsSessionInfo.getLastActivityTime()); + dtlsSessionsMap.putIfAbsent(remotePeer, dtlsSessionInfo); } public void evictTimeoutSessions() { long expTime = System.currentTimeMillis() - dtlsSessionInactivityTimeout; - dtlsSessionIdMap.entrySet().removeIf(entry -> { + dtlsSessionsMap.entrySet().removeIf(entry -> { if (entry.getValue().getLastActivityTime() < expTime) { log.trace("DTLS session was removed from in-memory store: [{}]", entry.getKey()); return true; diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java index ff778b57ab..7d5c17bf6d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java @@ -16,9 +16,13 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.elements.config.CertificateAuthenticationMode; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.util.SslContextUtil; +import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -26,17 +30,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; -import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; -import java.security.GeneralSecurityException; import java.util.Collections; @Slf4j @@ -75,15 +76,14 @@ public class TbCoapDtlsSettings { @Autowired private TbServiceInfoProvider serviceInfoProvider; - public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException { - DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); + public DtlsConnectorConfig dtlsConnectorConfig(Configuration configuration) throws UnknownHostException { + DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(configuration); configBuilder.setAddress(getInetSocketAddress()); SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials(); SslContextUtil.Credentials serverCredentials = new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain()); - configBuilder.setServerOnly(true); - configBuilder.setClientAuthenticationRequired(false); - configBuilder.setClientAuthenticationWanted(true); + configBuilder.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); + configBuilder.set(DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE, CertificateAuthenticationMode.WANTED); configBuilder.setAdvancedCertificateVerifier( new TbCoapDtlsCertificateVerifier( transportService, @@ -93,8 +93,8 @@ public class TbCoapDtlsSettings { skipValidityCheckForClientCert ) ); - configBuilder.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), - Collections.singletonList(CertificateType.X_509)); + configBuilder.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), + Collections.singletonList(CertificateType.X_509))); return configBuilder.build(); } diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java index b52d08fdd9..1d8e4d45f9 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java @@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.network.Exchange; +import org.eclipse.californium.core.server.DelivererException; import org.eclipse.californium.core.server.ServerMessageDeliverer; import org.eclipse.californium.core.server.resources.Resource; import org.springframework.util.CollectionUtils; @@ -32,7 +33,7 @@ public class TbCoapServerMessageDeliverer extends ServerMessageDeliverer { } @Override - protected Resource findResource(Exchange exchange) { + protected Resource findResource(Exchange exchange) throws DelivererException { validateUriPath(exchange); return findResource(exchange.getRequest().getOptions().getUriPath()); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java index c0fd1e529b..ff975059a1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java @@ -32,8 +32,8 @@ public class EdgeId extends UUIDBased implements EntityId { super(id); } - public static EdgeId fromString(String integrationId) { - return new EdgeId(UUID.fromString(integrationId)); + public static EdgeId fromString(String edgeId) { + return new EdgeId(UUID.fromString(edgeId)); } @ApiModelProperty(position = 2, required = true, value = "string", example = "EDGE", allowableValues = "EDGE") diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java index ac97ab6d8a..9f41b1a6bc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java @@ -18,7 +18,9 @@ package org.thingsboard.server.common.data.query; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.ToString; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; @@ -26,6 +28,8 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) @AllArgsConstructor public class AlarmDataPageLink extends EntityDataPageLink { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java index e2db80d9b9..951bbac030 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java @@ -16,10 +16,14 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class AssetSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java index d6428ae72c..ff93d31856 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java @@ -16,10 +16,14 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class DeviceSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java index 81daff3ef5..25b87629ee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java @@ -16,10 +16,14 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class EdgeSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java index 86974d14be..47ff69c091 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java @@ -16,10 +16,14 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class EntityViewSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java index a7e36a329e..4c317630f2 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java @@ -25,11 +25,19 @@ public class RuleEngineException extends Exception { protected static final ObjectMapper mapper = new ObjectMapper(); @Getter - private final long ts; + private long ts; public RuleEngineException(String message) { super(message != null ? message : "Unknown"); - this.ts = System.currentTimeMillis(); + ts = System.currentTimeMillis(); } + public String toJsonString() { + try { + return mapper.writeValueAsString(mapper.createObjectNode().put("message", getMessage())); + } catch (JsonProcessingException e) { + log.warn("Failed to serialize exception ", e); + throw new RuntimeException(e); + } + } } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 0c3ce2a530..3e291a8177 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -30,7 +30,6 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.msg.session.FeatureType; @@ -48,6 +47,7 @@ import org.thingsboard.server.transport.coap.callback.ToServerRpcSyncSessionCall import org.thingsboard.server.transport.coap.client.CoapClientContext; import org.thingsboard.server.transport.coap.client.TbCoapClientState; +import java.net.InetSocketAddress; import java.util.List; import java.util.Optional; import java.util.Random; @@ -56,6 +56,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import static org.eclipse.californium.elements.DtlsEndpointContext.KEY_SESSION_ID; + @Slf4j public class CoapTransportResource extends AbstractCoapTransportResource { private static final int ACCESS_TOKEN_POSITION = 3; @@ -64,9 +66,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource { private static final int FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST = 3; private static final int REQUEST_ID_POSITION_CERTIFICATE_REQUEST = 4; - private static final String DTLS_SESSION_ID_KEY = "DTLS_SESSION_ID"; - private final ConcurrentMap dtlsSessionIdMap; + private final ConcurrentMap dtlsSessionsMap; private final long timeout; private final CoapClientContext clients; @@ -74,7 +75,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { super(ctx, name); this.setObservable(true); // enable observing this.addObserver(new CoapResourceObserver()); - this.dtlsSessionIdMap = coapServerService.getDtlsSessionsMap(); + this.dtlsSessionsMap = coapServerService.getDtlsSessionsMap(); this.timeout = coapServerService.getTimeout(); this.clients = ctx.getClientContext(); long sessionReportTimeout = ctx.getSessionReportTimeout(); @@ -91,7 +92,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { if (relation == null || relation.isCanceled()) { return; // because request did not try to establish a relation } - if (CoAP.ResponseCode.isSuccess(response.getCode())) { + if (response.getCode().isSuccess()) { if (!relation.isEstablished()) { relation.setEstablished(); addObserveRelation(relation); @@ -198,10 +199,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource { Exchange advanced = exchange.advanced(); Request request = advanced.getRequest(); - String dtlsSessionIdStr = request.getSourceContext().get(DTLS_SESSION_ID_KEY); - if (dtlsSessionIdMap != null && StringUtils.isNotEmpty(dtlsSessionIdStr)) { - TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionIdMap - .computeIfPresent(dtlsSessionIdStr, (dtlsSessionId, dtlsSessionInfo) -> { + var dtlsSessionId = request.getSourceContext().get(KEY_SESSION_ID); + if (dtlsSessionsMap != null && dtlsSessionId != null && !dtlsSessionId.isEmpty()) { + TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionsMap + .computeIfPresent(request.getSourceContext().getPeerAddress(), (dtlsSessionIdStr, dtlsSessionInfo) -> { dtlsSessionInfo.setLastActivityTime(System.currentTimeMillis()); return dtlsSessionInfo; }); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java index f5ff256fef..0e45c52f62 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java @@ -29,6 +29,11 @@ public class TbCoapMessageObserver implements MessageObserver { private final Consumer onAcknowledge; private final Consumer onTimeout; + @Override + public boolean isInternal() { + return false; + } + @Override public void onRetransmission() { @@ -86,13 +91,18 @@ public class TbCoapMessageObserver implements MessageObserver { } + @Override + public void onResponseHandlingError(Throwable cause) { + + } + @Override public void onContextEstablished(EndpointContext endpointContext) { } @Override - public void onComplete() { + public void onTransferComplete() { } } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java index f23ae9deb4..fc0ab5a26c 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java @@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils; import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.elements.DtlsEndpointContext; import org.eclipse.californium.elements.EndpointContext; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.exception.ConnectorException; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -118,7 +120,7 @@ public class SecureClientNoAuth { String keyStorePassword = args[6]; - DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(); + DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration()); setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword); DTLSConnector dtlsConnector = new DTLSConnector(builder.build()); SecureClientNoAuth client = new SecureClientNoAuth(dtlsConnector, host, port, accessToken, clientKeys, sharedKeys); @@ -134,7 +136,7 @@ public class SecureClientNoAuth { keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray()); trustBuilder.setTrustedCertificates(trustedCertificates); config.setAdvancedCertificateVerifier(trustBuilder.build()); - config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)); + config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509))); } catch (GeneralSecurityException e) { System.err.println("certificates are invalid!"); throw new IllegalArgumentException(e.getMessage()); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java index e67055f4e5..700dee7ed9 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java @@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils; import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.elements.DtlsEndpointContext; import org.eclipse.californium.elements.EndpointContext; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.exception.ConnectorException; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -117,7 +119,7 @@ public class SecureClientX509 { String keyStorePassword = args[5]; - DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(); + DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration()); setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword); DTLSConnector dtlsConnector = new DTLSConnector(builder.build()); SecureClientX509 client = new SecureClientX509(dtlsConnector, host, port, clientKeys, sharedKeys); @@ -133,7 +135,7 @@ public class SecureClientX509 { keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray()); trustBuilder.setTrustedCertificates(trustedCertificates); config.setAdvancedCertificateVerifier(trustBuilder.build()); - config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)); + config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509))); } catch (GeneralSecurityException e) { System.err.println("certificates are invalid!"); throw new IllegalArgumentException(e.getMessage()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index b7af551e30..ff40289884 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; @@ -31,12 +32,14 @@ import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecu import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MInMemoryBootstrapConfigStore; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.security.cert.X509Certificate; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; +import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.PSK_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; @@ -45,7 +48,6 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.g @TbLwM2mBootstrapTransportComponent @RequiredArgsConstructor public class LwM2MTransportBootstrapService { - private boolean pskMode = false; private final LwM2MTransportServerConfig serverConfig; private final LwM2MTransportBootstrapConfig bootstrapConfig; @@ -80,12 +82,13 @@ public class LwM2MTransportBootstrapService { /* Create and Set DTLS Config */ - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups()); - dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers()); - dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); - /* Create credentials */ - this.setServerWithCredentials(builder, dtlsConfig); + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); + + dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); + dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups()); + dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers()); + + setServerWithCredentials(builder, dtlsConfig); /* Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); @@ -110,13 +113,13 @@ public class LwM2MTransportBootstrapService { builder.setPublicKey(sslCredentials.getPublicKey()); builder.setPrivateKey(sslCredentials.getPrivateKey()); builder.setCertificateChain(sslCredentials.getCertificateChain()); - dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, RPK_OR_X509_CIPHER_SUITES); } else { /* by default trust all */ builder.setTrustedCertificates(new X509Certificate[0]); log.info("Unable to load X509 files for BootStrapServer"); - this.pskMode = true; + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, PSK_CIPHER_SUITES); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/TbLwM2MDtlsBootstrapCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/TbLwM2MDtlsBootstrapCertificateVerifier.java index eff4cc3871..ca621f2618 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/TbLwM2MDtlsBootstrapCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/TbLwM2MDtlsBootstrapCertificateVerifier.java @@ -17,19 +17,18 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.elements.auth.RawPublicKeyIdentity; import org.eclipse.californium.elements.util.CertPathUtil; import org.eclipse.californium.scandium.dtls.AlertMessage; import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.ConnectionId; -import org.eclipse.californium.scandium.dtls.DTLSSession; import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; -import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; +import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.util.ServerNames; -import org.eclipse.leshan.server.security.SecurityChecker; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.StringUtils; @@ -39,14 +38,12 @@ import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.queue.util.TbLwM2mBootstrapTransportComponent; import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; import org.thingsboard.server.transport.lwm2m.server.client.LwM2MAuthException; -import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; -import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import javax.annotation.PostConstruct; import javax.security.auth.x500.X500Principal; +import java.net.InetSocketAddress; import java.security.PublicKey; import java.security.cert.CertPath; import java.security.cert.CertificateEncodingException; @@ -65,14 +62,13 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti private final LwM2MTransportServerConfig config; private final LwM2MBootstrapSecurityStore bsSecurityStore; - @SuppressWarnings("deprecation") - private StaticCertificateVerifier staticCertificateVerifier; + private StaticNewAdvancedCertificateVerifier staticCertificateVerifier; @Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}") private boolean skipValidityCheckForClientCert; @Override - public List getSupportedCertificateType() { + public List getSupportedCertificateTypes() { return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY); } @@ -83,17 +79,17 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti /* by default trust all */ if (config.getTrustSslCredentials() != null) { X509Certificate[] trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates(); - staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); + staticCertificateVerifier = new StaticNewAdvancedCertificateVerifier(trustedCertificates, new RawPublicKeyIdentity[0], null); } } catch (Exception e) { - log.info("Failed to initialize the certificate verifier", e); + log.warn("ailed to initialize the LwM2M certificate verifier", e); } } @Override - public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, - boolean truncateCertificatePath, CertificateMessage message, - DTLSSession session) { + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, + boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, + CertificateMessage message) { CertPath certChain = message.getCertificateChain(); if (certChain == null) { //We trust all RPK on this layer, and use TbLwM2MAuthorizer @@ -111,14 +107,14 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti TbLwM2MSecurityInfo securityInfo = null; // verify if trust if (staticCertificateVerifier != null) { - try { - staticCertificateVerifier.verifyCertificate(message, session); + HandshakeException exception = staticCertificateVerifier.verifyCertificate(cid, serverName, remotePeer, clientUsage, verifySubject, truncateCertificatePath, message).getException(); + if (exception == null) { String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); if (StringUtils.isNotEmpty(endpoint)) { securityInfo = bsSecurityStore.getX509ByEndpoint(endpoint); } - } catch (HandshakeException e) { - log.trace("Certificate validation failed.", e); + } else { + log.trace("Certificate validation failed.", exception); } } // if not trust or cert trust securityInfo == null @@ -143,8 +139,7 @@ public class TbLwM2MDtlsBootstrapCertificateVerifier implements NewAdvancedCerti } } if (!x509CredentialsFound) { - AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR, - session.getPeer()); + AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR); throw new HandshakeException("x509 verification not enabled!", alert); } return new CertificateVerificationResult(cid, certChain, null); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index f315fbe48d..0582ff5450 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.Link; import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.request.BootstrapDeleteRequest; @@ -134,18 +134,18 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi log.info("Object after discover: [{}]", objectLinks); this.securityInstances = new HashMap<>(); for (Link link : objectLinks) { - if (link.getUrl().startsWith("/0/")) { + if (link.getUriReference().startsWith("/0/")) { try { - LwM2mPath path = new LwM2mPath(link.getUrl()); + LwM2mPath path = new LwM2mPath(link.getUriReference()); if (path.isObjectInstance()) { - if (link.getAttributes().containsKey("ssid")) { - int serverId = Integer.parseInt(link.getAttributes().get("ssid")); + if (link.getLinkParams().containsKey("ssid")) { + int serverId = Integer.parseInt(link.getLinkParams().get("ssid").getUnquoted()); if (!this.securityInstances.containsKey(serverId)) { this.securityInstances.put(serverId, path.getObjectInstanceId()); } else { log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId()); } - this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId()); + this.securityInstances.put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId()); } else { if (!this.securityInstances.containsKey(0)) { this.securityInstances.put(0, path.getObjectInstanceId()); @@ -188,10 +188,10 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) { Link[] links = response.getObjectLinks(); Arrays.stream(links).forEach(link -> { - LwM2mPath path = new LwM2mPath(link.getUrl()); + LwM2mPath path = new LwM2mPath(link.getUriReference()); if (!path.isRoot() && path.getObjectId() < 3) { if (path.isObject()) { - String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0"; + String ver = link.getLinkParams().get("ver") != null ? link.getLinkParams().get("ver").getUnquoted() : "1.0"; this.supportedObjects.put(path.getObjectId(), ver); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java index e20fac8fb9..0cc6cc1b94 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapSecurityStore.java @@ -80,7 +80,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, BOOTSTRAP); if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { /* add value to store from BootstrapJson */ - this.setBootstrapConfigScurityInfo(store); + this.setBootstrapConfigSecurityInfo(store); BootstrapConfig bsConfig = store.getBootstrapConfig(); if (bsConfig.security != null) { try { @@ -99,18 +99,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { } public TbLwM2MSecurityInfo getX509ByEndpoint(String endPoint) { - try { TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, BOOTSTRAP); this.addValueToStore(store, store.getEndpoint()); return store; - } catch (LwM2MAuthException e) { - log.trace("Failed find security info: {}", endPoint, e); - } - return null; } - private void setBootstrapConfigScurityInfo(TbLwM2MSecurityInfo store) { + private void setBootstrapConfigSecurityInfo(TbLwM2MSecurityInfo store) { /* BootstrapConfig */ LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store); if (lwM2MBootstrapConfig != null) { @@ -182,7 +177,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { SecurityInfo securityInfo = null; if (store != null && store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) { securityInfo = store.getSecurityInfo(); - this.setBootstrapConfigScurityInfo(store); + this.setBootstrapConfigSecurityInfo(store); BootstrapConfig bsConfigNew = store.getBootstrapConfig(); if (bsConfigNew != null) { try { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java similarity index 70% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java index 3c12b8f6be..699f57481f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java @@ -16,31 +16,31 @@ package org.thingsboard.server.transport.lwm2m.config; import lombok.Getter; -import org.eclipse.leshan.core.LwM2m.Version; +import org.eclipse.leshan.core.LwM2m.LwM2mVersion; import org.eclipse.leshan.core.request.ContentFormat; -public enum LwM2mVersion { - VERSION_1_0(0, Version.V1_0, ContentFormat.TLV, false), - VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT, true); +public enum TbLwM2mVersion { + VERSION_1_0(0, LwM2mVersion.V1_0, ContentFormat.TLV, false), + VERSION_1_1(1, LwM2mVersion.V1_1, ContentFormat.TEXT, true); @Getter private final int code; @Getter - private final Version version; + private final LwM2mVersion version; @Getter private final ContentFormat contentFormat; @Getter private final boolean composite; - LwM2mVersion(int code, Version version, ContentFormat contentFormat, boolean composite) { + TbLwM2mVersion(int code, LwM2mVersion version, ContentFormat contentFormat, boolean composite) { this.code = code; this.version = version; this.contentFormat = contentFormat; this.composite = composite; } - public static LwM2mVersion fromVersion(Version version) { - for (LwM2mVersion to : LwM2mVersion.values()) { + public static TbLwM2mVersion fromVersion(LwM2mVersion version) { + for (TbLwM2mVersion to : TbLwM2mVersion.values()) { if (to.version.equals(version)) { return to; } @@ -48,8 +48,8 @@ public enum LwM2mVersion { throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %s", version)); } - public static LwM2mVersion fromVersionStr(String versionStr) { - for (LwM2mVersion to : LwM2mVersion.values()) { + public static TbLwM2mVersion fromVersionStr(String versionStr) { + for (TbLwM2mVersion to : TbLwM2mVersion.values()) { if (to.version.toString().equals(versionStr)) { return to; } @@ -57,8 +57,8 @@ public enum LwM2mVersion { throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %s", versionStr)); } - public static LwM2mVersion fromCode(int code) { - for (LwM2mVersion to : LwM2mVersion.values()) { + public static TbLwM2mVersion fromCode(int code) { + for (TbLwM2mVersion to : TbLwM2mVersion.values()) { if (to.code == code) { return to; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 93ba7934dc..917ff4821a 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -17,17 +17,17 @@ package org.thingsboard.server.transport.lwm2m.secure; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.elements.auth.RawPublicKeyIdentity; import org.eclipse.californium.elements.util.CertPathUtil; import org.eclipse.californium.scandium.dtls.AlertMessage; import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.ConnectionId; -import org.eclipse.californium.scandium.dtls.DTLSSession; import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; -import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; +import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.util.ServerNames; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.springframework.beans.factory.annotation.Value; @@ -49,6 +49,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import javax.annotation.PostConstruct; import javax.security.auth.x500.X500Principal; +import java.net.InetSocketAddress; import java.security.PublicKey; import java.security.cert.CertPath; import java.security.cert.CertificateEncodingException; @@ -71,34 +72,33 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; private final TbMainSecurityStore securityStore; - @SuppressWarnings("deprecation") - private StaticCertificateVerifier staticCertificateVerifier; + private StaticNewAdvancedCertificateVerifier staticCertificateVerifier; @Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}") private boolean skipValidityCheckForClientCert; @Override - public List getSupportedCertificateType() { + public List getSupportedCertificateTypes() { return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY); } - @SuppressWarnings("deprecation") @PostConstruct public void init() { try { /* by default trust all */ if (config.getTrustSslCredentials() != null) { X509Certificate[] trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates(); - staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); + staticCertificateVerifier = new StaticNewAdvancedCertificateVerifier(trustedCertificates, new RawPublicKeyIdentity[0], null); } - } catch (Exception e) { - log.info("Failed to initialize the "); + log.warn("Failed to initialize the LwM2M certificate verifier", e); } } @Override - public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, + boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, + CertificateMessage message) { CertPath certChain = message.getCertificateChain(); if (certChain == null) { //We trust all RPK on this layer, and use TbLwM2MAuthorizer @@ -115,21 +115,24 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } TbLwM2MSecurityInfo securityInfo = null; if (staticCertificateVerifier != null) { - try { - staticCertificateVerifier.verifyCertificate(message, session); - String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); - if (StringUtils.isNotEmpty(endpoint)) { - securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT); + HandshakeException exception = staticCertificateVerifier.verifyCertificate(cid, serverName, remotePeer, clientUsage, verifySubject, truncateCertificatePath, message).getException(); + if (exception == null) { + try { + String endpoint = config.getTrustSslCredentials().getValueFromSubjectNameByKey(cert.getSubjectX500Principal().getName(), "CN"); + if (StringUtils.isNotEmpty(endpoint)) { + securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(endpoint, CLIENT); + } + } catch (LwM2MAuthException e) { + log.trace("Certificate trust validation failed.", e); } - } catch (HandshakeException | LwM2MAuthException e) { - log.trace("Certificate trust validation failed.", e); + } else { + log.trace("Certificate trust validation failed.", exception); } } // if not trust or cert trust securityInfo == null String strCert = SslUtil.getCertificateString(cert); String sha3Hash = EncryptionUtil.getSha3Hash(strCert); if (securityInfo == null || securityInfo.getMsg() == null) { - try { securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, CLIENT); } catch (LwM2MAuthException e) { @@ -168,8 +171,7 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } } if (!x509CredentialsFound) { - AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR, - session.getPeer()); + AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR); throw new HandshakeException("x509 verification not enabled!", alert); } return new CertificateVerificationResult(cid, certChain, null); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 1245aeb9ea..23238a07a5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder; @@ -40,6 +41,8 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PreDestroy; import java.security.cert.X509Certificate; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; @@ -121,11 +124,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { /* Create DTLS Config */ - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(config.getPort(), config.getSecurePort(), config)); + + dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); + dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, config.isRecommendedSupportedGroups()); + dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, config.isRecommendedCiphers()); - dtlsConfig.setServerOnly(true); - dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups()); - dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers()); /* Create credentials */ this.setServerWithCredentials(builder, dtlsConfig); @@ -144,12 +148,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { builder.setCertificateChain(sslCredentials.getCertificateChain()); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); builder.setAuthorizer(authorizer); - dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, RPK_OR_X509_CIPHER_SUITES); } else { /* by default trust all */ builder.setTrustedCertificates(new X509Certificate[0]); log.info("Unable to load X509 files for LWM2MServer"); - dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, PSK_CIPHER_SUITES); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java index 31e0ae4de5..b47e548b56 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java @@ -15,27 +15,30 @@ */ package org.thingsboard.server.transport.lwm2m.server; -import org.eclipse.californium.core.network.config.NetworkConfig; -import org.eclipse.californium.core.network.config.NetworkConfigDefaults; +import org.eclipse.californium.core.config.CoapConfig; +import org.eclipse.californium.elements.config.Configuration; import org.springframework.util.CollectionUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS; public class LwM2MNetworkConfig { - public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { - NetworkConfig coapConfig = new NetworkConfig(); - coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, serverPortNoSec); - coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, serverSecurePort); + public static Configuration getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { + Configuration coapConfig = new Configuration(); + coapConfig.set(CoapConfig.COAP_PORT, serverPortNoSec); + coapConfig.set(CoapConfig.COAP_SECURE_PORT, serverSecurePort); /** Example:Property for large packet: #NetworkConfig config = new NetworkConfig(); - #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32); - #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32); - #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048); - #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3); - #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000); + #config.setInt(CoapConfig.MAX_MESSAGE_SIZE,32); + #config.setInt(CoapConfig.PREFERRED_BLOCK_SIZE,32); + #config.setInt(CoapConfig.MAX_RESOURCE_BODY_SIZE,2048); + #config.setInt(CoapConfig.MAX_RETRANSMIT,3); + #config.setInt(CoapConfig.MAX_TRANSMIT_WAIT,120000); */ /** @@ -46,14 +49,14 @@ public class LwM2MNetworkConfig { CoAP client will try to use block mode or adapt the block size when receiving a 4.13 Entity too large response code */ - coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); + coapConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true); /** Property to indicate if the response should always include the Block2 option \ when client request early blockwise negociation but the response can be sent on one packet. - value of false indicate that the server will respond without block2 option if no further blocks are required. - value of true indicate that the server will response with block2 option event if no further blocks are required. */ - coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); + coapConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); /** * The maximum amount of time (in milliseconds) allowed between * transfers of individual blocks in a blockwise transfer before the @@ -62,7 +65,7 @@ public class LwM2MNetworkConfig { * The default value of this property is * {@link NetworkConfigDefaults#DEFAULT_BLOCKWISE_STATUS_LIFETIME} = 5 * 60 * 1000; // 5 mins [ms]. */ - coapConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); + coapConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS); /** !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13 The maximum size of a resource body (in bytes) that will be accepted @@ -77,7 +80,7 @@ public class LwM2MNetworkConfig { The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192 A value of {@code 0} turns off transparent handling of blockwise transfers altogether. */ - coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); + coapConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); /** The default DTLS response matcher. Supported values are STRICT, RELAXED, or PRINCIPAL. @@ -88,13 +91,13 @@ public class LwM2MNetworkConfig { – true with address check, (STRICT, UDP) - if port Registration of client is changed - it is bad - false, without */ - coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); + coapConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED); /** https://tools.ietf.org/html/rfc7959#section-2.9.3 The block size (number of bytes) to use when doing a blockwise transfer. \ This value serves as the upper limit for block size in blockwise transfers */ - coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); + coapConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024); /** The maximum payload size (in bytes) that can be transferred in a single message, i.e. without requiring a blockwise transfer. @@ -102,12 +105,14 @@ public class LwM2MNetworkConfig { In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol DEFAULT_VALUE = 1024 */ - coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); + coapConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024); - coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10); + coapConfig.set(CoapConfig.MAX_RETRANSMIT, 10); if (!CollectionUtils.isEmpty(config.getNetworkConfig())) { - config.getNetworkConfig().forEach(p -> coapConfig.setString(p.getKey(), p.getValue())); + Properties networkProps = new Properties(); + config.getNetworkConfig().forEach(p -> networkProps.put(p.getKey(), p.getValue())); + coapConfig.add(networkProps); } return coapConfig; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 7ffcf88e31..5c0e225f8b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -16,7 +16,10 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.observation.CompositeObservation; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.observation.SingleObservation; +import org.eclipse.leshan.core.response.ObserveCompositeResponse; import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.server.observation.ObservationListener; import org.eclipse.leshan.server.queue.PresenceListener; @@ -86,26 +89,34 @@ public class LwM2mServerListener { @Override public void cancelled(Observation observation) { - log.trace("Canceled Observation {}.", observation.getPath()); + //TODO: should be able to use CompositeObservation + log.trace("Canceled Observation {}.", ((SingleObservation)observation).getPath()); } @Override - public void onResponse(Observation observation, Registration registration, ObserveResponse response) { + public void onResponse(SingleObservation observation, Registration registration, ObserveResponse response) { if (registration != null) { service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response); } } + @Override + public void onResponse(CompositeObservation observation, Registration registration, ObserveCompositeResponse response) { + throw new RuntimeException("Not implemented yet!"); + } + @Override public void onError(Observation observation, Registration registration, Exception error) { if (error != null) { - log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); + //TODO: should be able to use CompositeObservation + log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), ((SingleObservation)observation).getPath(), error.getMessage()); } } @Override public void newObservation(Observation observation, Registration registration) { - log.trace("Successful start newObservation {}.", observation.getPath()); + //TODO: should be able to use CompositeObservation + log.trace("Successful start newObservation {}.", ((SingleObservation)observation).getPath()); } }; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java index 53bb650868..fdf5e5f8bc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java @@ -56,7 +56,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { if (relation == null || relation.isCanceled()) { return; // because request did not try to establish a relation } - if (CoAP.ResponseCode.isSuccess(response.getCode())) { + if (response.getCode().isSuccess()) { if (!relation.isEstablished()) { relation.setEstablished(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 6f25e752d0..04b8f858c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; -import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; +import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion; import java.io.IOException; import java.io.ObjectInputStream; @@ -423,14 +423,14 @@ public class LwM2mClient implements Serializable { if (registration == null) { return ContentFormat.DEFAULT; } else{ - return LwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat(); + return TbLwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat(); } } static private Set clientSupportContentFormat(Registration registration) { Set contentFormats = new HashSet<>(); contentFormats.add(ContentFormat.DEFAULT); - String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")).findFirst().get().getAttributes().get("ct"); + String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUriReference().equals("/")).findFirst().get().getLinkParams().get("ct").getUnquoted(); if (code != null) { Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) .map(String::trim) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 5fcb532c10..eb675c9461 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -393,9 +393,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { public Set getSupportedIdVerInClient(LwM2mClient client) { Set clientObjects = ConcurrentHashMap.newKeySet(); Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { - LwM2mPath pathIds = new LwM2mPath(link.getUrl()); + LwM2mPath pathIds = new LwM2mPath(link.getUriReference()); if (!pathIds.isRoot()) { - clientObjects.add(convertObjectIdToVersionedId(link.getUrl(), client.getRegistration())); + clientObjects.add(convertObjectIdToVersionedId(link.getUriReference(), client.getRegistration())); } }); return (clientObjects.size() > 0) ? clientObjects : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 48292c92d0..89d461c76b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.Link; import org.eclipse.leshan.core.LwM2m; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; @@ -29,6 +29,7 @@ import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.observation.SingleObservation; import org.eclipse.leshan.core.request.CompositeDownlinkRequest; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.CreateRequest; @@ -160,7 +161,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im validateVersionedId(client, request); LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); - if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { + //TODO: should be able to use CompositeObservation + if (observations.stream().noneMatch(observation -> ((SingleObservation)observation).getPath().equals(resultIds))) { ObserveRequest downlink; ContentFormat contentFormat = getReadRequestContentFormat(client, request, modelProvider); if (resultIds.isResource()) { @@ -183,7 +185,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback) { Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); - Set paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); + //TODO: should be able to use CompositeObservation + Set paths = observations.stream().map(observation -> ((SingleObservation)observation).getPath().toString()).collect(Collectors.toUnmodifiableSet()); callback.onSuccess(request, paths); } @@ -620,9 +623,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } private static ContentFormat getContentFormatForComplex(LwM2mClient client) { - if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) { + if (LwM2m.LwM2mVersion.V1_0.equals(client.getRegistration().getLwM2mVersion())) { return ContentFormat.TLV; - } else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) { + } else if (LwM2m.LwM2mVersion.V1_1.equals(client.getRegistration().getLwM2mVersion())) { ContentFormat result = findFirst(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON); if (result != null) { return result; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java index b6f2c37c1d..9f5bf80cf6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.Link; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.DeleteRequest; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java index d9c213604c..c221f598a2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java @@ -15,7 +15,8 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.DefaultLinkSerializer; +import org.eclipse.leshan.core.link.LinkSerializer; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; import org.thingsboard.server.common.transport.TransportService; @@ -27,12 +28,14 @@ import java.util.Optional; public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback { + private final LinkSerializer serializer = new DefaultLinkSerializer(); + public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } protected Optional serializeSuccessfulResponse(DiscoverResponse response) { - return Optional.of(Link.serialize(response.getObjectLinks())); + return Optional.of(serializer.serialize(response.getObjectLinks())); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java index afa5eae53a..0b1254115e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java @@ -22,10 +22,11 @@ import org.eclipse.leshan.core.Destroyable; import org.eclipse.leshan.core.Startable; import org.eclipse.leshan.core.Stoppable; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.observation.SingleObservation; import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.core.util.Validate; -import org.eclipse.leshan.server.californium.observation.ObserveUtil; +import org.eclipse.leshan.core.californium.ObserveUtil; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.redis.RedisRegistrationStore; import org.eclipse.leshan.server.redis.serialization.IdentitySerDes; @@ -455,7 +456,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto // cancel existing observations for the same path and registration id. for (Observation obs : getObservations(connection, registrationId)) { - if (observation.getPath().equals(obs.getPath()) + //TODO: should be able to use CompositeObservation + if (((SingleObservation)observation).getPath().equals(((SingleObservation)obs).getPath()) && !Arrays.equals(observation.getId(), obs.getId())) { removed.add(obs); unsafeRemoveObservation(connection, registrationId, obs.getId()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index b1f6637085..e415858755 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -30,7 +30,6 @@ import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mSingleResource; -import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.node.codec.CodecException; import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; @@ -44,7 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.transport.util.JsonUtils; -import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; +import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; @@ -236,7 +235,7 @@ public class LwM2MTransportUtil { public static String convertObjectIdToVersionedId(String path, Registration registration) { String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); - ver = ver != null ? ver : LwM2mVersion.VERSION_1_0.getVersion().toString(); + ver = ver != null ? ver : TbLwM2mVersion.VERSION_1_0.getVersion().toString(); try { String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); if (keyArray.length > 1) { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index adc7f1515e..73c0e9a32f 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -122,7 +122,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg); } - + @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { return Optional.of(createMqttPublishMsg(ctx, topic, JsonConverter.toJson(notificationMsg))); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java index 72aac1fedd..d354821ce0 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java @@ -313,16 +313,18 @@ public class JsonConverter { return result; } - public static JsonObject getJsonObjectForGateway(String deviceName, TransportProtos.GetAttributeResponseMsg - responseMsg) { + public static JsonObject getJsonObjectForGateway( + String deviceName, + TransportProtos.GetAttributeResponseMsg responseMsg + ) { JsonObject result = new JsonObject(); result.addProperty("id", responseMsg.getRequestId()); result.addProperty(DEVICE_PROPERTY, deviceName); if (responseMsg.getClientAttributeListCount() > 0) { - addValues(result, responseMsg.getClientAttributeListList()); + addValues(result, responseMsg.getClientAttributeListList(), responseMsg.getIsMultipleAttributesRequest()); } if (responseMsg.getSharedAttributeListCount() > 0) { - addValues(result, responseMsg.getSharedAttributeListList()); + addValues(result, responseMsg.getSharedAttributeListList(), responseMsg.getIsMultipleAttributesRequest()); } return result; } @@ -335,8 +337,8 @@ public class JsonConverter { return result; } - private static void addValues(JsonObject result, List kvList) { - if (kvList.size() == 1) { + private static void addValues(JsonObject result, List kvList, boolean multipleAttrKeysRequested) { + if (kvList.size() == 1 && !multipleAttrKeysRequested) { addValueToJson(result, "value", kvList.get(0).getKv()); } else { JsonObject values; diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java index b1878792cf..5ea04de462 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.apache.cassandra.cql3.Json; import org.apache.commons.lang3.RandomStringUtils; @@ -69,6 +70,7 @@ public abstract class AbstractContainerTest { protected static String TB_TOKEN; protected static RestClient restClient; protected ObjectMapper mapper = new ObjectMapper(); + protected JsonParser jsonParser = new JsonParser(); @BeforeClass public static void before() throws Exception { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java index 2e106815c7..951efd6dfe 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java @@ -20,6 +20,7 @@ import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.netty.buffer.ByteBuf; @@ -151,6 +152,75 @@ public class MqttGatewayClientTest extends AbstractContainerTest { Assert.assertTrue(verify(actualLatestTelemetry, "attr4", Long.toString(73))); } + @Test + public void responseDataOnAttributesRequestCheck() throws Exception { + Optional createdDeviceCredentials = restClient.getDeviceCredentialsByDeviceId(createdDevice.getId()); + Assert.assertTrue(createdDeviceCredentials.isPresent()); + JsonObject sharedAttributes = new JsonObject(); + sharedAttributes.addProperty("attr1", "value1"); + sharedAttributes.addProperty("attr2", true); + sharedAttributes.addProperty("attr3", 42.0); + sharedAttributes.addProperty("attr4", 73); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + ResponseEntity sharedAttributesResponse = restClient.getRestTemplate() + .postForEntity(HTTPS_URL + "/api/plugins/telemetry/DEVICE/{deviceId}/SHARED_SCOPE", + mapper.readTree(sharedAttributes.toString()), ResponseEntity.class, + createdDevice.getId()); + Assert.assertTrue(sharedAttributesResponse.getStatusCode().is2xxSuccessful()); + var event = listener.getEvents().poll(10, TimeUnit.SECONDS); + + JsonObject requestData = new JsonObject(); + requestData.addProperty("id", 1); + requestData.addProperty("device", createdDevice.getName()); + requestData.addProperty("client", false); + requestData.addProperty("key", "attr1"); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(requestData.toString().getBytes())).get(); + event = listener.getEvents().poll(10, TimeUnit.SECONDS); + + JsonObject responseData = jsonParser.parse(Objects.requireNonNull(event).getMessage()).getAsJsonObject(); + Assert.assertTrue(responseData.has("value")); + Assert.assertEquals(sharedAttributes.get("attr1").getAsString(), responseData.get("value").getAsString()); + + requestData = new JsonObject(); + requestData.addProperty("id", 1); + requestData.addProperty("device", createdDevice.getName()); + requestData.addProperty("client", false); + JsonArray keys = new JsonArray(); + keys.add("attr1"); + keys.add("attr2"); + requestData.add("keys", keys); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(requestData.toString().getBytes())).get(); + event = listener.getEvents().poll(10, TimeUnit.SECONDS); + responseData = jsonParser.parse(Objects.requireNonNull(event).getMessage()).getAsJsonObject(); + + Assert.assertTrue(responseData.has("values")); + Assert.assertEquals(sharedAttributes.get("attr1").getAsString(), responseData.get("values").getAsJsonObject().get("attr1").getAsString()); + Assert.assertEquals(sharedAttributes.get("attr2").getAsString(), responseData.get("values").getAsJsonObject().get("attr2").getAsString()); + + requestData = new JsonObject(); + requestData.addProperty("id", 1); + requestData.addProperty("device", createdDevice.getName()); + requestData.addProperty("client", false); + keys = new JsonArray(); + keys.add("attr1"); + keys.add("undefined"); + requestData.add("keys", keys); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(requestData.toString().getBytes())).get(); + event = listener.getEvents().poll(10, TimeUnit.SECONDS); + responseData = jsonParser.parse(Objects.requireNonNull(event).getMessage()).getAsJsonObject(); + + Assert.assertTrue(responseData.has("values")); + Assert.assertEquals(sharedAttributes.get("attr1").getAsString(), responseData.get("values").getAsJsonObject().get("attr1").getAsString()); + Assert.assertEquals(1, responseData.get("values").getAsJsonObject().entrySet().size()); + } + @Test public void requestAttributeValuesFromServer() throws Exception { WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); diff --git a/pom.xml b/pom.xml index 96ff02f20f..295e01f2d3 100755 --- a/pom.xml +++ b/pom.xml @@ -68,8 +68,8 @@ 2.12.1 1.3.4 2.2.6 - 2.6.1 - 2.0.0-M4 + 3.0.0 + 2.0.0-M5 2.6.2 2.3.30 1.6.2 diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java index 087e2256da..62508e5503 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java @@ -229,18 +229,10 @@ class AlarmRuleState { long repeatingTimes = 0; AlarmConditionSpec alarmConditionSpec = getSpec(); AlarmConditionSpecType specType = alarmConditionSpec.getType(); - if(specType.equals(AlarmConditionSpecType.REPEATING)) { + if (specType.equals(AlarmConditionSpecType.REPEATING)) { RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec; - repeatingTimes = repeating.getPredicate().getDefaultValue(); - - if (repeating.getPredicate().getDynamicValue() != null && - repeating.getPredicate().getDynamicValue().getSourceAttribute() != null) { - EntityKeyValue repeatingKeyValue = getDynamicPredicateValue(data, repeating.getPredicate().getDynamicValue()); - if (repeatingKeyValue != null) { - repeatingTimes = repeatingKeyValue.getLngValue(); - } - } + repeatingTimes = resolveDynamicValue(data, repeating.getPredicate()); } return repeatingTimes; } @@ -249,22 +241,33 @@ class AlarmRuleState { long durationTimeInMs = 0; AlarmConditionSpec alarmConditionSpec = getSpec(); AlarmConditionSpecType specType = alarmConditionSpec.getType(); - if(specType.equals(AlarmConditionSpecType.DURATION)) { + if (specType.equals(AlarmConditionSpecType.DURATION)) { DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec; TimeUnit timeUnit = duration.getUnit(); - durationTimeInMs = timeUnit.toMillis(duration.getPredicate().getDefaultValue()); + durationTimeInMs = timeUnit.toMillis(resolveDynamicValue(data, duration.getPredicate())); + } + return durationTimeInMs; + } - if (duration.getPredicate().getDynamicValue() != null && - duration.getPredicate().getDynamicValue().getSourceAttribute() != null) { - EntityKeyValue durationKeyValue = getDynamicPredicateValue(data, duration.getPredicate().getDynamicValue()); - if (durationKeyValue != null) { - durationTimeInMs = timeUnit.toMillis(durationKeyValue.getLngValue()); - } - } + private Long resolveDynamicValue(DataSnapshot data, FilterPredicateValue predicate) { + DynamicValue dynamicValue = predicate.getDynamicValue(); + Long defaultValue = predicate.getDefaultValue().longValue(); + if (dynamicValue == null || dynamicValue.getSourceAttribute() == null) { + return defaultValue; } - return durationTimeInMs; + EntityKeyValue keyValue = getDynamicPredicateValue(data, dynamicValue); + if (keyValue == null) { + return defaultValue; + } + + var longValue = getLongValue(keyValue); + if (longValue == null) { + String sourceAttribute = dynamicValue.getSourceAttribute(); + throw new NumericParseException(String.format("Could not convert attribute '%s' with value '%s' to numeric value!", sourceAttribute, getStrValue(keyValue))); + } + return longValue; } public AlarmEvalResult eval(long ts, DataSnapshot dataSnapshot) { @@ -545,4 +548,28 @@ class AlarmRuleState { } } + private static Long getLongValue(EntityKeyValue ekv) { + switch (ekv.getDataType()) { + case LONG: + return ekv.getLngValue(); + case DOUBLE: + return ekv.getDblValue() != null ? ekv.getDblValue().longValue() : null; + case BOOLEAN: + return ekv.getBoolValue() != null ? (ekv.getBoolValue() ? 1 : 0L) : null; + case STRING: + try { + return Long.parseLong(ekv.getStrValue()); + } catch (RuntimeException e) { + return null; + } + case JSON: + try { + return Long.parseLong(ekv.getJsonValue()); + } catch (RuntimeException e) { + return null; + } + default: + return null; + } + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index ce78c3ad2a..2a46b77791 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -51,6 +51,7 @@ import java.util.function.BiFunction; @Slf4j class AlarmState { + public static final String ERROR_MSG = "Failed to process alarm rule for Device [%s]: %s"; private final ProfileState deviceProfile; private final EntityId originator; private DeviceProfileAlarm alarmDefinition; @@ -75,12 +76,20 @@ class AlarmState { lastMsgMetaData = msg.getMetaData(); lastMsgQueueName = msg.getQueueName(); this.dataSnapshot = data; - return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval); + try { + return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval); + } catch (NumericParseException e) { + throw new RuntimeException(String.format(ERROR_MSG, originator.getId().toString(), e.getMessage())); + } } public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException { initCurrentAlarm(ctx); - return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, dataSnapshot)); + try { + return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, dataSnapshot)); + } catch (NumericParseException e) { + throw new RuntimeException(String.format(ERROR_MSG, originator.getId().toString(), e.getMessage())); + } } public boolean createOrClearAlarms(TbContext ctx, TbMsg msg, T data, SnapshotUpdate update, BiFunction evalFunction) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java new file mode 100644 index 0000000000..15d3e6e476 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.rule.engine.profile; + +public class NumericParseException extends RuntimeException { + public NumericParseException(String message) { + super(message); + } +} diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java index 36e838f57e..78caee289f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java @@ -130,7 +130,7 @@ public class TbAlarmNodeTest { when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(any(Alarm.class)); - + long ts = msg.getTs(); node.onMsg(ctx, msg); verify(ctx).enqueue(any(), successCaptor.capture(), failureCaptor.capture()); @@ -152,6 +152,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) @@ -192,7 +194,7 @@ public class TbAlarmNodeTest { initWithCreateAlarmScript(); metaData.putValue("key", "value"); TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); - + long ts = msg.getTs(); Alarm clearedAlarm = Alarm.builder().status(CLEARED_ACK).build(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); @@ -222,6 +224,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) @@ -407,7 +411,7 @@ public class TbAlarmNodeTest { String rawJson = "{\"alarmSeverity\": \"WARNING\", \"passed\": 5}"; metaData.putValue("key", "value"); TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); - + long ts = msg.getTs(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(any(Alarm.class)); @@ -433,6 +437,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) @@ -467,6 +473,7 @@ public class TbAlarmNodeTest { metaData.putValue("alarmSeverity", "WARNING"); TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + long ts = msg.getTs(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); @@ -492,6 +499,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) diff --git a/ui-ngx/generate-types.js b/ui-ngx/generate-types.js new file mode 100644 index 0000000000..a24673cbd5 --- /dev/null +++ b/ui-ngx/generate-types.js @@ -0,0 +1,66 @@ +/* + * Copyright © 2016-2022 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const child_process = require("child_process"); +const fs = require('fs'); +const path = require('path'); +const typeDir = './target/types'; +const srcDir = typeDir + '/src'; +const moduleMapPath = "src/app/modules/common/modules-map.ts"; + +console.log(`Remove directory: ${typeDir}`); +try { + fs.rmSync(typeDir, {recursive: true, force: true,}); +} catch (err) { + console.error(`Remove directory error: ${err}`); +} + +const cliCommand = `./node_modules/.bin/ngc --p src/tsconfig.app.json --declaration --outDir ${srcDir}`; +console.log(cliCommand); +try { + child_process.execSync(cliCommand); +} catch (err) { + console.error("Build types", err); + process.exit(1); +} + +function fromDir(startPath, filter, callback) { + if (!fs.existsSync(startPath)) { + console.log("not dirs", startPath); + process.exit(1); + } + + const files = fs.readdirSync(startPath); + for (let i = 0; i < files.length; i++) { + const filename = path.join(startPath, files[i]); + const stat = fs.lstatSync(filename); + if (stat.isDirectory()) { + fromDir(filename, filter, callback); + } else if (filter.test(filename)) { + callback(filename) + } + } +} + + +fromDir(srcDir, /(\.js|\.js\.map)$/, function (filename) { + try { + fs.rmSync(filename); + } catch (err) { + console.error(`Remove file error ${filename}: ${err}`); + } +}); +fs.cpSync(moduleMapPath, `${typeDir}/${moduleMapPath}`); diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 7308a86c9e..6c912e1fdf 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -6,6 +6,7 @@ "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", "build:prod": "ng build --configuration production --vendor-chunk", + "build:types": "node generate-types.js", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e",