Lwm2m Fix bug review 1-10
This commit is contained in:
parent
9651b93574
commit
f86a30a8ed
@ -126,7 +126,6 @@ import org.thingsboard.server.service.component.ComponentDiscoveryService;
|
||||
import org.thingsboard.server.service.edge.EdgeLicenseService;
|
||||
import org.thingsboard.server.service.edge.EdgeNotificationService;
|
||||
import org.thingsboard.server.service.edge.rpc.EdgeRpcService;
|
||||
import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl;
|
||||
import org.thingsboard.server.service.ota.OtaPackageStateService;
|
||||
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
|
||||
import org.thingsboard.server.service.resource.TbResourceService;
|
||||
@ -185,9 +184,6 @@ public abstract class BaseController {
|
||||
@Autowired
|
||||
protected DeviceProfileService deviceProfileService;
|
||||
|
||||
@Autowired
|
||||
protected LwM2MServiceImpl lwM2MService;
|
||||
|
||||
@Autowired
|
||||
protected AssetService assetService;
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -31,6 +32,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
|
||||
import org.thingsboard.server.common.data.lwm2m.ServerSecurityConfig;
|
||||
import org.thingsboard.server.common.data.security.DeviceCredentials;
|
||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||
import org.thingsboard.server.service.lwm2m.LwM2MServiceImpl;
|
||||
import org.thingsboard.server.service.security.permission.Resource;
|
||||
|
||||
import java.util.Map;
|
||||
@ -41,6 +43,9 @@ import java.util.Map;
|
||||
@RequestMapping("/api")
|
||||
public class Lwm2mController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
protected LwM2MServiceImpl lwM2MService;
|
||||
|
||||
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
|
||||
@RequestMapping(value = "/lwm2m/deviceProfile/bootstrap/{isBootstrapServer}", method = RequestMethod.GET)
|
||||
@ResponseBody
|
||||
|
||||
@ -693,6 +693,8 @@ transport:
|
||||
ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}"
|
||||
clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
|
||||
log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}"
|
||||
psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}"
|
||||
paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}"
|
||||
# Use redis for Security and Registration stores
|
||||
redis.enabled: "${LWM2M_REDIS_ENABLED:false}"
|
||||
snmp:
|
||||
|
||||
@ -83,7 +83,7 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
|
||||
|
||||
@Override
|
||||
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) {
|
||||
log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
|
||||
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
|
||||
|
||||
switch (resourceId) {
|
||||
case 0:
|
||||
|
||||
@ -83,7 +83,7 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable {
|
||||
|
||||
@Override
|
||||
public WriteResponse write(ServerIdentity identity, boolean replace, int resourceId, LwM2mResource value) {
|
||||
log.warn("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
|
||||
log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceId);
|
||||
|
||||
switch (resourceId) {
|
||||
case 2:
|
||||
|
||||
@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.thingsboard.server.common.data.security;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.thingsboard.server.common.data.BaseData;
|
||||
import org.thingsboard.server.common.data.id.DeviceCredentialsId;
|
||||
|
||||
@ -17,6 +17,8 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.eclipse.leshan.core.SecurityMode;
|
||||
import org.eclipse.leshan.core.request.BindingMode;
|
||||
import org.eclipse.leshan.core.util.Hex;
|
||||
@ -41,7 +43,9 @@ public class LwM2MBootstrapConfig implements Serializable {
|
||||
* notifIfDisabled: boolean,
|
||||
* binding: string
|
||||
* */
|
||||
LwM2MBootstrapServers servers;
|
||||
@Getter
|
||||
@Setter
|
||||
private LwM2MBootstrapServers servers;
|
||||
|
||||
/** -bootstrapServer, lwm2mServer
|
||||
* interface ServerSecurityConfig
|
||||
@ -56,9 +60,13 @@ public class LwM2MBootstrapConfig implements Serializable {
|
||||
* serverId?: number,
|
||||
* bootstrapServerAccountTimeout: number
|
||||
* */
|
||||
LwM2MServerBootstrap bootstrapServer;
|
||||
@Getter
|
||||
@Setter
|
||||
private LwM2MServerBootstrap bootstrapServer;
|
||||
|
||||
LwM2MServerBootstrap lwm2mServer;
|
||||
@Getter
|
||||
@Setter
|
||||
private LwM2MServerBootstrap lwm2mServer;
|
||||
|
||||
@JsonIgnore
|
||||
public BootstrapConfig getLwM2MBootstrapConfig() {
|
||||
|
||||
@ -43,11 +43,11 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP;
|
||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR;
|
||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_INFO;
|
||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_TELEMETRY;
|
||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.getBootstrapParametersFromThingsboard;
|
||||
import static org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mTypeServer.BOOTSTRAP;
|
||||
|
||||
@Slf4j
|
||||
@Service("LwM2MBootstrapSecurityStore")
|
||||
@ -86,10 +86,10 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
bootstrapConfigStore.add(endPoint, bsConfigNew);
|
||||
} catch (InvalidConfigurationException e) {
|
||||
if (e.getMessage().contains("Psk identity") && e.getMessage().contains("already used for this bootstrap server")) {
|
||||
log.trace("", e);
|
||||
log.trace("Invalid Bootstrap Configuration", e);
|
||||
}
|
||||
else {
|
||||
log.error("", e);
|
||||
log.error("Invalid Bootstrap Configuration", e);
|
||||
}
|
||||
}
|
||||
return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()).iterator();
|
||||
@ -109,7 +109,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
try {
|
||||
bootstrapConfigStore.add(store.getEndpoint(), bsConfig);
|
||||
} catch (InvalidConfigurationException e) {
|
||||
log.error("", e);
|
||||
log.error("Invalid Bootstrap Configuration", e);
|
||||
}
|
||||
return store.getSecurityInfo();
|
||||
}
|
||||
@ -158,11 +158,11 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig();
|
||||
if (lwM2MBootstrapConfig != null) {
|
||||
BootstrapConfiguration bootstrapObject = getBootstrapParametersFromThingsboard(store.getDeviceProfile());
|
||||
lwM2MBootstrapConfig.servers = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class);
|
||||
LwM2MServerBootstrap profileServerBootstrap = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class);
|
||||
if (SecurityMode.NO_SEC != profileServerBootstrap.getSecurityMode() && profileServerBootstrap != null) {
|
||||
profileServerBootstrap.setSecurityHost( profileServerBootstrap.getHost());
|
||||
profileServerBootstrap.setSecurityPort( profileServerBootstrap.getPort());
|
||||
lwM2MBootstrapConfig.setServers(JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getServers()), LwM2MBootstrapServers.class));
|
||||
LwM2MServerBootstrap bootstrapServerProfile = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getBootstrapServer()), LwM2MServerBootstrap.class);
|
||||
if (SecurityMode.NO_SEC != bootstrapServerProfile.getSecurityMode() && bootstrapServerProfile != null) {
|
||||
bootstrapServerProfile.setSecurityHost( bootstrapServerProfile.getHost());
|
||||
bootstrapServerProfile.setSecurityPort( bootstrapServerProfile.getPort());
|
||||
}
|
||||
LwM2MServerBootstrap profileLwm2mServer = JacksonUtil.fromString(JacksonUtil.toString(bootstrapObject.getLwm2mServer()), LwM2MServerBootstrap.class);
|
||||
if (SecurityMode.NO_SEC != profileLwm2mServer.getSecurityMode() && profileLwm2mServer != null) {
|
||||
@ -173,9 +173,9 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
TransportProtos.SessionInfoProto sessionInfo = helper.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits());
|
||||
bsSessions.put(store.getEndpoint(), sessionInfo);
|
||||
context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, null, null, sessionInfo, context.getTransportService()));
|
||||
if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) {
|
||||
lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap);
|
||||
lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer);
|
||||
if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile, lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer)) {
|
||||
lwM2MBootstrapConfig.setBootstrapServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getBootstrapServer(), bootstrapServerProfile));
|
||||
lwM2MBootstrapConfig.setLwm2mServer(new LwM2MServerBootstrap(lwM2MBootstrapConfig.getLwm2mServer(), profileLwm2mServer));
|
||||
String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LWM2M_INFO, store.getEndpoint());
|
||||
helper.sendParametersOnThingsboardTelemetry(helper.getKvStringtoThingsboard(LOG_LWM2M_TELEMETRY, logMsg), sessionInfo);
|
||||
return lwM2MBootstrapConfig;
|
||||
@ -187,7 +187,6 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
log.error("Unable to decode Json or Certificate for [{}]", store.getEndpoint());
|
||||
return null;
|
||||
}
|
||||
@ -197,13 +196,13 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
|
||||
* and (lwm2mServer in credential and lwm2mServer in profile
|
||||
*
|
||||
* @param bootstrapFromCredential - Bootstrap -> Security of bootstrapServer in credential
|
||||
* @param profileServerBootstrap - Bootstrap -> Security of bootstrapServer in profile
|
||||
* @param bootstrapServerProfile - Bootstrap -> Security of bootstrapServer in profile
|
||||
* @param lwm2mFromCredential - Bootstrap -> Security of lwm2mServer in credential
|
||||
* @param profileLwm2mServer - Bootstrap -> Security of lwm2mServer in profile
|
||||
* @return false if not sync between SecurityMode of Bootstrap credential and profile
|
||||
*/
|
||||
private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap profileServerBootstrap, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) {
|
||||
return (bootstrapFromCredential.getSecurityMode().equals(profileServerBootstrap.getSecurityMode()) &&
|
||||
private boolean getValidatedSecurityMode(LwM2MServerBootstrap bootstrapFromCredential, LwM2MServerBootstrap bootstrapServerProfile, LwM2MServerBootstrap lwm2mFromCredential, LwM2MServerBootstrap profileLwm2mServer) {
|
||||
return (bootstrapFromCredential.getSecurityMode().equals(bootstrapServerProfile.getSecurityMode()) &&
|
||||
lwm2mFromCredential.getSecurityMode().equals(profileLwm2mServer.getSecurityMode()));
|
||||
}
|
||||
|
||||
|
||||
@ -200,21 +200,20 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession
|
||||
public BootstrapPolicy onRequestFailure(BootstrapSession bsSession,
|
||||
BootstrapDownlinkRequest<? extends LwM2mResponse> request, Throwable cause) {
|
||||
this.sendLogs (bsSession.getEndpoint(),
|
||||
String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO,
|
||||
request.getClass().getSimpleName(), request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString()));
|
||||
String.format("%s: %s %s failed because of %s for %s : %s", LOG_LWM2M_INFO, request.getClass().getSimpleName(),
|
||||
request.getPath().toString(), cause.toString(), bsSession.toString(), request.toString()));
|
||||
return BootstrapPolicy.failed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(BootstrapSession bsSession) {
|
||||
this.sendLogs (bsSession.getEndpoint(),
|
||||
String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString()));
|
||||
this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session finished : %s", LOG_LWM2M_INFO, bsSession.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(BootstrapSession bsSession, BootstrapFailureCause cause) {
|
||||
this.sendLogs (bsSession.getEndpoint(),
|
||||
String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO, cause.toString(), bsSession.toString()));
|
||||
this.sendLogs (bsSession.getEndpoint(), String.format("%s: Bootstrap session failed by %s: %s", LOG_LWM2M_INFO,
|
||||
cause.toString(), bsSession.toString()));
|
||||
}
|
||||
|
||||
private void sendLogs (String endpointName, String logMsg) {
|
||||
|
||||
@ -50,16 +50,13 @@ public enum LwM2mOperationType {
|
||||
WRITE_COMPOSITE(14, "WriteComposite", false, true),
|
||||
WRITE_ATTRIBUTES(15, "WriteAttributes", true),
|
||||
DELETE(16, "Delete", true),
|
||||
|
||||
// only for RPC
|
||||
FW_UPDATE(17, "FirmwareUpdate", false),
|
||||
// FW_READ_INFO(18, "FirmwareReadInfo", false),
|
||||
SW_UPDATE(19, "SoftwareUpdate", false),
|
||||
// SW_READ_INFO(20, "SoftwareReadInfo", false),
|
||||
SW_UNINSTALL(21, "SoftwareUninstall", false),
|
||||
CREATE(11, "Create", true);
|
||||
|
||||
|
||||
CREATE(17, "Create", true);
|
||||
// only for RPC - future
|
||||
// FW_UPDATE(18, "FirmwareUpdate", false),
|
||||
// FW_READ_INFO(19, "FirmwareReadInfo", false),
|
||||
// SW_UPDATE(20, "SoftwareUpdate", false),
|
||||
// SW_READ_INFO(21, "SoftwareReadInfo", false),
|
||||
// SW_UNINSTALL(22, "SoftwareUninstall", false);
|
||||
|
||||
|
||||
@Getter
|
||||
|
||||
@ -98,7 +98,9 @@ public class LwM2mServerListener {
|
||||
|
||||
@Override
|
||||
public void onError(Observation observation, Registration registration, Exception error) {
|
||||
log.error("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage());
|
||||
if (error != null) {
|
||||
log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -51,7 +51,7 @@ import static org.thingsboard.server.gen.transport.TransportProtos.KeyValueType.
|
||||
public class LwM2mTransportServerHelper {
|
||||
|
||||
private final LwM2mTransportContext context;
|
||||
private final static JsonParser JSON_PARSER = new JsonParser();;
|
||||
private final static JsonParser JSON_PARSER = new JsonParser();
|
||||
|
||||
public void sendParametersOnThingsboardAttribute(List<TransportProtos.KeyValueProto> result, SessionInfoProto sessionInfo) {
|
||||
PostAttributeMsg.Builder request = PostAttributeMsg.newBuilder();
|
||||
@ -231,7 +231,11 @@ public class LwM2mTransportServerHelper {
|
||||
case STRING_V:
|
||||
return kv.getStringV();
|
||||
case JSON_V:
|
||||
return JSON_PARSER.parse(kv.getJsonV());
|
||||
try {
|
||||
return JSON_PARSER.parse(kv.getJsonV());
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -40,7 +40,6 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.LwM2mDownlinkMsgHa
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteReplaceRequest;
|
||||
import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteResponseCallback;
|
||||
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
|
||||
import org.thingsboard.server.transport.lwm2m.server.ota.DefaultLwM2MOtaUpdateService;
|
||||
import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService;
|
||||
import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler;
|
||||
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
|
||||
@ -225,7 +224,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
|
||||
this.pushUpdateToClientIfNeeded(lwM2MClient, oldResourceValue, newValProto, pathIdVer, logFailedUpdateOfNonChangedValue, resourceModel.type);
|
||||
} else {
|
||||
pushUpdateMultiToClientIfNeeded(lwM2MClient, resourceModel, (JsonElement) newValProto,
|
||||
(Map<Integer, LwM2mResourceInstance>) oldResourceValue, pathIdVer);
|
||||
(Map<Integer, LwM2mResourceInstance>) oldResourceValue, pathIdVer, logFailedUpdateOfNonChangedValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -251,7 +250,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
|
||||
}
|
||||
|
||||
private void pushUpdateMultiToClientIfNeeded(LwM2mClient client, ResourceModel resourceModel, JsonElement newValProto,
|
||||
Map<Integer, LwM2mResourceInstance> valueOld, String versionedId) {
|
||||
Map<Integer, LwM2mResourceInstance> valueOld, String versionedId, boolean logFailedUpdateOfNonChangedValue) {
|
||||
Map newValues = convertMultiResourceValuesFromJson((JsonObject) newValProto, resourceModel.type, versionedId);
|
||||
if (newValues.size() > 0 && valueOld != null && valueOld.size() > 0) {
|
||||
valueOld.values().stream().forEach((v) -> {
|
||||
@ -272,7 +271,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService {
|
||||
if (newValues.size() > 0) {
|
||||
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId).value(newValues).timeout(this.config.getTimeout()).build();
|
||||
downlinkHandler.sendWriteReplaceRequest(client, request, new TbLwM2MWriteResponseCallback(uplinkHandler, logService, client, versionedId));
|
||||
} else {
|
||||
} else if (logFailedUpdateOfNonChangedValue) {
|
||||
log.warn("Didn't update resource [{}] [{}]", versionedId, newValProto);
|
||||
String logMsg = String.format("%s: Didn't update resource versionedId - %s value - %s. Value is not changed",
|
||||
LOG_LWM2M_WARN, versionedId, newValProto);
|
||||
|
||||
@ -46,7 +46,6 @@ import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@ -106,7 +105,6 @@ public class LwM2mClient implements Serializable {
|
||||
@Getter
|
||||
private Long pagingTransmissionWindow;
|
||||
@Getter
|
||||
@Setter
|
||||
private Long edrxCycle;
|
||||
@Getter
|
||||
private Registration registration;
|
||||
@ -122,9 +120,9 @@ public class LwM2mClient implements Serializable {
|
||||
private boolean firstEdrxDownlink = true;
|
||||
|
||||
@Getter
|
||||
Set<ContentFormat> clientSupportContentFormats;
|
||||
private Set<ContentFormat> clientSupportContentFormats;
|
||||
@Getter
|
||||
ContentFormat defaultContentFormat;
|
||||
private ContentFormat defaultContentFormat;
|
||||
@Getter
|
||||
private final AtomicInteger retryAttempts;
|
||||
|
||||
@ -327,15 +325,18 @@ public class LwM2mClient implements Serializable {
|
||||
Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet();
|
||||
Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration)
|
||||
.getObjectModel(pathIds.getObjectId()).resources;
|
||||
if (params != null) {
|
||||
if (params != null && params instanceof Map && ((Map<?, ?>) params).size() > 0) {
|
||||
resourceModels.forEach((resourceId, resourceModel) -> {
|
||||
if (((Map) params).containsKey(String.valueOf(resourceId))) {
|
||||
Object value = ((Map) params).get((String.valueOf(resourceId)));
|
||||
LwM2mResource resource = null;
|
||||
LwM2mResource resource;
|
||||
if (resourceModel.multiple) {
|
||||
if (value instanceof LinkedHashMap) {
|
||||
Map values = convertMultiResourceValuesFromRpcBody((LinkedHashMap) value, resourceModel.type, pathRezIdVer);
|
||||
try {
|
||||
Map values = convertMultiResourceValuesFromRpcBody(value, resourceModel.type, pathRezIdVer);
|
||||
resource = LwM2mMultipleResource.newResource(resourceId, (Map<Integer, ?>) values, resourceModel.type);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Resource id=" + resourceId + ", value = " + value + ", class = " +
|
||||
value.getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!");
|
||||
}
|
||||
} else {
|
||||
Object valueRez = value.getClass().getSimpleName().equals("Integer") ? ((Integer) value).longValue() : value;
|
||||
@ -353,9 +354,12 @@ public class LwM2mClient implements Serializable {
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
else if (params == null) {
|
||||
throw new IllegalArgumentException("The value of this resource must not be null.");
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("The value of this resource must be in Map format and size > 0");
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
|
||||
import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService;
|
||||
|
||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_WARN;
|
||||
import static org.thingsboard.server.transport.lwm2m.utils.LwM2mTransportUtil.LOG_LWM2M_ERROR;
|
||||
|
||||
@Slf4j
|
||||
public abstract class AbstractTbLwM2MRequestCallback<R, T> implements DownlinkRequestCallback<R, T> {
|
||||
@ -35,12 +35,12 @@ public abstract class AbstractTbLwM2MRequestCallback<R, T> implements DownlinkRe
|
||||
@Override
|
||||
public void onValidationError(String params, String msg) {
|
||||
log.trace("[{}] Request [{}] validation failed. Reason: {}", client.getEndpoint(), params, msg);
|
||||
logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_WARN, params, msg));
|
||||
logService.log(client, String.format("[%s]: Request [%s] validation failed. Reason: %s", LOG_LWM2M_ERROR, params, msg));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(String params, Exception e) {
|
||||
log.trace("[{}] Request [{}] processing failed", client.getEndpoint(), params, e);
|
||||
logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_WARN, params, e));
|
||||
logService.log(client, String.format("[%s]: Request [%s] processing failed. Reason: %s", LOG_LWM2M_ERROR, params, e));
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.leshan.core.Link;
|
||||
import org.eclipse.leshan.core.LwM2m;
|
||||
import org.eclipse.leshan.core.ResponseCode;
|
||||
import org.eclipse.leshan.core.attributes.Attribute;
|
||||
import org.eclipse.leshan.core.attributes.AttributeSet;
|
||||
import org.eclipse.leshan.core.model.LwM2mModel;
|
||||
@ -79,7 +78,6 @@ import javax.annotation.PreDestroy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -302,11 +300,13 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
|
||||
try {
|
||||
WriteRequest downlink = null;
|
||||
if (resourceModelWrite.multiple) {
|
||||
if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) {
|
||||
try {
|
||||
Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
|
||||
downlink = new WriteRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(),
|
||||
(Map<Integer, ?>) request.getValue(), resourceModelWrite.type);
|
||||
} else {
|
||||
callback.onValidationError(toString(request), "Resource value is: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!");
|
||||
value, resourceModelWrite.type);
|
||||
} catch (Exception e) {
|
||||
callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() +
|
||||
", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!");
|
||||
}
|
||||
} else {
|
||||
downlink = this.getWriteRequestSingleResource(resourceModelWrite.type, contentFormat,
|
||||
@ -368,12 +368,12 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im
|
||||
ResourceModel resourceModelWrite = client.getResourceModel(request.getVersionedId(), this.config.getModelProvider());
|
||||
if (resourceModelWrite != null) {
|
||||
if (resourceModelWrite.multiple) {
|
||||
if (request.getValue() instanceof Map && ((Map) request.getValue()).size() > 0) {
|
||||
Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) request.getValue(), resourceModelWrite.type, request.getObjectId());
|
||||
try {
|
||||
Map value = convertMultiResourceValuesFromRpcBody(request.getValue(), resourceModelWrite.type, request.getObjectId());
|
||||
downlink = new WriteRequest(WriteRequest.Mode.UPDATE, contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId(),
|
||||
value, resourceModelWrite.type);
|
||||
} else {
|
||||
callback.onValidationError(toString(request), "Resource value is bad. Format: " + request.getValue().getClass().getSimpleName() + ". Value of Multi-Instance Resource must be in Json format!");
|
||||
} catch (Exception e1) {
|
||||
callback.onValidationError(toString(request), "Resource id=" + resultIds.toString() + ", value = " + request.getValue() + ", class = " + request.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -169,8 +169,6 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
|
||||
case DISCOVER_ALL:
|
||||
sendDiscoverAllRequest(client, rpcRequest);
|
||||
break;
|
||||
case FW_UPDATE:
|
||||
//TODO: implement and add break statement
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported operation: " + operationType.name());
|
||||
}
|
||||
@ -257,11 +255,16 @@ public class DefaultLwM2MRpcRequestHandler implements LwM2MRpcRequestHandler {
|
||||
private void sendWriteReplaceRequest(LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, String versionedId) {
|
||||
RpcWriteReplaceRequest requestBody = JacksonUtil.fromString(requestMsg.getParams(), RpcWriteReplaceRequest.class);
|
||||
LwM2mPath path = new LwM2mPath(fromVersionedIdToObjectId(versionedId));
|
||||
if (path.isResource() && requestBody.getValue() instanceof LinkedHashMap) {
|
||||
if (path.isResource()) {
|
||||
ResourceModel resourceModel = client.getResourceModel(versionedId, this.config.getModelProvider());
|
||||
if (resourceModel != null && resourceModel.multiple) {
|
||||
Map value = convertMultiResourceValuesFromRpcBody((LinkedHashMap) requestBody.getValue(), resourceModel.type, versionedId);
|
||||
requestBody.setValue(value);
|
||||
try {
|
||||
Map value = convertMultiResourceValuesFromRpcBody(requestBody.getValue(), resourceModel.type, versionedId);
|
||||
requestBody.setValue(value);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Resource id=" + versionedId + ", value = " + requestBody.getValue() + ", class = " +
|
||||
requestBody.getValue().getClass().getSimpleName() + "is bad. Value of Multi-Instance Resource must be in Json format!");
|
||||
}
|
||||
}
|
||||
}
|
||||
TbLwM2MWriteReplaceRequest request = TbLwM2MWriteReplaceRequest.builder().versionedId(versionedId)
|
||||
|
||||
@ -16,10 +16,7 @@
|
||||
package org.thingsboard.server.transport.lwm2m.utils;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.leshan.core.attributes.Attribute;
|
||||
@ -47,6 +44,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.data.ota.OtaPackageType;
|
||||
import org.thingsboard.server.common.transport.util.JsonUtils;
|
||||
import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion;
|
||||
import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert;
|
||||
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
|
||||
@ -57,18 +55,15 @@ import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdate
|
||||
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult;
|
||||
import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState;
|
||||
import org.thingsboard.server.transport.lwm2m.server.uplink.DefaultLwM2MUplinkMsgHandler;
|
||||
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static org.eclipse.leshan.core.attributes.Attribute.DIMENSION;
|
||||
import static org.eclipse.leshan.core.attributes.Attribute.GREATER_THAN;
|
||||
@ -367,11 +362,9 @@ public class LwM2mTransportUtil {
|
||||
return String.format("%s %s", keyName, String.join(",", msgException)).trim();
|
||||
}
|
||||
|
||||
public static Map convertMultiResourceValuesFromRpcBody(LinkedHashMap value, ResourceModel.Type type, String versionedId) {
|
||||
Gson gson = new Gson();
|
||||
JsonParser JSON_PARSER = new JsonParser();
|
||||
String json = gson.toJson(value, LinkedHashMap.class);
|
||||
return convertMultiResourceValuesFromJson((JsonObject) JSON_PARSER.parse(json), type, versionedId);
|
||||
public static Map convertMultiResourceValuesFromRpcBody(Object value, ResourceModel.Type type, String versionedId) throws Exception {
|
||||
String valueJsonStr = JsonUtils.riteValueAsString(value);
|
||||
return convertMultiResourceValuesFromJson((JsonObject) JsonUtils.parse(valueJsonStr), type, versionedId);
|
||||
}
|
||||
|
||||
public static Map convertMultiResourceValuesFromJson(JsonObject newValProto, ResourceModel.Type type, String versionedId) {
|
||||
|
||||
@ -15,15 +15,19 @@
|
||||
*/
|
||||
package org.thingsboard.server.common.transport.util;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JsonUtils {
|
||||
|
||||
private static final JsonParser jsonParser = new JsonParser();
|
||||
private static final ObjectMapper json = new ObjectMapper();
|
||||
|
||||
public static JsonObject getJsonObject(List<KeyValueProto> tsKv) {
|
||||
JsonObject json = new JsonObject();
|
||||
@ -52,4 +56,9 @@ public class JsonUtils {
|
||||
public static JsonElement parse(String params) {
|
||||
return jsonParser.parse(params);
|
||||
}
|
||||
|
||||
public static String riteValueAsString (Object value) throws JsonProcessingException {
|
||||
return json.writeValueAsString(value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,10 +97,10 @@ transport:
|
||||
timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}"
|
||||
# Enable/disable http/mqtt/coap transport protocols (has higher priority than certain protocol's 'enabled' property)
|
||||
api_enabled: "${TB_TRANSPORT_API_ENABLED:true}"
|
||||
# Local LwM2M transport parameters
|
||||
log:
|
||||
enabled: "${TB_TRANSPORT_LOG_ENABLED:true}"
|
||||
max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}"
|
||||
# Local LwM2M transport parameters
|
||||
lwm2m:
|
||||
# Enable/disable lvm2m transport protocol.
|
||||
enabled: "${LWM2M_ENABLED:true}"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user