Commit 78f9194669b5369f26f20b839301a44ddccc8ab9

Authored by Andrii Shvaika
1 parent d190cba2

LwM2M Client Store

... ... @@ -87,7 +87,7 @@ public class LwM2mTransportUtil {
87 87
88 88 public static final String LWM2M_VERSION_DEFAULT = "1.0";
89 89
90   - public static final String LOG_LWM2M_TELEMETRY = "logLwm2m";
  90 + public static final String LOG_LWM2M_TELEMETRY = "transportLog";
91 91 public static final String LOG_LWM2M_INFO = "info";
92 92 public static final String LOG_LWM2M_ERROR = "error";
93 93 public static final String LOG_LWM2M_WARN = "warn";
... ... @@ -169,19 +169,6 @@ public class LwM2mTransportUtil {
169 169 return lwM2mOtaConvert;
170 170 }
171 171
172   - public static LwM2mNode getLvM2mNodeToObject(LwM2mNode content) {
173   - if (content instanceof LwM2mObject) {
174   - return (LwM2mObject) content;
175   - } else if (content instanceof LwM2mObjectInstance) {
176   - return (LwM2mObjectInstance) content;
177   - } else if (content instanceof LwM2mSingleResource) {
178   - return (LwM2mSingleResource) content;
179   - } else if (content instanceof LwM2mMultipleResource) {
180   - return (LwM2mMultipleResource) content;
181   - }
182   - return null;
183   - }
184   -
185 172 public static Lwm2mDeviceProfileTransportConfiguration toLwM2MClientProfile(DeviceProfile deviceProfile) {
186 173 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
187 174 if (transportConfiguration.getType().equals(DeviceTransportType.LWM2M)) {
... ... @@ -196,62 +183,6 @@ public class LwM2mTransportUtil {
196 183 return toLwM2MClientProfile(deviceProfile).getBootstrap();
197 184 }
198 185
199   - public static JsonObject validateJson(String jsonStr) {
200   - JsonObject object = null;
201   - if (jsonStr != null && !jsonStr.isEmpty()) {
202   - String jsonValidFlesh = jsonStr.replaceAll("\\\\", "");
203   - jsonValidFlesh = jsonValidFlesh.replaceAll("\n", "");
204   - jsonValidFlesh = jsonValidFlesh.replaceAll("\t", "");
205   - jsonValidFlesh = jsonValidFlesh.replaceAll(" ", "");
206   - String jsonValid = (jsonValidFlesh.charAt(0) == '"' && jsonValidFlesh.charAt(jsonValidFlesh.length() - 1) == '"') ? jsonValidFlesh.substring(1, jsonValidFlesh.length() - 1) : jsonValidFlesh;
207   - try {
208   - object = new JsonParser().parse(jsonValid).getAsJsonObject();
209   - } catch (JsonSyntaxException e) {
210   - log.error("[{}] Fail validateJson [{}]", jsonStr, e.getMessage());
211   - }
212   - }
213   - return object;
214   - }
215   -
216   - @SuppressWarnings("unchecked")
217   - public static <T> Optional<T> decode(byte[] byteArray) {
218   - try {
219   - FSTConfiguration config = FSTConfiguration.createDefaultConfiguration();
220   - T msg = (T) config.asObject(byteArray);
221   - return Optional.ofNullable(msg);
222   - } catch (IllegalArgumentException e) {
223   - log.error("Error during deserialization message, [{}]", e.getMessage());
224   - return Optional.empty();
225   - }
226   - }
227   -
228   - public static String splitCamelCaseString(String s) {
229   - LinkedList<String> linkedListOut = new LinkedList<>();
230   - LinkedList<String> linkedList = new LinkedList<String>((Arrays.asList(s.split(" "))));
231   - linkedList.forEach(str -> {
232   - String strOut = str.replaceAll("\\W", "").replaceAll("_", "").toUpperCase();
233   - if (strOut.length() > 1) linkedListOut.add(strOut.charAt(0) + strOut.substring(1).toLowerCase());
234   - else linkedListOut.add(strOut);
235   - });
236   - linkedListOut.set(0, (linkedListOut.get(0).substring(0, 1).toLowerCase() + linkedListOut.get(0).substring(1)));
237   - return StringUtils.join(linkedListOut, "");
238   - }
239   -
240   - public static <T> TransportServiceCallback<Void> getAckCallback(LwM2mClient lwM2MClient,
241   - int requestId, String typeTopic) {
242   - return new TransportServiceCallback<Void>() {
243   - @Override
244   - public void onSuccess(Void dummy) {
245   - log.trace("[{}] [{}] - requestId [{}] - EndPoint , Access AckCallback", typeTopic, requestId, lwM2MClient.getEndpoint());
246   - }
247   -
248   - @Override
249   - public void onError(Throwable e) {
250   - log.trace("[{}] Failed to publish msg", e.toString());
251   - }
252   - };
253   - }
254   -
255 186 public static String fromVersionedIdToObjectId(String pathIdVer) {
256 187 try {
257 188 if (pathIdVer == null) {
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -38,16 +38,14 @@ import org.thingsboard.server.common.data.id.TenantId;
38 38 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
39 39 import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
40 40 import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto;
41   -import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest;
42 41
  42 +import java.io.Serializable;
43 43 import java.util.Collection;
44 44 import java.util.Map;
45 45 import java.util.Optional;
46   -import java.util.Queue;
47 46 import java.util.Set;
48 47 import java.util.UUID;
49 48 import java.util.concurrent.ConcurrentHashMap;
50   -import java.util.concurrent.ConcurrentLinkedQueue;
51 49 import java.util.concurrent.locks.Lock;
52 50 import java.util.concurrent.locks.ReentrantLock;
53 51 import java.util.stream.Collectors;
... ... @@ -60,48 +58,38 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.f
60 58 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.getVerFromPathIdVerOrId;
61 59
62 60 @Slf4j
63   -public class LwM2mClient implements Cloneable {
  61 +public class LwM2mClient implements Serializable {
  62 +
  63 + private static final long serialVersionUID = 8793482946289222623L;
64 64
65 65 private final String nodeId;
66 66 @Getter
67 67 private final String endpoint;
68   - private final Lock lock;
69   - @Getter
70   - @Setter
71   - private LwM2MClientState state;
72   - @Getter
73   - private final Map<String, ResourceValue> resources;
74   - @Getter
75   - private final Map<String, TsKvProto> sharedAttributes;
76   - @Getter
77   - private final Queue<LwM2mQueuedRequest> queuedRequests;
78 68
  69 + private transient final Lock lock = new ReentrantLock();
  70 + //TODO: define custom serialization of those fields.
79 71 @Getter
80   - private String deviceName;
  72 + private transient final Map<String, ResourceValue> resources;
81 73 @Getter
82   - private String deviceProfileName;
83   -
84   - @Getter
85   - private PowerMode powerMode;
  74 + private final Map<String, TsKvProto> sharedAttributes;
86 75
87 76 @Getter
88   - private String identity;
89   - @Getter
90   - private SecurityInfo securityInfo;
91   - @Getter
92 77 private TenantId tenantId;
93 78 @Getter
  79 + private UUID profileId;
  80 + @Getter
94 81 private UUID deviceId;
95 82 @Getter
  83 + @Setter
  84 + private LwM2MClientState state;
  85 + @Getter
96 86 private SessionInfoProto session;
97 87 @Getter
98   - private UUID profileId;
  88 + private PowerMode powerMode;
99 89 @Getter
100 90 @Setter
101 91 private Registration registration;
102 92
103   - private ValidateDeviceCredentialsResponse credentials;
104   -
105 93 public Object clone() throws CloneNotSupportedException {
106 94 return super.clone();
107 95 }
... ... @@ -109,23 +97,16 @@ public class LwM2mClient implements Cloneable {
109 97 public LwM2mClient(String nodeId, String endpoint) {
110 98 this.nodeId = nodeId;
111 99 this.endpoint = endpoint;
112   - this.lock = new ReentrantLock();
113 100 this.sharedAttributes = new ConcurrentHashMap<>();
114 101 this.resources = new ConcurrentHashMap<>();
115   - this.queuedRequests = new ConcurrentLinkedQueue<>();
116 102 this.state = LwM2MClientState.CREATED;
117 103 }
118 104
119   - public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID sessionId) {
120   - this.identity = identity;
121   - this.securityInfo = securityInfo;
122   - this.credentials = credentials;
  105 + public void init(ValidateDeviceCredentialsResponse credentials, UUID sessionId) {
123 106 this.session = createSession(nodeId, sessionId, credentials);
124 107 this.tenantId = new TenantId(new UUID(session.getTenantIdMSB(), session.getTenantIdLSB()));
125 108 this.deviceId = new UUID(session.getDeviceIdMSB(), session.getDeviceIdLSB());
126 109 this.profileId = new UUID(session.getDeviceProfileIdMSB(), session.getDeviceProfileIdLSB());
127   - this.deviceName = session.getDeviceName();
128   - this.deviceProfileName = session.getDeviceType();
129 110 this.powerMode = credentials.getDeviceInfo().getPowerMode();
130 111 }
131 112
... ... @@ -140,10 +121,9 @@ public class LwM2mClient implements Cloneable {
140 121 public void onDeviceUpdate(Device device, Optional<DeviceProfile> deviceProfileOpt) {
141 122 SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session);
142 123 this.deviceId = device.getUuidId();
143   - this.deviceName = device.getName();
144 124 builder.setDeviceIdMSB(deviceId.getMostSignificantBits());
145 125 builder.setDeviceIdLSB(deviceId.getLeastSignificantBits());
146   - builder.setDeviceName(deviceName);
  126 + builder.setDeviceName(device.getName());
147 127 deviceProfileOpt.ifPresent(deviceProfile -> updateSession(deviceProfile, builder));
148 128 this.session = builder.build();
149 129 this.powerMode = ((Lwm2mDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration()).getPowerMode();
... ... @@ -156,11 +136,10 @@ public class LwM2mClient implements Cloneable {
156 136 }
157 137
158 138 private void updateSession(DeviceProfile deviceProfile, SessionInfoProto.Builder builder) {
159   - this.deviceProfileName = deviceProfile.getName();
160 139 this.profileId = deviceProfile.getUuidId();
161 140 builder.setDeviceProfileIdMSB(profileId.getMostSignificantBits());
162 141 builder.setDeviceProfileIdLSB(profileId.getLeastSignificantBits());
163   - builder.setDeviceType(this.deviceProfileName);
  142 + builder.setDeviceType(deviceProfile.getName());
164 143 }
165 144
166 145 private SessionInfoProto createSession(String nodeId, UUID sessionId, ValidateDeviceCredentialsResponse msg) {
... ...
... ... @@ -28,8 +28,6 @@ import java.util.UUID;
28 28
29 29 public interface LwM2mClientContext {
30 30
31   - LwM2mClient getClientByRegistrationId(String registrationId);
32   -
33 31 LwM2mClient getClientByEndpoint(String endpoint);
34 32
35 33 LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo);
... ... @@ -53,8 +51,6 @@ public interface LwM2mClientContext {
53 51
54 52 LwM2mClient getClientByDeviceId(UUID deviceId);
55 53
56   - String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName);
57   -
58 54 String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName);
59 55
60 56 void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials);
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -31,6 +31,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
31 31 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
32 32 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
33 33 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  34 +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore;
34 35 import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore;
35 36
36 37 import java.util.Arrays;
... ... @@ -56,13 +57,27 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
56 57 private final LwM2mTransportContext context;
57 58 private final LwM2MTransportServerConfig config;
58 59 private final TbMainSecurityStore securityStore;
  60 + private final TbLwM2MClientStore clientStore;
59 61 private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
60 62 private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
61 63 private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>();
62 64
63 65 @Override
64 66 public LwM2mClient getClientByEndpoint(String endpoint) {
65   - return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> new LwM2mClient(context.getNodeId(), ep));
  67 + return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> {
  68 + LwM2mClient client = clientStore.get(ep);
  69 + if (client == null) {
  70 + log.info("[{}] initialized new client.", endpoint);
  71 + client = new LwM2mClient(context.getNodeId(), ep);
  72 + } else {
  73 + log.debug("[{}] fetched client from store: {}", endpoint, client);
  74 + if (client.getRegistration() != null) {
  75 + lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client);
  76 + //TODO: create ThingsBoard session.
  77 + }
  78 + }
  79 + return client;
  80 + });
66 81 }
67 82
68 83 @Override
... ... @@ -82,9 +97,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
82 97 if (securityInfo.getDeviceProfile() != null) {
83 98 profileUpdate(securityInfo.getDeviceProfile());
84 99 if (securityInfo.getSecurityInfo() != null) {
85   - lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), UUID.randomUUID());
  100 + lwM2MClient.init(securityInfo.getMsg(), UUID.randomUUID());
86 101 } else if (NO_SEC.equals(securityInfo.getSecurityMode())) {
87   - lwM2MClient.init(null, null, securityInfo.getMsg(), UUID.randomUUID());
  102 + lwM2MClient.init(securityInfo.getMsg(), UUID.randomUUID());
88 103 } else {
89 104 throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint()));
90 105 }
... ... @@ -97,6 +112,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
97 112 lwM2MClient.setRegistration(registration);
98 113 this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient);
99 114 lwM2MClient.setState(LwM2MClientState.REGISTERED);
  115 + clientStore.put(lwM2MClient);
100 116 } finally {
101 117 lwM2MClient.unlock();
102 118 }
... ... @@ -111,6 +127,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
111 127 throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state.");
112 128 }
113 129 lwM2MClient.setRegistration(registration);
  130 + clientStore.put(lwM2MClient);
114 131 } finally {
115 132 lwM2MClient.unlock();
116 133 }
... ... @@ -129,6 +146,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
129 146 lwM2MClient.setState(LwM2MClientState.UNREGISTERED);
130 147 lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint());
131 148 this.securityStore.remove(lwM2MClient.getEndpoint(), registration.getId());
  149 + clientStore.remove(lwM2MClient.getEndpoint());
132 150 UUID profileId = lwM2MClient.getProfileId();
133 151 if (profileId != null) {
134 152 Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst();
... ... @@ -145,11 +163,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
145 163 }
146 164
147 165 @Override
148   - public LwM2mClient getClientByRegistrationId(String registrationId) {
149   - return lwM2mClientsByRegistrationId.get(registrationId);
150   - }
151   -
152   - @Override
153 166 public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) {
154 167 LwM2mClient lwM2mClient = null;
155 168 Predicate<LwM2mClient> isClientFilter = c ->
... ... @@ -169,18 +182,6 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
169 182 return lwM2mClient;
170 183 }
171 184
172   - /**
173   - * Get path to resource from profile equal keyName
174   - *
175   - * @param sessionInfo -
176   - * @param keyName -
177   - * @return -
178   - */
179   - @Override
180   - public String getObjectIdByKeyNameFromProfile(TransportProtos.SessionInfoProto sessionInfo, String keyName) {
181   - return getObjectIdByKeyNameFromProfile(getClientBySessionInfo(sessionInfo), keyName);
182   - }
183   -
184 185 @Override
185 186 public String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName) {
186 187 Lwm2mDeviceProfileTransportConfiguration profile = getProfile(lwM2mClient.getProfileId());
... ... @@ -198,7 +199,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
198 199 @Override
199 200 public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) {
200 201 LwM2mClient client = getClientByEndpoint(registration.getEndpoint());
201   - client.init(null, null, credentials, UUID.randomUUID());
  202 + client.init(credentials, UUID.randomUUID());
202 203 lwM2mClientsByRegistrationId.put(registration.getId(), client);
203 204 profileUpdate(credentials.getDeviceProfile());
204 205 }
... ...
... ... @@ -31,18 +31,8 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
31 31 @RequiredArgsConstructor
32 32 public class DefaultLwM2MTelemetryLogService implements LwM2MTelemetryLogService {
33 33
34   - private final LwM2mClientContext clientContext;
35 34 private final LwM2mTransportServerHelper helper;
36 35
37   - /**
38   - * @param logMsg - text msg
39   - * @param registrationId - Id of Registration LwM2M Client
40   - */
41   - @Override
42   - public void log(String registrationId, String logMsg) {
43   - log(clientContext.getClientByRegistrationId(registrationId), logMsg);
44   - }
45   -
46 36 @Override
47 37 public void log(LwM2mClient client, String logMsg) {
48 38 if (logMsg != null && client != null && client.getSession() != null) {
... ...
... ... @@ -21,6 +21,4 @@ public interface LwM2MTelemetryLogService {
21 21
22 22 void log(LwM2mClient client, String msg);
23 23
24   - void log(String registrationId, String msg);
25   -
26 24 }
... ...
  1 +package org.thingsboard.server.transport.lwm2m.server.store;
  2 +
  3 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  4 +
  5 +public class TbDummyLwM2MClientStore implements TbLwM2MClientStore {
  6 + @Override
  7 + public LwM2mClient get(String endpoint) {
  8 + return null;
  9 + }
  10 +
  11 + @Override
  12 + public void put(LwM2mClient client) {
  13 +
  14 + }
  15 +
  16 + @Override
  17 + public void remove(String endpoint) {
  18 +
  19 + }
  20 +}
... ...
  1 +package org.thingsboard.server.transport.lwm2m.server.store;
  2 +
  3 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  4 +
  5 +public interface TbLwM2MClientStore {
  6 +
  7 + LwM2mClient get(String endpoint);
  8 +
  9 + void put(LwM2mClient client);
  10 +
  11 + void remove(String endpoint);
  12 +}
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -57,6 +57,11 @@ public class TbLwM2mStoreFactory {
57 57 }
58 58
59 59 @Bean
  60 + private TbLwM2MClientStore clientStore() {
  61 + return new TbDummyLwM2MClientStore();
  62 + }
  63 +
  64 + @Bean
60 65 private TbLwM2MDtlsSessionStore sessionStore() {
61 66 return redisConfiguration.isPresent() && useRedis ?
62 67 new TbLwM2MDtlsSessionRedisStore(redisConfiguration.get().redisConnectionFactory()) : new TbL2M2MDtlsSessionInMemoryStore();
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -247,14 +247,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl
247 247 log.warn("[{}] [{{}] Client: update after Registration", registration.getEndpoint(), registration.getId());
248 248 logService.log(lwM2MClient, String.format("[%s][%s] Updated registration.", registration.getId(), registration.getSocketAddress()));
249 249 clientContext.updateRegistration(lwM2MClient, registration);
250   - TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession();
251   - this.reportActivityAndRegister(sessionInfo);
252   - if (registration.usesQueueMode()) {
253   - LwM2mQueuedRequest request;
254   - while ((request = lwM2MClient.getQueuedRequests().poll()) != null) {
255   - request.send();
256   - }
257   - }
  250 + this.reportActivityAndRegister(lwM2MClient.getSession());
258 251 } catch (LwM2MClientStateException stateException) {
259 252 if (LwM2MClientState.REGISTERED.equals(stateException.getState())) {
260 253 log.info("[{}] update registration failed because client has different registration id: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());
... ...