lwm2m: add Lwm2m provider for models
This commit is contained in:
		
							parent
							
								
									d27c721bbf
								
							
						
					
					
						commit
						648e8ec262
					
				@ -17,6 +17,10 @@ package org.thingsboard.server.service.install;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.databind.JsonNode;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.eclipse.leshan.core.model.DDFFileParser;
 | 
			
		||||
import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
 | 
			
		||||
import org.eclipse.leshan.core.model.InvalidDDFFileException;
 | 
			
		||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
@ -39,6 +43,8 @@ import org.thingsboard.server.dao.rule.RuleChainService;
 | 
			
		||||
import org.thingsboard.server.dao.widget.WidgetTypeService;
 | 
			
		||||
import org.thingsboard.server.dao.widget.WidgetsBundleService;
 | 
			
		||||
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.nio.file.DirectoryStream;
 | 
			
		||||
import java.nio.file.Files;
 | 
			
		||||
@ -196,37 +202,70 @@ public class InstallScripts {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void loadSystemLwm2mResources() throws Exception {
 | 
			
		||||
//        Path modelsDir = Paths.get("/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/");
 | 
			
		||||
        Path modelsDir = Paths.get(getDataDir(), MODELS_DIR);
 | 
			
		||||
        try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) {
 | 
			
		||||
            dirStream.forEach(
 | 
			
		||||
                    path -> {
 | 
			
		||||
                        try {
 | 
			
		||||
                            Resource resource = new Resource();
 | 
			
		||||
                            resource.setTenantId(TenantId.SYS_TENANT_ID);
 | 
			
		||||
                            resource.setResourceType(ResourceType.LWM2M_MODEL);
 | 
			
		||||
                            resource.setResourceId(path.getFileName().toString());
 | 
			
		||||
                            resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(path)));
 | 
			
		||||
                            resourceService.saveResource(resource);
 | 
			
		||||
                        } catch (Exception e) {
 | 
			
		||||
                            log.error("Unable to load lwm2m model [{}]", path.toString());
 | 
			
		||||
                            throw new RuntimeException("Unable to load lwm2m model", e);
 | 
			
		||||
        if (Files.isDirectory(modelsDir)) {
 | 
			
		||||
            try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) {
 | 
			
		||||
                dirStream.forEach(
 | 
			
		||||
                        path -> {
 | 
			
		||||
                            try {
 | 
			
		||||
                                byte[] fileBytes = Files.readAllBytes(path);
 | 
			
		||||
                                String key = getObjectModelLwm2mValid(fileBytes, path.getFileName().toString(), new DefaultDDFFileValidator());
 | 
			
		||||
                                if (key != null) {
 | 
			
		||||
                                    Resource resource = new Resource();
 | 
			
		||||
                                    resource.setTenantId(TenantId.SYS_TENANT_ID);
 | 
			
		||||
                                    resource.setResourceType(ResourceType.LWM2M_MODEL);
 | 
			
		||||
                                    resource.setResourceId(key);
 | 
			
		||||
                                    resource.setValue(Base64.getEncoder().encodeToString(fileBytes));
 | 
			
		||||
                                    resourceService.saveResource(resource);
 | 
			
		||||
                                }
 | 
			
		||||
                            } catch (Exception e) {
 | 
			
		||||
                                log.error("Unable to load lwm2m model [{}]", path.toString());
 | 
			
		||||
                                throw new RuntimeException("Unable to load lwm2m model", e);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            );
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks");
 | 
			
		||||
                        try {
 | 
			
		||||
                            Resource resource = new Resource();
 | 
			
		||||
                            resource.setTenantId(TenantId.SYS_TENANT_ID);
 | 
			
		||||
                            resource.setResourceType(ResourceType.JKS);
 | 
			
		||||
                            resource.setResourceId(jksPath.getFileName().toString());
 | 
			
		||||
                            resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
 | 
			
		||||
                            resourceService.saveResource(resource);
 | 
			
		||||
                        } catch (Exception e) {
 | 
			
		||||
                            log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
 | 
			
		||||
                            throw new RuntimeException("Unable to load l2m2m serverKeyStore", e);
 | 
			
		||||
                        }
 | 
			
		||||
        try {
 | 
			
		||||
            Resource resource = new Resource();
 | 
			
		||||
            resource.setTenantId(TenantId.SYS_TENANT_ID);
 | 
			
		||||
            resource.setResourceType(ResourceType.JKS);
 | 
			
		||||
            resource.setResourceId(jksPath.getFileName().toString());
 | 
			
		||||
            resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
 | 
			
		||||
            resourceService.saveResource(resource);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
 | 
			
		||||
            throw new RuntimeException("Unable to load l2m2m serverKeyStore", e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getObjectModelLwm2mValid(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) {
 | 
			
		||||
        try {
 | 
			
		||||
            DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator);
 | 
			
		||||
            ObjectModel objectModel = ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0);
 | 
			
		||||
            return objectModel.id + "##" + objectModel.getVersion();
 | 
			
		||||
        } catch (IOException | InvalidDDFFileException e) {
 | 
			
		||||
            log.error("Could not parse the XML file [{}]", streamName, e);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void removeFile(Path modelsDir, String nameFile, byte[] fileBytes) {
 | 
			
		||||
        String path = "/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/";
 | 
			
		||||
        File file = new File(path + nameFile);
 | 
			
		||||
        if (!file.isDirectory()) {
 | 
			
		||||
            try {
 | 
			
		||||
                Files.write(Paths.get(path + "server/" + nameFile), fileBytes);
 | 
			
		||||
                file.delete();
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
                e.printStackTrace();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
 | 
			
		||||
import org.eclipse.leshan.core.model.StaticModel;
 | 
			
		||||
import org.eclipse.leshan.core.util.Hex;
 | 
			
		||||
import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
 | 
			
		||||
import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
 | 
			
		||||
@ -94,7 +93,7 @@ public class LwM2MTransportBootstrapServerConfiguration {
 | 
			
		||||
        builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort));
 | 
			
		||||
 | 
			
		||||
        /** Define model provider (Create Models )*/
 | 
			
		||||
        builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon()));
 | 
			
		||||
//        builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon()));
 | 
			
		||||
 | 
			
		||||
        /**  Create credentials */
 | 
			
		||||
        this.setServerWithCredentials(builder);
 | 
			
		||||
 | 
			
		||||
@ -16,13 +16,13 @@
 | 
			
		||||
package org.thingsboard.server.transport.lwm2m.server;
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2020 The Thingsboard Authors
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 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
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * <p>
 | 
			
		||||
 * 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.
 | 
			
		||||
@ -34,9 +34,13 @@ import com.google.gson.JsonElement;
 | 
			
		||||
import com.google.gson.JsonObject;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.eclipse.leshan.core.model.DDFFileParser;
 | 
			
		||||
import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
 | 
			
		||||
import org.eclipse.leshan.core.model.InvalidDDFFileException;
 | 
			
		||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.thingsboard.server.common.transport.TransportContext;
 | 
			
		||||
import org.thingsboard.server.common.transport.TransportResourceCache;
 | 
			
		||||
import org.thingsboard.server.common.transport.TransportService;
 | 
			
		||||
import org.thingsboard.server.common.transport.TransportServiceCallback;
 | 
			
		||||
import org.thingsboard.server.common.transport.adaptor.AdaptorException;
 | 
			
		||||
@ -48,7 +52,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCreden
 | 
			
		||||
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
 | 
			
		||||
import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.io.ByteArrayInputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
 | 
			
		||||
 | 
			
		||||
@ -62,14 +67,16 @@ public class LwM2mTransportContextServer extends TransportContext {
 | 
			
		||||
 | 
			
		||||
    private final TransportService transportService;
 | 
			
		||||
 | 
			
		||||
    private List<ObjectModel> modelsValueServer;
 | 
			
		||||
    private final TransportResourceCache transportResourceCache;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    private final LwM2MJsonAdaptor adaptor;
 | 
			
		||||
 | 
			
		||||
    public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, LwM2MJsonAdaptor adaptor) {
 | 
			
		||||
    public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, TransportResourceCache transportResourceCache, LwM2MJsonAdaptor adaptor) {
 | 
			
		||||
        this.lwM2MTransportConfigServer = lwM2MTransportConfigServer;
 | 
			
		||||
        this.transportService = transportService;
 | 
			
		||||
        this.transportResourceCache = transportResourceCache;
 | 
			
		||||
        this.adaptor = adaptor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -77,6 +84,10 @@ public class LwM2mTransportContextServer extends TransportContext {
 | 
			
		||||
        return this.lwM2MTransportConfigServer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public TransportResourceCache getTransportResourceCache() {
 | 
			
		||||
        return this.transportResourceCache;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sent to Thingsboard Attribute || Telemetry
 | 
			
		||||
     *
 | 
			
		||||
@ -139,59 +150,13 @@ public class LwM2mTransportContextServer extends TransportContext {
 | 
			
		||||
                .build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//    /**
 | 
			
		||||
//     * ResourcesRequestMsg
 | 
			
		||||
//     *
 | 
			
		||||
//     * @param resourceType
 | 
			
		||||
//     * @return
 | 
			
		||||
//     */
 | 
			
		||||
//    public GetResourcesResponseMsg getResourceTenant (UUID tenantId, String resourceType) {
 | 
			
		||||
//        CountDownLatch latch = new CountDownLatch(1);
 | 
			
		||||
//        GetResourcesResponseMsg responseMsg =
 | 
			
		||||
//                this.getTransportService()
 | 
			
		||||
//                        .getResources(GetResourcesRequestMsg.newBuilder()
 | 
			
		||||
//                                .setResourceType(resourceType)
 | 
			
		||||
//                                .setTenantIdLSB(tenantId.getLeastSignificantBits())
 | 
			
		||||
//                                .setTenantIdMSB(tenantId.getMostSignificantBits())
 | 
			
		||||
//                                .build());
 | 
			
		||||
//        latch.countDown();
 | 
			
		||||
//        try {
 | 
			
		||||
//            latch.await(this.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS);
 | 
			
		||||
//        } catch (InterruptedException e) {
 | 
			
		||||
//            log.error("Failed to await credentials!", e);
 | 
			
		||||
//        }
 | 
			
		||||
//
 | 
			
		||||
//        return responseMsg;
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
//    public GetResourcesResponseMsg getResourceTenantProcess (UUID tenantId, String resourceType) {
 | 
			
		||||
//        CountDownLatch latch = new CountDownLatch(2);
 | 
			
		||||
//        final GetResourcesResponseMsg[] responseMsg = {null};
 | 
			
		||||
//        this.getTransportService().process(GetResourcesRequestMsg.newBuilder()
 | 
			
		||||
//                        .setResourceType(resourceType)
 | 
			
		||||
//                        .setTenantIdLSB(tenantId.getLeastSignificantBits())
 | 
			
		||||
//                        .setTenantIdMSB(tenantId.getMostSignificantBits())
 | 
			
		||||
//                        .build(),
 | 
			
		||||
//                new TransportServiceCallback<>() {
 | 
			
		||||
//                    @Override
 | 
			
		||||
//                    public void onSuccess(GetResourcesResponseMsg msg) { responseMsg[0] = msg;
 | 
			
		||||
//                        latch.countDown();
 | 
			
		||||
//                    }
 | 
			
		||||
//
 | 
			
		||||
//                    @Override
 | 
			
		||||
//                    public void onError(Throwable e) {
 | 
			
		||||
//                        log.trace("[{}] [{}] Failed to process credentials ", tenantId, e);
 | 
			
		||||
//                        latch.countDown();
 | 
			
		||||
//                    }
 | 
			
		||||
//                });
 | 
			
		||||
//        try {
 | 
			
		||||
//            latch.await(this.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS);
 | 
			
		||||
//        } catch (InterruptedException e) {
 | 
			
		||||
//            log.error("Failed to await credentials!", e);
 | 
			
		||||
//        }
 | 
			
		||||
//        return responseMsg[0];
 | 
			
		||||
//    }
 | 
			
		||||
    public ObjectModel parseFromXmlToObjectModel(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) {
 | 
			
		||||
        try {
 | 
			
		||||
            DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator);
 | 
			
		||||
            return ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0);
 | 
			
		||||
        } catch (IOException | InvalidDDFFileException e) {
 | 
			
		||||
            log.error("Could not parse the XML file [{}]", streamName, e);
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,7 @@ import org.eclipse.leshan.server.californium.LeshanServerBuilder;
 | 
			
		||||
import org.nustaq.serialization.FSTConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceProfile;
 | 
			
		||||
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.transport.TransportServiceCallback;
 | 
			
		||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
 | 
			
		||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
 | 
			
		||||
@ -45,7 +46,6 @@ import java.util.Arrays;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
//@Component("LwM2MTransportHandler")
 | 
			
		||||
@ -189,7 +189,7 @@ public class LwM2mTransportHandler {
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, UUID tenantId) {
 | 
			
		||||
    public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
 | 
			
		||||
        LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
 | 
			
		||||
        lwM2MClientProfile.setTenantId(tenantId);
 | 
			
		||||
        lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject());
 | 
			
		||||
@ -223,7 +223,7 @@ public class LwM2mTransportHandler {
 | 
			
		||||
                ObjectMapper mapper = new ObjectMapper();
 | 
			
		||||
                String profileStr = mapper.writeValueAsString(profile);
 | 
			
		||||
                JsonObject profileJson = (profileStr  != null) ? validateJson(profileStr) : null;
 | 
			
		||||
                return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId().getId()) : null;
 | 
			
		||||
                return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
 | 
			
		||||
            } catch (IOException e) {
 | 
			
		||||
                log.error("", e);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -87,9 +87,6 @@ public class LwM2mTransportRequest {
 | 
			
		||||
 | 
			
		||||
    private final LeshanServer leshanServer;
 | 
			
		||||
 | 
			
		||||
//    @Autowired
 | 
			
		||||
//    private LwM2mTransportServiceImpl serviceImpl;
 | 
			
		||||
 | 
			
		||||
    private final LwM2mTransportServiceImpl serviceImpl;
 | 
			
		||||
 | 
			
		||||
    public LwM2mTransportRequest(LwM2mTransportContextServer context, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) {
 | 
			
		||||
@ -232,6 +229,7 @@ public class LwM2mTransportRequest {
 | 
			
		||||
    private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) {
 | 
			
		||||
        LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
 | 
			
		||||
        leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
 | 
			
		||||
 | 
			
		||||
            if (!lwM2MClient.isInit()) {
 | 
			
		||||
                lwM2MClient.initValue(this.serviceImpl, request.getPath().toString());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -27,7 +27,6 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider;
 | 
			
		||||
import org.eclipse.leshan.server.security.DefaultAuthorizer;
 | 
			
		||||
import org.eclipse.leshan.server.security.EditableSecurityStore;
 | 
			
		||||
import org.eclipse.leshan.server.security.SecurityChecker;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.context.annotation.Bean;
 | 
			
		||||
import org.springframework.stereotype.Component;
 | 
			
		||||
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
 | 
			
		||||
@ -61,24 +60,23 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_W
 | 
			
		||||
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Component("LwM2MTransportServerConfiguration")
 | 
			
		||||
@Component
 | 
			
		||||
@TbLwM2mTransportComponent
 | 
			
		||||
public class LwM2mTransportServerConfiguration {
 | 
			
		||||
    private PublicKey publicKey;
 | 
			
		||||
    private PrivateKey privateKey;
 | 
			
		||||
    private boolean pskMode = false;
 | 
			
		||||
    private final LwM2mTransportContextServer context;
 | 
			
		||||
    private final CaliforniumRegistrationStore registrationStore;
 | 
			
		||||
    private final EditableSecurityStore securityStore;
 | 
			
		||||
    private final LwM2mClientContext lwM2mClientContext;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private LwM2mTransportContextServer context;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private CaliforniumRegistrationStore registrationStore;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private EditableSecurityStore securityStore;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private LwM2mClientContext lwM2mClientContext;;
 | 
			
		||||
    public LwM2mTransportServerConfiguration(LwM2mTransportContextServer context, CaliforniumRegistrationStore registrationStore, EditableSecurityStore securityStore, LwM2mClientContext lwM2mClientContext) {
 | 
			
		||||
        this.context = context;
 | 
			
		||||
        this.registrationStore = registrationStore;
 | 
			
		||||
        this.securityStore = securityStore;
 | 
			
		||||
        this.lwM2mClientContext = lwM2mClientContext;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Bean
 | 
			
		||||
    public LeshanServer getLeshanServer() {
 | 
			
		||||
@ -98,10 +96,8 @@ public class LwM2mTransportServerConfiguration {
 | 
			
		||||
        builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort));
 | 
			
		||||
 | 
			
		||||
        /** Define model provider (Create Models )*/
 | 
			
		||||
//        TransportProtos.GetResourcesResponseMsg responseMsg= this.context.getResourceTenantProcess(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
 | 
			
		||||
//        TransportProtos.GetResourcesResponseMsg responseMsg= this.context.getResourceTenant(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
 | 
			
		||||
//        LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValueCommon());
 | 
			
		||||
        LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValueServer(), this.lwM2mClientContext);
 | 
			
		||||
        LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.context);
 | 
			
		||||
        this.context.getLwM2MTransportConfigServer().setModelProvider(modelProvider);
 | 
			
		||||
        builder.setObjectModelProvider(modelProvider);
 | 
			
		||||
 | 
			
		||||
        /**  Create credentials */
 | 
			
		||||
 | 
			
		||||
@ -153,11 +153,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
 | 
			
		||||
        executorRegistered.submit(() -> {
 | 
			
		||||
            try {
 | 
			
		||||
                log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
 | 
			
		||||
                ((LwM2mVersionedModelProvider)leshanServer.getModelProvider()).setRepository(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelsValueCommon());
 | 
			
		||||
//                TransportProtos.GetResourcesResponseMsg responseMsg= this.lwM2mTransportContextServer.getResourceTenantProcess(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
 | 
			
		||||
//                TransportProtos.GetResourcesResponseMsg responseMsg= this.lwM2mTransportContextServer.getResourceTenant(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
 | 
			
		||||
 | 
			
		||||
                //                (((VersionedModelProvider) (leshanServer)).modelProvider).repository;
 | 
			
		||||
                LwM2mClient lwM2MClient = this.lwM2mClientContext.updateInSessionsLwM2MClient(registration);
 | 
			
		||||
                if (lwM2MClient != null) {
 | 
			
		||||
                    SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
 | 
			
		||||
@ -657,21 +652,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
 | 
			
		||||
        return (clientInstances.size() > 0) ? clientInstances : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
//    /**
 | 
			
		||||
//     * get AttrName/TelemetryName with value from Client
 | 
			
		||||
//     *
 | 
			
		||||
//     * @param registration -
 | 
			
		||||
//     * @return - JsonObject, format: {name: value}}
 | 
			
		||||
//     */
 | 
			
		||||
//    private JsonObject getAttributeClient(Registration registration) {
 | 
			
		||||
//        if (registration.getAdditionalRegistrationAttributes().size() > 0) {
 | 
			
		||||
//            JsonObject resNameValues = new JsonObject();
 | 
			
		||||
//            registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty);
 | 
			
		||||
//            return resNameValues;
 | 
			
		||||
//        }
 | 
			
		||||
//        return null;
 | 
			
		||||
//    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param attributes   - new JsonObject
 | 
			
		||||
     * @param telemetry    - new JsonObject
 | 
			
		||||
 | 
			
		||||
@ -15,100 +15,122 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.thingsboard.server.transport.lwm2m.server;
 | 
			
		||||
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
 | 
			
		||||
import org.eclipse.leshan.core.model.LwM2mModel;
 | 
			
		||||
import org.eclipse.leshan.core.model.LwM2mModelRepository;
 | 
			
		||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
			
		||||
import org.eclipse.leshan.core.model.ResourceModel;
 | 
			
		||||
import org.eclipse.leshan.server.model.LwM2mModelProvider;
 | 
			
		||||
import org.eclipse.leshan.server.registration.Registration;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Base64;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Iterator;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
 | 
			
		||||
public class LwM2mVersionedModelProvider  implements LwM2mModelProvider {
 | 
			
		||||
import static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL;
 | 
			
		||||
 | 
			
		||||
    private LwM2mModelRepository repository;
 | 
			
		||||
    private Map<String, LwM2mModelRepository> repositoriesTenant;
 | 
			
		||||
    private LwM2mClientContext lwM2mClientContext;
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
 | 
			
		||||
 | 
			
		||||
    public LwM2mVersionedModelProvider(Collection<ObjectModel> objectModels, LwM2mClientContext lwM2mClientContext) {
 | 
			
		||||
        this.repository = new LwM2mModelRepository(objectModels);
 | 
			
		||||
    /**
 | 
			
		||||
     * int objectId
 | 
			
		||||
     * String version ("1.01")
 | 
			
		||||
     * Key = objectId + "##" + version
 | 
			
		||||
     * Value = TenantId
 | 
			
		||||
     */
 | 
			
		||||
    private final LwM2mClientContext lwM2mClientContext;
 | 
			
		||||
    private final LwM2mTransportContextServer lwM2mTransportContextServer;
 | 
			
		||||
 | 
			
		||||
    public LwM2mVersionedModelProvider(LwM2mClientContext lwM2mClientContext, LwM2mTransportContextServer lwM2mTransportContextServer) {
 | 
			
		||||
        this.lwM2mClientContext = lwM2mClientContext;
 | 
			
		||||
        this.repositoriesTenant = new ConcurrentHashMap<>();
 | 
			
		||||
        this.lwM2mTransportContextServer = lwM2mTransportContextServer;
 | 
			
		||||
    }
 | 
			
		||||
    private String getIdVer(ObjectModel objectModel) {
 | 
			
		||||
        return objectModel.id + "##" + ((objectModel.getVersion() == null || objectModel.getVersion().isEmpty()) ? ObjectModel.DEFAULT_VERSION : objectModel.getVersion());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LwM2mVersionedModelProvider(LwM2mModelRepository repository, LwM2mClientContext lwM2mClientContext) {
 | 
			
		||||
        this.repository = repository;
 | 
			
		||||
        this.lwM2mClientContext = lwM2mClientContext;
 | 
			
		||||
        this.repositoriesTenant = new ConcurrentHashMap<>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRepositoriesTenant (String tenantID, LwM2mModelRepository repositoryTenant) {
 | 
			
		||||
        this.repositoriesTenant.put(tenantID, repositoryTenant);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LwM2mModelRepository getRepositoriesTenant (String tenantID) {
 | 
			
		||||
        return this.repositoriesTenant.get(tenantID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRepository (Collection<ObjectModel> objectModels) {
 | 
			
		||||
        this.repository = new LwM2mModelRepository(objectModels);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LwM2mModelRepository getRepositoriesCommonTenant (String tenantID) {
 | 
			
		||||
        LwM2mModelRepository repository = new LwM2mModelRepository();
 | 
			
		||||
 | 
			
		||||
        return repository;
 | 
			
		||||
    private String getIdVer(Integer objectId, String version) {
 | 
			
		||||
        return objectId != null ? objectId + "##" + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update repository if need
 | 
			
		||||
     *
 | 
			
		||||
     * @param registration
 | 
			
		||||
     * @return
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public LwM2mModel getObjectModel(Registration registration) {
 | 
			
		||||
        return new DynamicModel(registration, this.lwM2mClientContext.getProfile(registration).getTenantId());
 | 
			
		||||
        return new DynamicModel(registration
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class DynamicModel implements LwM2mModel {
 | 
			
		||||
 | 
			
		||||
        private final Registration registration;
 | 
			
		||||
        private final UUID tenantId;
 | 
			
		||||
        private final TenantId tenantId;
 | 
			
		||||
 | 
			
		||||
        public DynamicModel(Registration registration, UUID tenantId) {
 | 
			
		||||
        public DynamicModel(Registration registration) {
 | 
			
		||||
            this.registration = registration;
 | 
			
		||||
            this.tenantId = tenantId;
 | 
			
		||||
            this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public ResourceModel getResourceModel(int objectId, int resourceId) {
 | 
			
		||||
            ObjectModel objectModel = getObjectModel(objectId);
 | 
			
		||||
            if (objectModel != null)
 | 
			
		||||
                return objectModel.resources.get(resourceId);
 | 
			
		||||
            else
 | 
			
		||||
            try {
 | 
			
		||||
                ObjectModel objectModel = getObjectModel(objectId);
 | 
			
		||||
                if (objectModel != null)
 | 
			
		||||
                    return objectModel.resources.get(resourceId);
 | 
			
		||||
                else
 | 
			
		||||
                    return null;
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                log.error("", e);
 | 
			
		||||
                return null;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public ObjectModel getObjectModel(int objectId) {
 | 
			
		||||
            String version = registration.getSupportedVersion(objectId);
 | 
			
		||||
            if (version != null) {
 | 
			
		||||
                return repository.getObjectModel(objectId, version);
 | 
			
		||||
                return this.getObjectModelDynamic(objectId, version);
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public Collection<ObjectModel> getObjectModels() {
 | 
			
		||||
            Map<Integer, String> supportedObjects = registration.getSupportedObject();
 | 
			
		||||
            Collection<ObjectModel> result = new ArrayList<>(supportedObjects.size());
 | 
			
		||||
            for (Map.Entry<Integer, String> supportedObject : supportedObjects.entrySet()) {
 | 
			
		||||
                ObjectModel objectModel = repository.getObjectModel(supportedObject.getKey(),
 | 
			
		||||
                        supportedObject.getValue());
 | 
			
		||||
                if (objectModel != null)
 | 
			
		||||
            Map<Integer, String> supportedObjects = this.registration.getSupportedObject();
 | 
			
		||||
            Collection<ObjectModel> result = new ArrayList(supportedObjects.size());
 | 
			
		||||
            Iterator i$ = supportedObjects.entrySet().iterator();
 | 
			
		||||
 | 
			
		||||
            while (i$.hasNext()) {
 | 
			
		||||
                Map.Entry<Integer, String> supportedObject = (Map.Entry) i$.next();
 | 
			
		||||
                ObjectModel objectModel = this.getObjectModelDynamic((Integer) supportedObject.getKey(), (String) supportedObject.getValue());
 | 
			
		||||
                if (objectModel != null) {
 | 
			
		||||
                    result.add(objectModel);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private ObjectModel getObjectModelDynamic(Integer objectId, String version) {
 | 
			
		||||
            String key = getIdVer(objectId, version);
 | 
			
		||||
            String xmlB64 = lwM2mTransportContextServer.getTransportResourceCache().get(
 | 
			
		||||
                    this.tenantId,
 | 
			
		||||
                    LWM2M_MODEL,
 | 
			
		||||
                    key).
 | 
			
		||||
                    getValue();
 | 
			
		||||
            return xmlB64 != null && !xmlB64.isEmpty() ?
 | 
			
		||||
                    lwM2mTransportContextServer.parseFromXmlToObjectModel(
 | 
			
		||||
                            Base64.getDecoder().decode(xmlB64),
 | 
			
		||||
                            key + ".xml",
 | 
			
		||||
                            new DefaultDDFFileValidator()) :
 | 
			
		||||
                    null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -168,5 +168,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,13 +19,12 @@ import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.JsonArray;
 | 
			
		||||
import com.google.gson.JsonObject;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
public class LwM2mClientProfile {
 | 
			
		||||
 | 
			
		||||
    private UUID tenantId;
 | 
			
		||||
    private TenantId tenantId;
 | 
			
		||||
    /**
 | 
			
		||||
     * {"clientLwM2mSettings": {
 | 
			
		||||
     *      clientUpdateValueAfterConnect: false;
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,8 @@ import java.text.DateFormat;
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class LwM2mValueConverterImpl implements LwM2mValueConverter {
 | 
			
		||||
 | 
			
		||||
@ -52,6 +54,9 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
 | 
			
		||||
            /** expected type */
 | 
			
		||||
            return value;
 | 
			
		||||
        }
 | 
			
		||||
        if (currentType == null) {
 | 
			
		||||
            currentType = OPAQUE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (expectedType) {
 | 
			
		||||
            case INTEGER:
 | 
			
		||||
 | 
			
		||||
@ -18,10 +18,10 @@ package org.thingsboard.server.common.transport.lwm2m;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import org.eclipse.leshan.core.model.ObjectLoader;
 | 
			
		||||
import org.eclipse.leshan.core.model.ObjectModel;
 | 
			
		||||
import org.eclipse.leshan.core.model.ResourceModel;
 | 
			
		||||
import org.eclipse.leshan.core.node.LwM2mPath;
 | 
			
		||||
import org.eclipse.leshan.server.model.LwM2mModelProvider;
 | 
			
		||||
import org.eclipse.leshan.server.registration.Registration;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value;
 | 
			
		||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
 | 
			
		||||
@ -38,9 +38,7 @@ import java.security.KeyStore;
 | 
			
		||||
import java.security.KeyStoreException;
 | 
			
		||||
import java.security.NoSuchAlgorithmException;
 | 
			
		||||
import java.security.cert.CertificateException;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
@Slf4j
 | 
			
		||||
@Component
 | 
			
		||||
@ -87,7 +85,7 @@ public class LwM2MTransportConfigServer {
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    @Setter
 | 
			
		||||
    private List<ObjectModel> modelsValueServer;
 | 
			
		||||
    private LwM2mModelProvider modelProvider;
 | 
			
		||||
 | 
			
		||||
    @Getter
 | 
			
		||||
    @Value("${transport.lwm2m.timeout:}")
 | 
			
		||||
@ -189,35 +187,11 @@ public class LwM2MTransportConfigServer {
 | 
			
		||||
    @Value("${transport.lwm2m.server.secure.alias:}")
 | 
			
		||||
    private String serverAlias;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void init() {
 | 
			
		||||
        modelsValueServer = ObjectLoader.loadDefault();
 | 
			
		||||
        modelsValueServer.remove(3);
 | 
			
		||||
        modelsValueCommon = ObjectLoader.loadDefault();
 | 
			
		||||
        File path = getPathModels();
 | 
			
		||||
        if (path.isDirectory()) {
 | 
			
		||||
            try {
 | 
			
		||||
                modelsValueCommon.addAll(ObjectLoader.loadObjectsFromDir(path));
 | 
			
		||||
                log.info(" [{}] Models directory is a directory", path.getAbsoluteFile());
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                log.error(" [{}] Could not parse the resource definition file", e.toString());
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            log.error(" [{}] Read Models", path.getAbsoluteFile());
 | 
			
		||||
        }
 | 
			
		||||
        this.getInKeyStore();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private File getPathModels() {
 | 
			
		||||
        Path pathModels = (modelPathFile != null && !modelPathFile.isEmpty()) ? Paths.get(modelPathFile) :
 | 
			
		||||
                (new File(Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT).toUri()).isDirectory()) ?
 | 
			
		||||
                        Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT) :
 | 
			
		||||
                        Paths.get(getBaseDirPath(), APP_DIR, TRANSPORT_DIR, LWM2M_DIR, SRC_DIR, MAIN_DIR, RESOURCES_DIR, MODEL_PATH_DEFAULT);
 | 
			
		||||
        return (pathModels != null) ? new File(pathModels.toUri()) : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private KeyStore getInKeyStore() {
 | 
			
		||||
        try {
 | 
			
		||||
            if (keyStoreValue != null && keyStoreValue.size() > 0)
 | 
			
		||||
@ -260,12 +234,7 @@ public class LwM2MTransportConfigServer {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) {
 | 
			
		||||
        String pathLink = "/" + pathIds.getObjectId() + "/" + pathIds.getObjectInstanceId();
 | 
			
		||||
        return (Arrays.stream(registration.getObjectLinks()).filter(p-> p.getUrl().equals(pathLink)).findFirst().isPresent() &&
 | 
			
		||||
                this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).size() > 0) &&
 | 
			
		||||
                this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.containsKey(pathIds.getResourceId()) ?
 | 
			
		||||
                this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.get(pathIds.getResourceId()) :
 | 
			
		||||
                null;
 | 
			
		||||
        return this.modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								pom.xml
									
									
									
									
									
								
							@ -66,9 +66,9 @@
 | 
			
		||||
        <jackson-core.version>2.12.1</jackson-core.version>
 | 
			
		||||
        <json-schema-validator.version>2.2.6</json-schema-validator.version>
 | 
			
		||||
        <californium.version>2.6.1</californium.version>
 | 
			
		||||
        <leshan-server.version>1.3.0</leshan-server.version>
 | 
			
		||||
        <leshan-core.version>1.3.0</leshan-core.version>
 | 
			
		||||
        <leshan-client.version>1.3.0</leshan-client.version>
 | 
			
		||||
        <leshan-server.version>1.3.1</leshan-server.version>
 | 
			
		||||
        <leshan-core.version>1.3.1</leshan-core.version>
 | 
			
		||||
        <leshan-client.version>1.3.1</leshan-client.version>
 | 
			
		||||
        <gson.version>2.6.2</gson.version>
 | 
			
		||||
        <freemarker.version>2.3.30</freemarker.version>
 | 
			
		||||
        <mail.version>1.6.2</mail.version>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user