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