Browse Source

LwM2mClient is no more serializable

pull/5977/head
YevhenBondarenko 4 years ago
parent
commit
fde8ecdead
  1. 2
      application/src/main/resources/thingsboard.yml
  2. 25
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java
  3. 9
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  4. 37
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java
  5. 21
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MResource.java
  6. 30
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MResourceInstance.java
  7. 30
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MSingleResource.java
  8. 30
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2mMultipleResource.java
  9. 29
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbResourceModel.java
  10. 34
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java
  11. 12
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java
  12. 345
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/util/LwM2MClientSerDes.java
  13. 2
      transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml

2
application/src/main/resources/thingsboard.yml

@ -831,8 +831,6 @@ transport:
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}"
network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside
# - key: "PROTOCOL_STAGE_THREAD_COUNT"
# value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}"

25
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java

@ -42,9 +42,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@ -72,15 +69,14 @@ import static org.thingsboard.server.transport.lwm2m.utils.LwM2MTransportUtil.ge
@Slf4j
@EqualsAndHashCode(of = {"endpoint"})
@ToString(of = "endpoint")
public class LwM2mClient implements Serializable {
private static final long serialVersionUID = 8793482946289222623L;
public class LwM2mClient {
@Getter
private final String nodeId;
@Getter
private final String endpoint;
private transient Lock lock;
private final Lock lock;
@Getter
private final Map<String, ResourceValue> resources;
@ -109,7 +105,7 @@ public class LwM2mClient implements Serializable {
@Getter
private Long edrxCycle;
@Getter
private transient Registration registration;
private Registration registration;
@Getter
@Setter
private boolean asleep;
@ -117,14 +113,14 @@ public class LwM2mClient implements Serializable {
private long lastUplinkTime;
@Getter
@Setter
private transient Future<Void> sleepTask;
private Future<Void> sleepTask;
private boolean firstEdrxDownlink = true;
@Getter
private transient Set<ContentFormat> clientSupportContentFormats;
private Set<ContentFormat> clientSupportContentFormats;
@Getter
private transient ContentFormat defaultContentFormat;
private ContentFormat defaultContentFormat;
@Getter
private final AtomicInteger retryAttempts;
@ -423,7 +419,7 @@ public class LwM2mClient implements Serializable {
private ContentFormat calculateDefaultContentFormat(Registration registration) {
if (registration == null) {
return ContentFormat.DEFAULT;
} else{
} else {
return TbLwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat();
}
}
@ -443,11 +439,6 @@ public class LwM2mClient implements Serializable {
return contentFormats;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
this.lock = new ReentrantLock();
}
public long updateLastUplinkTime() {
this.lastUplinkTime = System.currentTimeMillis();
this.firstEdrxDownlink = true;

9
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -20,7 +20,6 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.core.SecurityMode;
import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.registration.RegistrationStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@ -73,7 +72,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
private final LwM2MSessionManager sessionManager;
private final TransportDeviceProfileCache deviceProfileCache;
private final LwM2MModelConfigService modelConfigService;
private final RegistrationStore registrationStore;
@Autowired
@Lazy
@ -120,11 +118,8 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
private void updateFetchedClient(String nodeId, LwM2mClient client) {
boolean updated = false;
Registration registration = registrationStore.getRegistrationByEndpoint(client.getEndpoint());
if (registration != null) {
client.setRegistration(registration);
lwM2mClientsByRegistrationId.put(registration.getId(), client);
if (client.getRegistration() != null) {
lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client);
}
if (client.getSession() != null) {
client.refreshSessionId(nodeId);

37
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/ResourceValue.java

@ -25,54 +25,39 @@ import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.request.WriteRequest.Mode;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Data
public class ResourceValue implements Serializable {
private static final long serialVersionUID = -228268906779089402L;
private TbLwM2MResource lwM2mResource;
private TbResourceModel resourceModel;
private LwM2mResource lwM2mResource;
private ResourceModel resourceModel;
public ResourceValue(LwM2mResource lwM2mResource, ResourceModel resourceModel) {
this.resourceModel = toTbResourceModel(resourceModel);
this.resourceModel = resourceModel;
updateLwM2mResource(lwM2mResource, Mode.UPDATE);
}
public void updateLwM2mResource(LwM2mResource lwM2mResource, Mode mode) {
if (lwM2mResource instanceof LwM2mSingleResource) {
this.lwM2mResource = new TbLwM2MSingleResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType());
this.lwM2mResource = LwM2mSingleResource.newResource(lwM2mResource.getId(), lwM2mResource.getValue(), lwM2mResource.getType());
} else if (lwM2mResource instanceof LwM2mMultipleResource) {
if (lwM2mResource.getInstances().values().size() > 0) {
Set <TbLwM2MResourceInstance> instancesSet = lwM2mResource.getInstances().values().stream().map(ResourceValue::toTbLwM2MResourceInstance).collect(Collectors.toSet());
Set<LwM2mResourceInstance> instancesSet = new HashSet<>(lwM2mResource.getInstances().values());
if (Mode.REPLACE.equals(mode) && this.lwM2mResource != null) {
Map<Integer, LwM2mResourceInstance> oldInstances = this.lwM2mResource.getInstances();
oldInstances.values().forEach(v -> {
if (instancesSet.stream().noneMatch(vIns -> v.getId() == vIns.getId())){
instancesSet.add(toTbLwM2MResourceInstance(v));
}
if (instancesSet.stream().noneMatch(vIns -> v.getId() == vIns.getId())) {
instancesSet.add(v);
}
});
}
TbLwM2MResourceInstance[] instances = instancesSet.toArray(new TbLwM2MResourceInstance[0]);
this.lwM2mResource = new TbLwM2mMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances);
LwM2mResourceInstance[] instances = instancesSet.toArray(new LwM2mResourceInstance[0]);
this.lwM2mResource = new LwM2mMultipleResource(lwM2mResource.getId(), lwM2mResource.getType(), instances);
}
}
}
public void setResourceModel(ResourceModel resourceModel) {
this.resourceModel = toTbResourceModel(resourceModel);
}
private static TbLwM2MResourceInstance toTbLwM2MResourceInstance(LwM2mResourceInstance instance) {
return new TbLwM2MResourceInstance(instance.getId(), instance.getValue(), instance.getType());
}
private static TbResourceModel toTbResourceModel(ResourceModel resourceModel) {
return new TbResourceModel(resourceModel.id, resourceModel.name, resourceModel.operations, resourceModel.multiple,
resourceModel.mandatory, resourceModel.type, resourceModel.rangeEnumeration, resourceModel.units, resourceModel.description);
}
}

21
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MResource.java

@ -1,21 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.core.node.LwM2mResource;
public interface TbLwM2MResource extends LwM2mResource {
}

30
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MResourceInstance.java

@ -1,30 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mResourceInstance;
import java.io.Serializable;
public class TbLwM2MResourceInstance extends LwM2mResourceInstance implements Serializable {
private static final long serialVersionUID = -8322290426892538345L;
protected TbLwM2MResourceInstance(int id, Object value, ResourceModel.Type type) {
super(id, value, type);
}
}

30
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2MSingleResource.java

@ -1,30 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import java.io.Serializable;
public class TbLwM2MSingleResource extends LwM2mSingleResource implements TbLwM2MResource, Serializable {
private static final long serialVersionUID = -878078368245340809L;
public TbLwM2MSingleResource(int id, Object value, ResourceModel.Type type) {
super(id, value, type);
}
}

30
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbLwM2mMultipleResource.java

@ -1,30 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import java.io.Serializable;
public class TbLwM2mMultipleResource extends LwM2mMultipleResource implements TbLwM2MResource, Serializable {
private static final long serialVersionUID = 4658477128628087186L;
public TbLwM2mMultipleResource(int id, ResourceModel.Type type, TbLwM2MResourceInstance... instances) {
super(id, type, instances);
}
}

29
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/TbResourceModel.java

@ -1,29 +0,0 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.client;
import org.eclipse.leshan.core.model.ResourceModel;
import java.io.Serializable;
public class TbResourceModel extends ResourceModel implements Serializable {
private static final long serialVersionUID = -2082846558899793932L;
public TbResourceModel(Integer id, String name, Operations operations, Boolean multiple, Boolean mandatory, Type type, String rangeEnumeration, String units, String description) {
super(id, name, operations, multiple, mandatory, type, rangeEnumeration, units, description);
}
}

34
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreFactory.java

@ -15,10 +15,9 @@
*/
package org.thingsboard.server.transport.lwm2m.server.store;
import lombok.RequiredArgsConstructor;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Component;
@ -31,58 +30,47 @@ import java.util.Optional;
@Component
@TbLwM2mTransportComponent
@RequiredArgsConstructor
public class TbLwM2mStoreFactory {
@Autowired(required = false)
private Optional<TBRedisCacheConfiguration> redisConfiguration;
@Autowired
private LwM2MTransportServerConfig config;
@Autowired
private LwM2mCredentialsSecurityInfoValidator validator;
@Value("${transport.lwm2m.redis.enabled:false}")
private boolean useRedis;
private final Optional<TBRedisCacheConfiguration> redisConfiguration;
private final LwM2MTransportServerConfig config;
private final LwM2mCredentialsSecurityInfoValidator validator;
@Bean
private CaliforniumRegistrationStore registrationStore() {
return isRedis() ?
return redisConfiguration.isPresent() ?
new TbLwM2mRedisRegistrationStore(getConnectionFactory()) : new InMemoryRegistrationStore(config.getCleanPeriodInSec());
}
@Bean
private TbMainSecurityStore securityStore() {
return new TbLwM2mSecurityStore(isRedis() ?
return new TbLwM2mSecurityStore(redisConfiguration.isPresent() ?
new TbLwM2mRedisSecurityStore(getConnectionFactory()) : new TbInMemorySecurityStore(), validator);
}
@Bean
private TbLwM2MClientStore clientStore() {
return isRedis() ? new TbRedisLwM2MClientStore(getConnectionFactory()) : new TbDummyLwM2MClientStore();
return redisConfiguration.isPresent() ? new TbRedisLwM2MClientStore(getConnectionFactory()) : new TbDummyLwM2MClientStore();
}
@Bean
private TbLwM2MModelConfigStore modelConfigStore() {
return isRedis() ? new TbRedisLwM2MModelConfigStore(getConnectionFactory()) : new TbDummyLwM2MModelConfigStore();
return redisConfiguration.isPresent() ? new TbRedisLwM2MModelConfigStore(getConnectionFactory()) : new TbDummyLwM2MModelConfigStore();
}
@Bean
private TbLwM2MClientOtaInfoStore otaStore() {
return isRedis() ? new TbLwM2mRedisClientOtaInfoStore(getConnectionFactory()) : new TbDummyLwM2MClientOtaInfoStore();
return redisConfiguration.isPresent() ? new TbLwM2mRedisClientOtaInfoStore(getConnectionFactory()) : new TbDummyLwM2MClientOtaInfoStore();
}
@Bean
private TbLwM2MDtlsSessionStore sessionStore() {
return isRedis() ? new TbLwM2MDtlsSessionRedisStore(getConnectionFactory()) : new TbL2M2MDtlsSessionInMemoryStore();
return redisConfiguration.isPresent() ? new TbLwM2MDtlsSessionRedisStore(getConnectionFactory()) : new TbL2M2MDtlsSessionInMemoryStore();
}
private RedisConnectionFactory getConnectionFactory() {
return redisConfiguration.get().redisConnectionFactory();
}
private boolean isRedis() {
return redisConfiguration.isPresent() && useRedis;
}
}

12
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbRedisLwM2MClientStore.java

@ -16,7 +16,6 @@
package org.thingsboard.server.transport.lwm2m.server.store;
import lombok.extern.slf4j.Slf4j;
import org.nustaq.serialization.FSTConfiguration;
import org.springframework.data.redis.connection.RedisClusterConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
@ -29,16 +28,17 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.thingsboard.server.transport.lwm2m.server.store.util.LwM2MClientSerDes.deserialize;
import static org.thingsboard.server.transport.lwm2m.server.store.util.LwM2MClientSerDes.serialize;
@Slf4j
public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
private static final String CLIENT_EP = "CLIENT#EP#";
private final RedisConnectionFactory connectionFactory;
private final FSTConfiguration serializer;
public TbRedisLwM2MClientStore(RedisConnectionFactory redisConnectionFactory) {
this.connectionFactory = redisConnectionFactory;
this.serializer = FSTConfiguration.createDefaultConfiguration();
}
@Override
@ -48,7 +48,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
if (data == null) {
return null;
} else {
return (LwM2mClient) serializer.asObject(data);
return deserialize(data);
}
}
}
@ -70,7 +70,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
scans.forEach(scan -> {
scan.forEachRemaining(key -> {
byte[] element = connection.get(key);
clients.add((LwM2mClient) serializer.asObject(element));
clients.add(deserialize(element));
});
});
return clients;
@ -82,7 +82,7 @@ public class TbRedisLwM2MClientStore implements TbLwM2MClientStore {
if (client.getState().equals(LwM2MClientState.UNREGISTERED)) {
log.error("[{}] Client is in invalid state: {}!", client.getEndpoint(), client.getState(), new Exception());
} else {
byte[] clientSerialized = serializer.asByteArray(client);
byte[] clientSerialized = serialize(client);
try (var connection = connectionFactory.getConnection()) {
connection.getSet(getKey(client.getEndpoint()), clientSerialized);
}

345
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/util/LwM2MClientSerDes.java

@ -0,0 +1,345 @@
/**
* Copyright © 2016-2022 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.transport.lwm2m.server.store.util;
import com.eclipsesource.json.Json;
import com.eclipsesource.json.JsonObject;
import com.eclipsesource.json.JsonValue;
import com.google.protobuf.util.JsonFormat;
import lombok.SneakyThrows;
import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mMultipleResource;
import org.eclipse.leshan.core.node.LwM2mNodeException;
import org.eclipse.leshan.core.node.LwM2mResource;
import org.eclipse.leshan.core.node.LwM2mSingleResource;
import org.eclipse.leshan.core.node.ObjectLink;
import org.eclipse.leshan.core.util.datatype.ULong;
import org.eclipse.leshan.server.redis.serialization.RegistrationSerDes;
import org.thingsboard.server.common.data.device.data.PowerMode;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
public class LwM2MClientSerDes {
public static final String VALUE = "value";
@SneakyThrows
public static byte[] serialize(LwM2mClient client) {
JsonObject o = Json.object();
o.add("nodeId", client.getNodeId());
o.add("endpoint", client.getEndpoint());
JsonObject resources = Json.object();
client.getResources().forEach((k, v) -> {
JsonObject resourceValue = Json.object();
resourceValue.add("lwM2mResource", serialize(v.getLwM2mResource()));
resourceValue.add("resourceModel", serialize(v.getResourceModel()));
resources.add(k, resourceValue);
});
o.add("resources", resources);
JsonObject sharedAttributes = Json.object();
for (Map.Entry<String, TransportProtos.TsKvProto> entry : client.getSharedAttributes().entrySet()) {
sharedAttributes.add(entry.getKey(), JsonFormat.printer().print(entry.getValue()));
}
o.add("sharedAttributes", sharedAttributes);
JsonObject keyTsLatestMap = Json.object();
client.getKeyTsLatestMap().forEach((k, v) -> {
keyTsLatestMap.add(k, v.get());
});
o.add("keyTsLatestMap", keyTsLatestMap);
if (client.getSession() != null) {
o.add("session", JsonFormat.printer().print(client.getSession()));
}
if (client.getTenantId() != null) {
o.add("tenantId", client.getTenantId().toString());
}
if (client.getDeviceId() != null) {
o.add("deviceId", client.getDeviceId().toString());
}
if (client.getProfileId() != null) {
o.add("profileId", client.getProfileId().toString());
}
if (client.getPowerMode() != null) {
o.add("powerMode", client.getPowerMode().toString());
}
if (client.getEdrxCycle() != null) {
o.add("edrxCycle", client.getEdrxCycle());
}
if (client.getPsmActivityTimer() != null) {
o.add("psmActivityTimer", client.getPsmActivityTimer());
}
if (client.getPagingTransmissionWindow() != null) {
o.add("pagingTransmissionWindow", client.getPagingTransmissionWindow());
}
if (client.getRegistration() != null) {
o.add("registration", RegistrationSerDes.jSerialize(client.getRegistration()));
}
o.add("asleep", client.isAsleep());
o.add("lastUplinkTime", client.getLastUplinkTime());
Field firstEdrxDownlink = LwM2mClient.class.getDeclaredField("firstEdrxDownlink");
firstEdrxDownlink.setAccessible(true);
o.add("firstEdrxDownlink", (boolean) firstEdrxDownlink.get(client));
o.add("retryAttempts", client.getRetryAttempts().get());
if (client.getLastSentRpcId() != null) {
o.add("lastSentRpcId", client.getLastSentRpcId().toString());
}
return o.toString().getBytes();
}
private static JsonObject serialize(LwM2mResource resource) {
JsonObject o = Json.object();
o.add("id", resource.getId());
o.add("type", resource.getType().toString());
if (resource.isMultiInstances()) {
o.add("multiInstances", true);
JsonObject instances = Json.object();
resource.getInstances().forEach((id, in) -> {
JsonObject instance = Json.object();
instance.add("id", in.getId());
addValue(instance, in.getType(), in.getValue());
instances.add(id.toString(), instance);
});
o.add("instances", instances);
} else {
o.add("multiInstances", false);
addValue(o, resource.getType(), resource.getValue());
}
return o;
}
private static LwM2mResource parseLwM2mResource(JsonObject o) {
boolean multiInstances = o.get("multiInstances").asBoolean();
int id = o.get("id").asInt();
ResourceModel.Type type = ResourceModel.Type.valueOf(o.get("type").asString());
if (multiInstances) {
Map<Integer, Object> instances = new HashMap<>();
o.get("instances").asObject().forEach(entry -> {
instances.put(Integer.valueOf(entry.getName()), parseValue(type, entry.getValue()));
});
return LwM2mMultipleResource.newResource(id, instances, type);
} else {
return LwM2mSingleResource.newResource(id, parseValue(type, o.get(VALUE)));
}
}
private static Object parseValue(ResourceModel.Type type, JsonValue value) {
switch (type) {
case INTEGER:
return value.asLong();
case FLOAT:
return value.asDouble();
case BOOLEAN:
return value.asBoolean();
case OPAQUE:
return Base64.getDecoder().decode(value.asString());
case STRING:
return value.asString();
case TIME:
return new Date(value.asLong());
case OBJLNK:
return ObjectLink.decodeFromString(value.asString());
case UNSIGNED_INTEGER:
return ULong.valueOf(value.asString());
default:
throw new LwM2mNodeException(String.format("Type %s is not supported", type.name()));
}
}
private static JsonObject serialize(ResourceModel resourceModel) {
JsonObject o = Json.object();
o.add("id", resourceModel.id);
o.add("name", resourceModel.name);
o.add("operations", resourceModel.operations.toString());
o.add("multiple", resourceModel.multiple);
o.add("mandatory", resourceModel.mandatory);
o.add("type", resourceModel.type.toString());
o.add("rangeEnumeration", resourceModel.rangeEnumeration);
o.add("units", resourceModel.units);
o.add("description", resourceModel.description);
return o;
}
private static ResourceModel parseResourceModel(JsonObject o) {
Integer id = o.get("id").asInt();
String name = o.get("name").asString();
ResourceModel.Operations operations = ResourceModel.Operations.valueOf(o.get("operations").asString());
Boolean multiple = o.get("multiple").asBoolean();
Boolean mandatory = o.get("mandatory").asBoolean();
ResourceModel.Type type = ResourceModel.Type.valueOf(o.get("type").asString());
String rangeEnumeration = o.get("rangeEnumeration").asString();
String units = o.get("units").asString();
String description = o.get("description").asString();
return new ResourceModel(id, name, operations, multiple, mandatory, type, rangeEnumeration, units, description);
}
private static void addValue(JsonObject o, ResourceModel.Type type, Object value) {
switch (type) {
case INTEGER:
o.add(VALUE, (Long) value);
break;
case FLOAT:
o.add(VALUE, (Double) value);
break;
case BOOLEAN:
o.add(VALUE, (Boolean) value);
break;
case OPAQUE:
o.add(VALUE, Base64.getEncoder().encodeToString((byte[]) value));
break;
case STRING:
o.add(VALUE, (String) value);
break;
case TIME:
o.add(VALUE, ((Date) value).getTime());
break;
case OBJLNK:
o.add(VALUE, ((ObjectLink) value).encodeToString());
break;
case UNSIGNED_INTEGER:
o.add(VALUE, value.toString());
break;
default:
throw new LwM2mNodeException(String.format("Type %s is not supported", type.name()));
}
}
@SneakyThrows
public static LwM2mClient deserialize(byte[] data) {
JsonObject o = Json.parse(new String(data)).asObject();
LwM2mClient lwM2mClient = new LwM2mClient(o.get("nodeId").asString(), o.get("endpoint").asString());
o.get("resources").asObject().forEach(entry -> {
JsonObject resource = entry.getValue().asObject();
LwM2mResource lwM2mResource = parseLwM2mResource(resource.get("lwM2mResource").asObject());
ResourceModel resourceModel = parseResourceModel(resource.get("resourceModel").asObject());
ResourceValue resourceValue = new ResourceValue(lwM2mResource, resourceModel);
lwM2mClient.getResources().put(entry.getName(), resourceValue);
});
for (JsonObject.Member entry : o.get("sharedAttributes").asObject()) {
TransportProtos.TsKvProto.Builder builder = TransportProtos.TsKvProto.newBuilder();
JsonFormat.parser().merge(entry.getValue().asString(), builder);
lwM2mClient.getSharedAttributes().put(entry.getName(), builder.build());
}
o.get("keyTsLatestMap").asObject().forEach(entry -> {
lwM2mClient.getKeyTsLatestMap().put(entry.getName(), new AtomicLong(entry.getValue().asLong()));
});
Class<LwM2mClient> lwM2mClientClass = LwM2mClient.class;
JsonValue session = o.get("session");
if (session != null) {
TransportProtos.SessionInfoProto.Builder builder = TransportProtos.SessionInfoProto.newBuilder();
JsonFormat.parser().merge(session.asString(), builder);
Field sessionField = lwM2mClientClass.getDeclaredField("session");
sessionField.setAccessible(true);
sessionField.set(lwM2mClient, builder.build());
}
JsonValue tenantId = o.get("tenantId");
if (tenantId != null) {
Field tenantIdField = lwM2mClientClass.getDeclaredField("tenantId");
tenantIdField.setAccessible(true);
tenantIdField.set(lwM2mClient, new TenantId(UUID.fromString(tenantId.asString())));
}
JsonValue deviceId = o.get("deviceId");
if (tenantId != null) {
Field deviceIdField = lwM2mClientClass.getDeclaredField("deviceId");
deviceIdField.setAccessible(true);
deviceIdField.set(lwM2mClient, UUID.fromString(deviceId.asString()));
}
JsonValue profileId = o.get("profileId");
if (tenantId != null) {
Field profileIdField = lwM2mClientClass.getDeclaredField("profileId");
profileIdField.setAccessible(true);
profileIdField.set(lwM2mClient, UUID.fromString(profileId.asString()));
}
JsonValue powerMode = o.get("powerMode");
if (powerMode != null) {
Field powerModeField = lwM2mClientClass.getDeclaredField("powerMode");
powerModeField.setAccessible(true);
powerModeField.set(lwM2mClient, PowerMode.valueOf(powerMode.asString()));
}
JsonValue edrxCycle = o.get("edrxCycle");
if (edrxCycle != null) {
Field edrxCycleField = lwM2mClientClass.getDeclaredField("edrxCycle");
edrxCycleField.setAccessible(true);
edrxCycleField.setLong(lwM2mClient, edrxCycle.asLong());
}
JsonValue psmActivityTimer = o.get("psmActivityTimer");
if (psmActivityTimer != null) {
Field psmActivityTimerField = lwM2mClientClass.getDeclaredField("psmActivityTimer");
psmActivityTimerField.setAccessible(true);
psmActivityTimerField.setLong(lwM2mClient, psmActivityTimer.asLong());
}
JsonValue pagingTransmissionWindow = o.get("pagingTransmissionWindow");
if (pagingTransmissionWindow != null) {
Field pagingTransmissionWindowField = lwM2mClientClass.getDeclaredField("pagingTransmissionWindow");
pagingTransmissionWindowField.setAccessible(true);
pagingTransmissionWindowField.setLong(lwM2mClient, pagingTransmissionWindow.asLong());
}
JsonValue registration = o.get("registration");
if (registration != null) {
lwM2mClient.setRegistration(RegistrationSerDes.deserialize(registration.asObject()));
}
lwM2mClient.setAsleep(o.get("asleep").asBoolean());
Field lastUplinkTimeField = lwM2mClientClass.getDeclaredField("lastUplinkTime");
lastUplinkTimeField.setAccessible(true);
lastUplinkTimeField.setLong(lwM2mClient, o.get("lastUplinkTime").asLong());
Field firstEdrxDownlinkField = lwM2mClientClass.getDeclaredField("firstEdrxDownlink");
firstEdrxDownlinkField.setAccessible(true);
firstEdrxDownlinkField.setBoolean(lwM2mClient, o.get("firstEdrxDownlink").asBoolean());
lwM2mClient.getRetryAttempts().set(o.get("retryAttempts").asInt());
JsonValue lastSentRpcId = o.get("lastSentRpcId");
if (lastSentRpcId != null) {
lwM2mClient.setLastSentRpcId(UUID.fromString(lastSentRpcId.asString()));
}
return lwM2mClient;
}
}

2
transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml

@ -201,8 +201,6 @@ transport:
clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}"
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}"
network_config: # In this section you can specify custom parameters for LwM2M network configuration and expose the env variables to configure outside
# - key: "PROTOCOL_STAGE_THREAD_COUNT"
# value: "${LWM2M_PROTOCOL_STAGE_THREAD_COUNT:4}"

Loading…
Cancel
Save