Showing
18 changed files
with
416 additions
and
136 deletions
... | ... | @@ -181,6 +181,7 @@ public class DefaultLwM2MAttributesService implements LwM2MAttributesService { |
181 | 181 | } |
182 | 182 | } |
183 | 183 | }); |
184 | + clientContext.update(lwM2MClient); | |
184 | 185 | // #2.1 |
185 | 186 | lwM2MClient.getSharedAttributes().forEach((pathIdVer, tsKvProto) -> { |
186 | 187 | this.pushUpdateToClientIfNeeded(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer), | ... | ... |
... | ... | @@ -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, |
... | ... | @@ -142,6 +142,16 @@ public class LwM2mClient implements Serializable { |
142 | 142 | builder.setDeviceType(deviceProfile.getName()); |
143 | 143 | } |
144 | 144 | |
145 | + public void refreshSessionId(String nodeId) { | |
146 | + UUID newId = UUID.randomUUID(); | |
147 | + SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session); | |
148 | + builder.setNodeId(nodeId); | |
149 | + builder.setSessionIdMSB(newId.getMostSignificantBits()); | |
150 | + builder.setSessionIdLSB(newId.getLeastSignificantBits()); | |
151 | + this.session = builder.build(); | |
152 | + } | |
153 | + | |
154 | + | |
145 | 155 | private SessionInfoProto createSession(String nodeId, UUID sessionId, ValidateDeviceCredentialsResponse msg) { |
146 | 156 | return SessionInfoProto.newBuilder() |
147 | 157 | .setNodeId(nodeId) | ... | ... |
... | ... | @@ -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, |
... | ... | @@ -24,6 +24,7 @@ import org.eclipse.leshan.server.registration.Registration; |
24 | 24 | import org.springframework.stereotype.Service; |
25 | 25 | import org.thingsboard.server.common.data.DeviceProfile; |
26 | 26 | import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; |
27 | +import org.thingsboard.server.common.transport.TransportService; | |
27 | 28 | import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; |
28 | 29 | import org.thingsboard.server.gen.transport.TransportProtos; |
29 | 30 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
... | ... | @@ -31,6 +32,7 @@ import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
31 | 32 | import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; |
32 | 33 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; |
33 | 34 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; |
35 | +import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; | |
34 | 36 | import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientStore; |
35 | 37 | import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; |
36 | 38 | |
... | ... | @@ -58,6 +60,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
58 | 60 | private final LwM2MTransportServerConfig config; |
59 | 61 | private final TbMainSecurityStore securityStore; |
60 | 62 | private final TbLwM2MClientStore clientStore; |
63 | + private final LwM2MSessionManager sessionManager; | |
61 | 64 | private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>(); |
62 | 65 | private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>(); |
63 | 66 | private final Map<UUID, Lwm2mDeviceProfileTransportConfiguration> profiles = new ConcurrentHashMap<>(); |
... | ... | @@ -66,14 +69,23 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
66 | 69 | public LwM2mClient getClientByEndpoint(String endpoint) { |
67 | 70 | return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> { |
68 | 71 | LwM2mClient client = clientStore.get(ep); |
72 | + String nodeId = context.getNodeId(); | |
69 | 73 | if (client == null) { |
70 | 74 | log.info("[{}] initialized new client.", endpoint); |
71 | - client = new LwM2mClient(context.getNodeId(), ep); | |
75 | + client = new LwM2mClient(nodeId, ep); | |
72 | 76 | } else { |
73 | 77 | log.debug("[{}] fetched client from store: {}", endpoint, client); |
78 | + boolean updated = false; | |
74 | 79 | if (client.getRegistration() != null) { |
75 | 80 | lwM2mClientsByRegistrationId.put(client.getRegistration().getId(), client); |
76 | - //TODO: create ThingsBoard session. | |
81 | + } | |
82 | + if (client.getSession() != null) { | |
83 | + client.refreshSessionId(nodeId); | |
84 | + sessionManager.register(client.getSession()); | |
85 | + updated = true; | |
86 | + } | |
87 | + if (updated) { | |
88 | + clientStore.put(client); | |
77 | 89 | } |
78 | 90 | } |
79 | 91 | return client; |
... | ... | @@ -81,15 +93,15 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
81 | 93 | } |
82 | 94 | |
83 | 95 | @Override |
84 | - public Optional<TransportProtos.SessionInfoProto> register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { | |
96 | + public Optional<TransportProtos.SessionInfoProto> register(LwM2mClient client, Registration registration) throws LwM2MClientStateException { | |
85 | 97 | TransportProtos.SessionInfoProto oldSession = null; |
86 | - lwM2MClient.lock(); | |
98 | + client.lock(); | |
87 | 99 | try { |
88 | - if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) { | |
89 | - throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); | |
100 | + if (LwM2MClientState.UNREGISTERED.equals(client.getState())) { | |
101 | + throw new LwM2MClientStateException(client.getState(), "Client is in invalid state."); | |
90 | 102 | } |
91 | - oldSession = lwM2MClient.getSession(); | |
92 | - TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint()); | |
103 | + oldSession = client.getSession(); | |
104 | + TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(client.getEndpoint()); | |
93 | 105 | if (securityInfo.getSecurityMode() != null) { |
94 | 106 | if (SecurityMode.X509.equals(securityInfo.getSecurityMode())) { |
95 | 107 | securityStore.registerX509(registration.getEndpoint(), registration.getId()); |
... | ... | @@ -97,57 +109,57 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
97 | 109 | if (securityInfo.getDeviceProfile() != null) { |
98 | 110 | profileUpdate(securityInfo.getDeviceProfile()); |
99 | 111 | if (securityInfo.getSecurityInfo() != null) { |
100 | - lwM2MClient.init(securityInfo.getMsg(), UUID.randomUUID()); | |
112 | + client.init(securityInfo.getMsg(), UUID.randomUUID()); | |
101 | 113 | } else if (NO_SEC.equals(securityInfo.getSecurityMode())) { |
102 | - lwM2MClient.init(securityInfo.getMsg(), UUID.randomUUID()); | |
114 | + client.init(securityInfo.getMsg(), UUID.randomUUID()); | |
103 | 115 | } else { |
104 | - throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); | |
116 | + throw new RuntimeException(String.format("Registration failed: device %s not found.", client.getEndpoint())); | |
105 | 117 | } |
106 | 118 | } else { |
107 | - throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint())); | |
119 | + throw new RuntimeException(String.format("Registration failed: device %s not found.", client.getEndpoint())); | |
108 | 120 | } |
109 | 121 | } else { |
110 | - throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", lwM2MClient.getEndpoint())); | |
122 | + throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", client.getEndpoint())); | |
111 | 123 | } |
112 | - lwM2MClient.setRegistration(registration); | |
113 | - this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient); | |
114 | - lwM2MClient.setState(LwM2MClientState.REGISTERED); | |
115 | - clientStore.put(lwM2MClient); | |
124 | + client.setRegistration(registration); | |
125 | + this.lwM2mClientsByRegistrationId.put(registration.getId(), client); | |
126 | + client.setState(LwM2MClientState.REGISTERED); | |
127 | + clientStore.put(client); | |
116 | 128 | } finally { |
117 | - lwM2MClient.unlock(); | |
129 | + client.unlock(); | |
118 | 130 | } |
119 | 131 | return Optional.ofNullable(oldSession); |
120 | 132 | } |
121 | 133 | |
122 | 134 | @Override |
123 | - public void updateRegistration(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { | |
124 | - lwM2MClient.lock(); | |
135 | + public void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException { | |
136 | + client.lock(); | |
125 | 137 | try { |
126 | - if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { | |
127 | - throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); | |
138 | + if (!LwM2MClientState.REGISTERED.equals(client.getState())) { | |
139 | + throw new LwM2MClientStateException(client.getState(), "Client is in invalid state."); | |
128 | 140 | } |
129 | - lwM2MClient.setRegistration(registration); | |
130 | - clientStore.put(lwM2MClient); | |
141 | + client.setRegistration(registration); | |
142 | + clientStore.put(client); | |
131 | 143 | } finally { |
132 | - lwM2MClient.unlock(); | |
144 | + client.unlock(); | |
133 | 145 | } |
134 | 146 | } |
135 | 147 | |
136 | 148 | @Override |
137 | - public void unregister(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException { | |
138 | - lwM2MClient.lock(); | |
149 | + public void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException { | |
150 | + client.lock(); | |
139 | 151 | try { |
140 | - if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) { | |
141 | - throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state."); | |
152 | + if (!LwM2MClientState.REGISTERED.equals(client.getState())) { | |
153 | + throw new LwM2MClientStateException(client.getState(), "Client is in invalid state."); | |
142 | 154 | } |
143 | 155 | lwM2mClientsByRegistrationId.remove(registration.getId()); |
144 | - Registration currentRegistration = lwM2MClient.getRegistration(); | |
156 | + Registration currentRegistration = client.getRegistration(); | |
145 | 157 | if (currentRegistration.getId().equals(registration.getId())) { |
146 | - lwM2MClient.setState(LwM2MClientState.UNREGISTERED); | |
147 | - lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint()); | |
148 | - this.securityStore.remove(lwM2MClient.getEndpoint(), registration.getId()); | |
149 | - clientStore.remove(lwM2MClient.getEndpoint()); | |
150 | - UUID profileId = lwM2MClient.getProfileId(); | |
158 | + client.setState(LwM2MClientState.UNREGISTERED); | |
159 | + lwM2mClientsByEndpoint.remove(client.getEndpoint()); | |
160 | + this.securityStore.remove(client.getEndpoint(), registration.getId()); | |
161 | + clientStore.remove(client.getEndpoint()); | |
162 | + UUID profileId = client.getProfileId(); | |
151 | 163 | if (profileId != null) { |
152 | 164 | Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst(); |
153 | 165 | if (otherClients.isEmpty()) { |
... | ... | @@ -155,19 +167,19 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
155 | 167 | } |
156 | 168 | } |
157 | 169 | } else { |
158 | - throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration."); | |
170 | + throw new LwM2MClientStateException(client.getState(), "Client has different registration."); | |
159 | 171 | } |
160 | 172 | } finally { |
161 | - lwM2MClient.unlock(); | |
173 | + client.unlock(); | |
162 | 174 | } |
163 | 175 | } |
164 | 176 | |
165 | 177 | @Override |
166 | 178 | public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) { |
167 | 179 | LwM2mClient lwM2mClient = null; |
180 | + UUID sessionId = new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); | |
168 | 181 | Predicate<LwM2mClient> isClientFilter = c -> |
169 | - (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())) | |
170 | - .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); | |
182 | + sessionId.equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB()))); | |
171 | 183 | if (this.lwM2mClientsByEndpoint.size() > 0) { |
172 | 184 | lwM2mClient = this.lwM2mClientsByEndpoint.values().stream().filter(isClientFilter).findAny().orElse(null); |
173 | 185 | } |
... | ... | @@ -175,19 +187,17 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
175 | 187 | lwM2mClient = this.lwM2mClientsByRegistrationId.values().stream().filter(isClientFilter).findAny().orElse(null); |
176 | 188 | } |
177 | 189 | if (lwM2mClient == null) { |
178 | - log.warn("Device TimeOut? lwM2mClient is null."); | |
179 | - log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}] lwM2mClientsByRegistrationId: [{}]", sessionInfo, lwM2mClientsByEndpoint.values(), lwM2mClientsByRegistrationId.values()); | |
180 | - log.error("", new RuntimeException()); | |
190 | + log.error("[{}] Failed to lookup client by session id.", sessionId); | |
181 | 191 | } |
182 | 192 | return lwM2mClient; |
183 | 193 | } |
184 | 194 | |
185 | 195 | @Override |
186 | - public String getObjectIdByKeyNameFromProfile(LwM2mClient lwM2mClient, String keyName) { | |
187 | - Lwm2mDeviceProfileTransportConfiguration profile = getProfile(lwM2mClient.getProfileId()); | |
196 | + public String getObjectIdByKeyNameFromProfile(LwM2mClient client, String keyName) { | |
197 | + Lwm2mDeviceProfileTransportConfiguration profile = getProfile(client.getProfileId()); | |
188 | 198 | |
189 | 199 | return profile.getObserveAttr().getKeyName().entrySet().stream() |
190 | - .filter(e -> e.getValue().equals(keyName) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().orElseThrow( | |
200 | + .filter(e -> e.getValue().equals(keyName) && validateResourceInModel(client, e.getKey(), false)).findFirst().orElseThrow( | |
191 | 201 | () -> new IllegalArgumentException(keyName + " is not configured in the device profile!") |
192 | 202 | ).getKey(); |
193 | 203 | } |
... | ... | @@ -205,6 +215,16 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
205 | 215 | } |
206 | 216 | |
207 | 217 | @Override |
218 | + public void update(LwM2mClient client) { | |
219 | + client.lock(); | |
220 | + try { | |
221 | + clientStore.put(client); | |
222 | + } finally { | |
223 | + client.unlock(); | |
224 | + } | |
225 | + } | |
226 | + | |
227 | + @Override | |
208 | 228 | public Collection<LwM2mClient> getLwM2mClients() { |
209 | 229 | return lwM2mClientsByEndpoint.values(); |
210 | 230 | } |
... | ... | @@ -221,9 +241,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { |
221 | 241 | |
222 | 242 | @Override |
223 | 243 | public Lwm2mDeviceProfileTransportConfiguration profileUpdate(DeviceProfile deviceProfile) { |
224 | - Lwm2mDeviceProfileTransportConfiguration lwM2MClientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile); | |
225 | - profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile); | |
226 | - return lwM2MClientProfile; | |
244 | + Lwm2mDeviceProfileTransportConfiguration clientProfile = LwM2mTransportUtil.toLwM2MClientProfile(deviceProfile); | |
245 | + profiles.put(deviceProfile.getUuidId(), clientProfile); | |
246 | + return clientProfile; | |
227 | 247 | } |
228 | 248 | |
229 | 249 | @Override | ... | ... |
... | ... | @@ -52,6 +52,7 @@ import org.thingsboard.server.transport.lwm2m.server.ota.firmware.FirmwareUpdate |
52 | 52 | import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareUpdateStrategy; |
53 | 53 | import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateResult; |
54 | 54 | import org.thingsboard.server.transport.lwm2m.server.ota.software.SoftwareUpdateState; |
55 | +import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MClientOtaInfoStore; | |
55 | 56 | import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; |
56 | 57 | |
57 | 58 | import javax.annotation.PostConstruct; |
... | ... | @@ -123,6 +124,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
123 | 124 | private final OtaPackageDataCache otaPackageDataCache; |
124 | 125 | private final LwM2MTelemetryLogService logService; |
125 | 126 | private final LwM2mTransportServerHelper helper; |
127 | + private final TbLwM2MClientOtaInfoStore otaInfoStore; | |
126 | 128 | |
127 | 129 | @Autowired |
128 | 130 | @Lazy |
... | ... | @@ -174,6 +176,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
174 | 176 | }, throwable -> { |
175 | 177 | if (fwInfo.isSupported()) { |
176 | 178 | fwInfo.setTargetFetchFailure(true); |
179 | + update(fwInfo); | |
177 | 180 | } |
178 | 181 | }, executor); |
179 | 182 | } |
... | ... | @@ -191,6 +194,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
191 | 194 | public void onTargetFirmwareUpdate(LwM2mClient client, String newFirmwareTitle, String newFirmwareVersion, Optional<String> newFirmwareUrl) { |
192 | 195 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); |
193 | 196 | fwInfo.updateTarget(newFirmwareTitle, newFirmwareVersion, newFirmwareUrl); |
197 | + update(fwInfo); | |
194 | 198 | startFirmwareUpdateIfNeeded(client, fwInfo); |
195 | 199 | } |
196 | 200 | |
... | ... | @@ -202,7 +206,7 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
202 | 206 | } |
203 | 207 | |
204 | 208 | @Override |
205 | - public void onCurrentFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { | |
209 | + public void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration) { | |
206 | 210 | log.debug("[{}] Current fw strategy: {}", client.getEndpoint(), configuration.getFwUpdateStrategy()); |
207 | 211 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); |
208 | 212 | fwInfo.setFwStrategy(LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(configuration.getFwUpdateStrategy())); |
... | ... | @@ -242,9 +246,10 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
242 | 246 | executeFwUpdate(client); |
243 | 247 | } |
244 | 248 | fwInfo.setUpdateState(state); |
245 | - Optional<OtaPackageUpdateStatus> status = this.toOtaPackageUpdateStatus(state); | |
249 | + Optional<OtaPackageUpdateStatus> status = toOtaPackageUpdateStatus(state); | |
246 | 250 | status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo, |
247 | 251 | otaStatus, "Firmware Update State: " + state.name())); |
252 | + update(fwInfo); | |
248 | 253 | } |
249 | 254 | |
250 | 255 | @Override |
... | ... | @@ -252,15 +257,16 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
252 | 257 | log.debug("[{}] Current fw result: {}", client.getEndpoint(), code); |
253 | 258 | LwM2MClientOtaInfo fwInfo = getOrInitFwInfo(client); |
254 | 259 | FirmwareUpdateResult result = FirmwareUpdateResult.fromUpdateResultFwByCode(code.intValue()); |
255 | - Optional<OtaPackageUpdateStatus> status = this.toOtaPackageUpdateStatus(result); | |
260 | + Optional<OtaPackageUpdateStatus> status = toOtaPackageUpdateStatus(result); | |
256 | 261 | status.ifPresent(otaStatus -> sendStateUpdateToTelemetry(client, fwInfo, |
257 | 262 | otaStatus, "Firmware Update Result: " + result.name())); |
258 | 263 | if (result.isAgain() && fwInfo.getRetryAttempts() <= 2) { |
259 | 264 | fwInfo.setRetryAttempts(fwInfo.getRetryAttempts() + 1); |
260 | 265 | startFirmwareUpdateIfNeeded(client, fwInfo); |
261 | 266 | } else { |
262 | - fwInfo.setUpdateResult(result); | |
267 | + fwInfo.update(result); | |
263 | 268 | } |
269 | + update(fwInfo); | |
264 | 270 | } |
265 | 271 | |
266 | 272 | @Override |
... | ... | @@ -378,23 +384,38 @@ public class DefaultLwM2MOtaUpdateService extends LwM2MExecutorAwareService impl |
378 | 384 | } |
379 | 385 | |
380 | 386 | public LwM2MClientOtaInfo getOrInitFwInfo(LwM2mClient client) { |
381 | - //TODO: fetch state from the cache or DB. | |
382 | 387 | return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> { |
383 | - var profile = clientContext.getProfile(client.getProfileId()); | |
384 | - return new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, profile.getClientLwM2mSettings().getFwUpdateStrategy(), | |
385 | - profile.getClientLwM2mSettings().getFwUpdateResource()); | |
388 | + LwM2MClientOtaInfo info = otaInfoStore.get(OtaPackageType.FIRMWARE, endpoint); | |
389 | + if (info == null) { | |
390 | + var profile = clientContext.getProfile(client.getProfileId()); | |
391 | + info = new LwM2MClientOtaInfo(endpoint, OtaPackageType.FIRMWARE, | |
392 | + LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(profile.getClientLwM2mSettings().getFwUpdateStrategy()), | |
393 | + profile.getClientLwM2mSettings().getFwUpdateResource()); | |
394 | + update(info); | |
395 | + } | |
396 | + return info; | |
386 | 397 | }); |
387 | 398 | } |
388 | 399 | |
389 | 400 | private LwM2MClientOtaInfo getOrInitSwInfo(LwM2mClient client) { |
390 | - //TODO: fetch state from the cache or DB. | |
391 | - return swStates.computeIfAbsent(client.getEndpoint(), endpoint -> { | |
392 | - var profile = clientContext.getProfile(client.getProfileId()); | |
393 | - return new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE, profile.getClientLwM2mSettings().getSwUpdateStrategy(), profile.getClientLwM2mSettings().getSwUpdateResource()); | |
401 | + return this.fwStates.computeIfAbsent(client.getEndpoint(), endpoint -> { | |
402 | + LwM2MClientOtaInfo info = otaInfoStore.get(OtaPackageType.SOFTWARE, endpoint); | |
403 | + if (info == null) { | |
404 | + var profile = clientContext.getProfile(client.getProfileId()); | |
405 | + info = new LwM2MClientOtaInfo(endpoint, OtaPackageType.SOFTWARE, | |
406 | + LwM2MSoftwareUpdateStrategy.fromStrategySwByCode(profile.getClientLwM2mSettings().getFwUpdateStrategy()), | |
407 | + profile.getClientLwM2mSettings().getSwUpdateResource()); | |
408 | + update(info); | |
409 | + } | |
410 | + return info; | |
394 | 411 | }); |
395 | 412 | |
396 | 413 | } |
397 | 414 | |
415 | + private void update(LwM2MClientOtaInfo info) { | |
416 | + otaInfoStore.put(info); | |
417 | + } | |
418 | + | |
398 | 419 | private void sendStateUpdateToTelemetry(LwM2mClient client, LwM2MClientOtaInfo fwInfo, OtaPackageUpdateStatus status, String log) { |
399 | 420 | List<TransportProtos.KeyValueProto> result = new ArrayList<>(); |
400 | 421 | TransportProtos.KeyValueProto.Builder kvProto = TransportProtos.KeyValueProto.newBuilder().setKey(getAttributeKey(fwInfo.getType(), STATE)); | ... | ... |
... | ... | @@ -15,7 +15,9 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.transport.lwm2m.server.ota; |
17 | 17 | |
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | |
18 | 19 | import lombok.Data; |
20 | +import lombok.NoArgsConstructor; | |
19 | 21 | import org.thingsboard.server.common.data.StringUtils; |
20 | 22 | import org.thingsboard.server.common.data.ota.OtaPackageType; |
21 | 23 | import org.thingsboard.server.transport.lwm2m.server.ota.firmware.LwM2MFirmwareUpdateStrategy; |
... | ... | @@ -26,10 +28,11 @@ import org.thingsboard.server.transport.lwm2m.server.ota.software.LwM2MSoftwareU |
26 | 28 | import java.util.Optional; |
27 | 29 | |
28 | 30 | @Data |
31 | +@NoArgsConstructor | |
29 | 32 | public class LwM2MClientOtaInfo { |
30 | 33 | |
31 | - private final String endpoint; | |
32 | - private final OtaPackageType type; | |
34 | + private String endpoint; | |
35 | + private OtaPackageType type; | |
33 | 36 | |
34 | 37 | private String baseUrl; |
35 | 38 | |
... | ... | @@ -53,10 +56,17 @@ public class LwM2MClientOtaInfo { |
53 | 56 | private String failedPackageId; |
54 | 57 | private int retryAttempts; |
55 | 58 | |
56 | - public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, Integer strategyCode, String baseUrl) { | |
59 | + public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, LwM2MFirmwareUpdateStrategy fwStrategy, String baseUrl) { | |
57 | 60 | this.endpoint = endpoint; |
58 | 61 | this.type = type; |
59 | - this.fwStrategy = LwM2MFirmwareUpdateStrategy.fromStrategyFwByCode(strategyCode); | |
62 | + this.fwStrategy = fwStrategy; | |
63 | + this.baseUrl = baseUrl; | |
64 | + } | |
65 | + | |
66 | + public LwM2MClientOtaInfo(String endpoint, OtaPackageType type, LwM2MSoftwareUpdateStrategy swStrategy, String baseUrl) { | |
67 | + this.endpoint = endpoint; | |
68 | + this.type = type; | |
69 | + this.swStrategy = swStrategy; | |
60 | 70 | this.baseUrl = baseUrl; |
61 | 71 | } |
62 | 72 | |
... | ... | @@ -66,6 +76,7 @@ public class LwM2MClientOtaInfo { |
66 | 76 | this.targetUrl = newFirmwareUrl.orElse(null); |
67 | 77 | } |
68 | 78 | |
79 | + @JsonIgnore | |
69 | 80 | public boolean isUpdateRequired() { |
70 | 81 | if (StringUtils.isEmpty(targetName) || StringUtils.isEmpty(targetVersion) || !isSupported()) { |
71 | 82 | return false; |
... | ... | @@ -86,11 +97,12 @@ public class LwM2MClientOtaInfo { |
86 | 97 | } |
87 | 98 | } |
88 | 99 | |
100 | + @JsonIgnore | |
89 | 101 | public boolean isSupported() { |
90 | 102 | return StringUtils.isNotEmpty(currentName) || StringUtils.isNotEmpty(currentVersion5) || StringUtils.isNotEmpty(currentVersion3); |
91 | 103 | } |
92 | 104 | |
93 | - public void setUpdateResult(FirmwareUpdateResult updateResult) { | |
105 | + public void update(FirmwareUpdateResult updateResult) { | |
94 | 106 | this.updateResult = updateResult; |
95 | 107 | switch (updateResult) { |
96 | 108 | case INITIAL: | ... | ... |
... | ... | @@ -32,7 +32,7 @@ public interface LwM2MOtaUpdateService { |
32 | 32 | |
33 | 33 | void onCurrentFirmwareNameUpdate(LwM2mClient client, String name); |
34 | 34 | |
35 | - void onCurrentFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); | |
35 | + void onFirmwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); | |
36 | 36 | |
37 | 37 | void onCurrentSoftwareStrategyUpdate(LwM2mClient client, OtherConfiguration configuration); |
38 | 38 | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.lwm2m.server.session; | |
17 | + | |
18 | +import lombok.extern.slf4j.Slf4j; | |
19 | +import org.springframework.context.annotation.Lazy; | |
20 | +import org.springframework.stereotype.Service; | |
21 | +import org.thingsboard.server.common.transport.TransportService; | |
22 | +import org.thingsboard.server.common.transport.service.DefaultTransportService; | |
23 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
24 | +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; | |
25 | +import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; | |
26 | +import org.thingsboard.server.transport.lwm2m.server.attributes.LwM2MAttributesService; | |
27 | +import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; | |
28 | +import org.thingsboard.server.transport.lwm2m.server.uplink.LwM2mUplinkMsgHandler; | |
29 | + | |
30 | +@Slf4j | |
31 | +@Service | |
32 | +@TbLwM2mTransportComponent | |
33 | +public class DefaultLwM2MSessionManager implements LwM2MSessionManager { | |
34 | + | |
35 | + private final TransportService transportService; | |
36 | + private final LwM2MAttributesService attributesService; | |
37 | + private final LwM2MRpcRequestHandler rpcHandler; | |
38 | + private final LwM2mUplinkMsgHandler uplinkHandler; | |
39 | + | |
40 | + public DefaultLwM2MSessionManager(TransportService transportService, | |
41 | + @Lazy LwM2MAttributesService attributesService, | |
42 | + @Lazy LwM2MRpcRequestHandler rpcHandler, | |
43 | + @Lazy LwM2mUplinkMsgHandler uplinkHandler) { | |
44 | + this.transportService = transportService; | |
45 | + this.attributesService = attributesService; | |
46 | + this.rpcHandler = rpcHandler; | |
47 | + this.uplinkHandler = uplinkHandler; | |
48 | + } | |
49 | + | |
50 | + @Override | |
51 | + public void register(TransportProtos.SessionInfoProto sessionInfo) { | |
52 | + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(uplinkHandler, attributesService, rpcHandler, sessionInfo, transportService)); | |
53 | + TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() | |
54 | + .setSessionInfo(sessionInfo) | |
55 | + .setSessionEvent(DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.OPEN)) | |
56 | + .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build()) | |
57 | + .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build()) | |
58 | + .build(); | |
59 | + transportService.process(msg, null); | |
60 | + } | |
61 | + | |
62 | + @Override | |
63 | + public void deregister(TransportProtos.SessionInfoProto sessionInfo) { | |
64 | + transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(TransportProtos.SessionEvent.CLOSED), null); | |
65 | + transportService.deregisterSession(sessionInfo); | |
66 | + } | |
67 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.lwm2m.server.session; | |
17 | + | |
18 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
19 | + | |
20 | +public interface LwM2MSessionManager { | |
21 | + | |
22 | + void register(TransportProtos.SessionInfoProto sessionInfo); | |
23 | + | |
24 | + void deregister(TransportProtos.SessionInfoProto sessionInfo); | |
25 | + | |
26 | + | |
27 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.lwm2m.server.store; | |
17 | + | |
18 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | |
19 | +import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo; | |
20 | + | |
21 | +public class TbDummyLwM2MClientOtaInfoStore implements TbLwM2MClientOtaInfoStore { | |
22 | + | |
23 | + @Override | |
24 | + public LwM2MClientOtaInfo get(OtaPackageType type, String endpoint) { | |
25 | + return null; | |
26 | + } | |
27 | + | |
28 | + @Override | |
29 | + public void put(LwM2MClientOtaInfo info) { | |
30 | + | |
31 | + } | |
32 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
1 | 16 | package org.thingsboard.server.transport.lwm2m.server.store; |
2 | 17 | |
3 | 18 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.lwm2m.server.store; | |
17 | + | |
18 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | |
19 | +import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo; | |
20 | + | |
21 | +public interface TbLwM2MClientOtaInfoStore { | |
22 | + | |
23 | + LwM2MClientOtaInfo get(OtaPackageType type, String endpoint); | |
24 | + | |
25 | + void put(LwM2MClientOtaInfo info); | |
26 | +} | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
1 | 16 | package org.thingsboard.server.transport.lwm2m.server.store; |
2 | 17 | |
3 | 18 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.lwm2m.server.store; | |
17 | + | |
18 | +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; | |
19 | +import org.eclipse.leshan.server.security.SecurityInfo; | |
20 | +import org.nustaq.serialization.FSTConfiguration; | |
21 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | |
22 | +import org.springframework.integration.redis.util.RedisLockRegistry; | |
23 | +import org.thingsboard.common.util.JacksonUtil; | |
24 | +import org.thingsboard.server.common.data.ota.OtaPackageType; | |
25 | +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo; | |
26 | +import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MClientOtaInfo; | |
27 | + | |
28 | +import java.util.concurrent.locks.Lock; | |
29 | + | |
30 | +public class TbLwM2mRedisClientOtaInfoStore implements TbLwM2MClientOtaInfoStore { | |
31 | + private static final String OTA_EP = "OTA#EP#"; | |
32 | + | |
33 | + private final RedisConnectionFactory connectionFactory; | |
34 | + | |
35 | + public TbLwM2mRedisClientOtaInfoStore(RedisConnectionFactory connectionFactory) { | |
36 | + this.connectionFactory = connectionFactory; | |
37 | + } | |
38 | + | |
39 | + @Override | |
40 | + public LwM2MClientOtaInfo get(OtaPackageType type, String endpoint) { | |
41 | + try (var connection = connectionFactory.getConnection()) { | |
42 | + byte[] data = connection.get((OTA_EP + type + endpoint).getBytes()); | |
43 | + return JacksonUtil.fromBytes(data, LwM2MClientOtaInfo.class); | |
44 | + } | |
45 | + } | |
46 | + | |
47 | + @Override | |
48 | + public void put(LwM2MClientOtaInfo info) { | |
49 | + try (var connection = connectionFactory.getConnection()) { | |
50 | + connection.set((OTA_EP + info.getType() + info.getEndpoint()).getBytes(), JacksonUtil.toString(info).getBytes()); | |
51 | + } | |
52 | + } | |
53 | + | |
54 | +} | ... | ... |
... | ... | @@ -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, |
... | ... | @@ -20,6 +20,7 @@ import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationSt |
20 | 20 | import org.springframework.beans.factory.annotation.Autowired; |
21 | 21 | import org.springframework.beans.factory.annotation.Value; |
22 | 22 | import org.springframework.context.annotation.Bean; |
23 | +import org.springframework.data.redis.connection.RedisConnectionFactory; | |
23 | 24 | import org.springframework.stereotype.Component; |
24 | 25 | import org.thingsboard.server.cache.TBRedisCacheConfiguration; |
25 | 26 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
... | ... | @@ -46,14 +47,14 @@ public class TbLwM2mStoreFactory { |
46 | 47 | |
47 | 48 | @Bean |
48 | 49 | private CaliforniumRegistrationStore registrationStore() { |
49 | - return redisConfiguration.isPresent() && useRedis ? | |
50 | - new TbLwM2mRedisRegistrationStore(redisConfiguration.get().redisConnectionFactory()) : new InMemoryRegistrationStore(config.getCleanPeriodInSec()); | |
50 | + return isRedis() ? | |
51 | + new TbLwM2mRedisRegistrationStore(getConnectionFactory()) : new InMemoryRegistrationStore(config.getCleanPeriodInSec()); | |
51 | 52 | } |
52 | 53 | |
53 | 54 | @Bean |
54 | 55 | private TbMainSecurityStore securityStore() { |
55 | - return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ? | |
56 | - new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator); | |
56 | + return new TbLwM2mSecurityStore(isRedis() ? | |
57 | + new TbLwM2mRedisSecurityStore(getConnectionFactory()) : new TbInMemorySecurityStore(), validator); | |
57 | 58 | } |
58 | 59 | |
59 | 60 | @Bean |
... | ... | @@ -62,9 +63,21 @@ public class TbLwM2mStoreFactory { |
62 | 63 | } |
63 | 64 | |
64 | 65 | @Bean |
66 | + private TbLwM2MClientOtaInfoStore otaStore() { | |
67 | + return isRedis() ? new TbLwM2mRedisClientOtaInfoStore(getConnectionFactory()) : new TbDummyLwM2MClientOtaInfoStore(); | |
68 | + } | |
69 | + | |
70 | + @Bean | |
65 | 71 | private TbLwM2MDtlsSessionStore sessionStore() { |
66 | - return redisConfiguration.isPresent() && useRedis ? | |
67 | - new TbLwM2MDtlsSessionRedisStore(redisConfiguration.get().redisConnectionFactory()) : new TbL2M2MDtlsSessionInMemoryStore(); | |
72 | + return isRedis() ? new TbLwM2MDtlsSessionRedisStore(getConnectionFactory()) : new TbL2M2MDtlsSessionInMemoryStore(); | |
73 | + } | |
74 | + | |
75 | + private RedisConnectionFactory getConnectionFactory() { | |
76 | + return redisConfiguration.get().redisConnectionFactory(); | |
77 | + } | |
78 | + | |
79 | + private boolean isRedis() { | |
80 | + return redisConfiguration.isPresent() && useRedis; | |
68 | 81 | } |
69 | 82 | |
70 | 83 | } | ... | ... |
... | ... | @@ -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, |
... | ... | @@ -48,15 +48,11 @@ import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTrans |
48 | 48 | import org.thingsboard.server.common.data.ota.OtaPackageUtil; |
49 | 49 | import org.thingsboard.server.common.transport.TransportService; |
50 | 50 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
51 | -import org.thingsboard.server.common.transport.service.DefaultTransportService; | |
52 | 51 | import org.thingsboard.server.gen.transport.TransportProtos; |
53 | -import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; | |
54 | 52 | import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
55 | 53 | import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; |
56 | 54 | import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; |
57 | 55 | import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; |
58 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mQueuedRequest; | |
59 | -import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; | |
60 | 56 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext; |
61 | 57 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper; |
62 | 58 | import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil; |
... | ... | @@ -84,6 +80,7 @@ import org.thingsboard.server.transport.lwm2m.server.downlink.TbLwM2MWriteAttrib |
84 | 80 | import org.thingsboard.server.transport.lwm2m.server.log.LwM2MTelemetryLogService; |
85 | 81 | import org.thingsboard.server.transport.lwm2m.server.ota.LwM2MOtaUpdateService; |
86 | 82 | import org.thingsboard.server.transport.lwm2m.server.rpc.LwM2MRpcRequestHandler; |
83 | +import org.thingsboard.server.transport.lwm2m.server.session.LwM2MSessionManager; | |
87 | 84 | import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore; |
88 | 85 | import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; |
89 | 86 | |
... | ... | @@ -129,6 +126,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
129 | 126 | private final TransportService transportService; |
130 | 127 | private final LwM2mTransportContext context; |
131 | 128 | private final LwM2MAttributesService attributesService; |
129 | + private final LwM2MSessionManager sessionManager; | |
132 | 130 | private final LwM2MOtaUpdateService otaService; |
133 | 131 | private final LwM2MTransportServerConfig config; |
134 | 132 | private final LwM2MTelemetryLogService logService; |
... | ... | @@ -143,12 +141,14 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
143 | 141 | LwM2mTransportServerHelper helper, |
144 | 142 | LwM2mClientContext clientContext, |
145 | 143 | LwM2MTelemetryLogService logService, |
144 | + LwM2MSessionManager sessionManager, | |
146 | 145 | @Lazy LwM2MOtaUpdateService otaService, |
147 | 146 | @Lazy LwM2MAttributesService attributesService, |
148 | 147 | @Lazy LwM2MRpcRequestHandler rpcHandler, |
149 | 148 | @Lazy LwM2mDownlinkMsgHandler defaultLwM2MDownlinkMsgHandler, |
150 | 149 | LwM2mTransportContext context, TbLwM2MDtlsSessionStore sessionStore) { |
151 | 150 | this.transportService = transportService; |
151 | + this.sessionManager = sessionManager; | |
152 | 152 | this.attributesService = attributesService; |
153 | 153 | this.otaService = otaService; |
154 | 154 | this.config = config; |
... | ... | @@ -205,18 +205,10 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
205 | 205 | Optional<SessionInfoProto> oldSessionInfo = this.clientContext.register(lwM2MClient, registration); |
206 | 206 | if (oldSessionInfo.isPresent()) { |
207 | 207 | log.info("[{}] Closing old session: {}", registration.getEndpoint(), new UUID(oldSessionInfo.get().getSessionIdMSB(), oldSessionInfo.get().getSessionIdLSB())); |
208 | - closeSession(oldSessionInfo.get()); | |
208 | + sessionManager.deregister(oldSessionInfo.get()); | |
209 | 209 | } |
210 | 210 | logService.log(lwM2MClient, LOG_LWM2M_INFO + ": Client registered with registration id: " + registration.getId()); |
211 | - SessionInfoProto sessionInfo = lwM2MClient.getSession(); | |
212 | - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo, transportService)); | |
213 | - TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder() | |
214 | - .setSessionInfo(sessionInfo) | |
215 | - .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN)) | |
216 | - .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build()) | |
217 | - .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().setSessionType(TransportProtos.SessionType.ASYNC).build()) | |
218 | - .build(); | |
219 | - transportService.process(msg, null); | |
211 | + sessionManager.register(lwM2MClient.getSession()); | |
220 | 212 | this.initClientTelemetry(lwM2MClient); |
221 | 213 | this.initAttributes(lwM2MClient); |
222 | 214 | otaService.init(lwM2MClient); |
... | ... | @@ -273,7 +265,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
273 | 265 | clientContext.unregister(client, registration); |
274 | 266 | SessionInfoProto sessionInfo = client.getSession(); |
275 | 267 | if (sessionInfo != null) { |
276 | - closeSession(sessionInfo); | |
268 | + sessionManager.deregister(sessionInfo); | |
277 | 269 | sessionStore.remove(registration.getEndpoint()); |
278 | 270 | log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); |
279 | 271 | } else { |
... | ... | @@ -288,11 +280,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
288 | 280 | }); |
289 | 281 | } |
290 | 282 | |
291 | - public void closeSession(SessionInfoProto sessionInfo) { | |
292 | - transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.CLOSED), null); | |
293 | - transportService.deregisterSession(sessionInfo); | |
294 | - } | |
295 | - | |
296 | 283 | @Override |
297 | 284 | public void onSleepingDev(Registration registration) { |
298 | 285 | log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); |
... | ... | @@ -300,19 +287,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
300 | 287 | //TODO: associate endpointId with device information. |
301 | 288 | } |
302 | 289 | |
303 | -// /** | |
304 | -// * Cancel observation for All objects for this registration | |
305 | -// */ | |
306 | -// @Override | |
307 | -// public void setCancelObservationsAll(Registration registration) { | |
308 | -// if (registration != null) { | |
309 | -// LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint()); | |
310 | -// if (client != null && client.getRegistration() != null && client.getRegistration().getId().equals(registration.getId())) { | |
311 | -// defaultLwM2MDownlinkMsgHandler.sendCancelAllRequest(client, TbLwM2MCancelAllRequest.builder().build(), new TbLwM2MCancelAllObserveRequestCallback(this, client)); | |
312 | -// } | |
313 | -// } | |
314 | -// } | |
315 | - | |
316 | 290 | /** |
317 | 291 | * Sending observe value to thingsboard from ObservationListener.onResponse: object, instance, SingleResource or MultipleResource |
318 | 292 | * |
... | ... | @@ -337,6 +311,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
337 | 311 | this.updateResourcesValue(lwM2MClient, lwM2mResource, path); |
338 | 312 | } |
339 | 313 | } |
314 | + clientContext.update(lwM2MClient); | |
340 | 315 | } |
341 | 316 | } |
342 | 317 | |
... | ... | @@ -376,16 +351,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
376 | 351 | } |
377 | 352 | |
378 | 353 | /** |
379 | - * Deregister session in transport | |
380 | - * | |
381 | - * @param sessionInfo - lwm2m client | |
382 | - */ | |
383 | - @Override | |
384 | - public void doDisconnect(SessionInfoProto sessionInfo) { | |
385 | - closeSession(sessionInfo); | |
386 | - } | |
387 | - | |
388 | - /** | |
389 | 354 | * Those methods are called by the protocol stage thread pool, this means that execution MUST be done in a short delay, |
390 | 355 | * * if you need to do long time processing use a dedicated thread pool. |
391 | 356 | * |
... | ... | @@ -479,14 +444,6 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
479 | 444 | attributesMap.forEach((targetId, params) -> sendWriteAttributesRequest(lwM2MClient, targetId, params)); |
480 | 445 | } |
481 | 446 | |
482 | - private void sendDiscoverRequests(LwM2mClient lwM2MClient, Lwm2mDeviceProfileTransportConfiguration profile, Set<String> supportedObjects) { | |
483 | - Set<String> targetIds = profile.getObserveAttr().getAttributeLwm2m().keySet(); | |
484 | - targetIds = targetIds.stream().filter(target -> isSupportedTargetId(supportedObjects, target)).collect(Collectors.toSet()); | |
485 | -// TODO: why do we need to put observe into pending read requests? | |
486 | -// lwM2MClient.getPendingReadRequests().addAll(targetIds); | |
487 | - targetIds.forEach(targetId -> sendDiscoverRequest(lwM2MClient, targetId)); | |
488 | - } | |
489 | - | |
490 | 447 | private void sendDiscoverRequest(LwM2mClient lwM2MClient, String targetId) { |
491 | 448 | TbLwM2MDiscoverRequest request = TbLwM2MDiscoverRequest.builder().versionedId(targetId).timeout(this.config.getTimeout()).build(); |
492 | 449 | defaultLwM2MDownlinkMsgHandler.sendDiscoverRequest(lwM2MClient, request, new TbLwM2MDiscoverCallback(logService, lwM2MClient, targetId)); |
... | ... | @@ -637,7 +594,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
637 | 594 | List<TransportProtos.KeyValueProto> resultAttributes = new ArrayList<>(); |
638 | 595 | profile.getObserveAttr().getAttribute().forEach(pathIdVer -> { |
639 | 596 | if (path.contains(pathIdVer)) { |
640 | - TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer, registration); | |
597 | + TransportProtos.KeyValueProto kvAttr = this.getKvToThingsBoard(pathIdVer, registration); | |
641 | 598 | if (kvAttr != null) { |
642 | 599 | resultAttributes.add(kvAttr); |
643 | 600 | } |
... | ... | @@ -646,7 +603,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
646 | 603 | List<TransportProtos.KeyValueProto> resultTelemetries = new ArrayList<>(); |
647 | 604 | profile.getObserveAttr().getTelemetry().forEach(pathIdVer -> { |
648 | 605 | if (path.contains(pathIdVer)) { |
649 | - TransportProtos.KeyValueProto kvAttr = this.getKvToThingsboard(pathIdVer, registration); | |
606 | + TransportProtos.KeyValueProto kvAttr = this.getKvToThingsBoard(pathIdVer, registration); | |
650 | 607 | if (kvAttr != null) { |
651 | 608 | resultTelemetries.add(kvAttr); |
652 | 609 | } |
... | ... | @@ -663,7 +620,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
663 | 620 | return null; |
664 | 621 | } |
665 | 622 | |
666 | - private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) { | |
623 | + private TransportProtos.KeyValueProto getKvToThingsBoard(String pathIdVer, Registration registration) { | |
667 | 624 | LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint()); |
668 | 625 | Map<String, String> names = clientContext.getProfile(lwM2MClient.getProfileId()).getObserveAttr().getKeyName(); |
669 | 626 | if (names != null && names.containsKey(pathIdVer)) { |
... | ... | @@ -710,10 +667,12 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
710 | 667 | public void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request) { |
711 | 668 | if (request.getNode() instanceof LwM2mResource) { |
712 | 669 | this.updateResourcesValue(client, ((LwM2mResource) request.getNode()), path); |
670 | + clientContext.update(client); | |
713 | 671 | } else if (request.getNode() instanceof LwM2mObjectInstance) { |
714 | 672 | ((LwM2mObjectInstance) request.getNode()).getResources().forEach((resId, resource) -> { |
715 | 673 | this.updateResourcesValue(client, resource, path + "/" + resId); |
716 | 674 | }); |
675 | + clientContext.update(client); | |
717 | 676 | } |
718 | 677 | } |
719 | 678 | |
... | ... | @@ -788,7 +747,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
788 | 747 | if (!newLwM2mSettings.getFwUpdateStrategy().equals(oldLwM2mSettings.getFwUpdateStrategy()) |
789 | 748 | || (StringUtils.isNotEmpty(newLwM2mSettings.getFwUpdateResource()) && |
790 | 749 | !newLwM2mSettings.getFwUpdateResource().equals(oldLwM2mSettings.getFwUpdateResource()))) { |
791 | - clients.forEach(lwM2MClient -> otaService.onCurrentFirmwareStrategyUpdate(lwM2MClient, newLwM2mSettings)); | |
750 | + clients.forEach(lwM2MClient -> otaService.onFirmwareStrategyUpdate(lwM2MClient, newLwM2mSettings)); | |
792 | 751 | } |
793 | 752 | |
794 | 753 | if (!newLwM2mSettings.getSwUpdateStrategy().equals(oldLwM2mSettings.getSwUpdateStrategy()) |
... | ... | @@ -893,7 +852,7 @@ public class DefaultLwM2MUplinkMsgHandler extends LwM2MExecutorAwareService impl |
893 | 852 | */ |
894 | 853 | private void reportActivityAndRegister(SessionInfoProto sessionInfo) { |
895 | 854 | if (sessionInfo != null && transportService.reportActivity(sessionInfo) == null) { |
896 | - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, attributesService, rpcHandler, sessionInfo, transportService)); | |
855 | + sessionManager.register(sessionInfo); | |
897 | 856 | this.reportActivitySubscription(sessionInfo); |
898 | 857 | } |
899 | 858 | } | ... | ... |
... | ... | @@ -48,8 +48,6 @@ public interface LwM2mUplinkMsgHandler { |
48 | 48 | |
49 | 49 | void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceDeleteMsgOpt); |
50 | 50 | |
51 | - void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); | |
52 | - | |
53 | 51 | void onAwakeDev(Registration registration); |
54 | 52 | |
55 | 53 | void onWriteResponseOk(LwM2mClient client, String path, WriteRequest request); | ... | ... |
... | ... | @@ -47,7 +47,7 @@ public class JacksonUtil { |
47 | 47 | throw new IllegalArgumentException("The given object value: " |
48 | 48 | + fromValue + " cannot be converted to " + toValueTypeRef, e); |
49 | 49 | } |
50 | - } | |
50 | + } | |
51 | 51 | |
52 | 52 | public static <T> T fromString(String string, Class<T> clazz) { |
53 | 53 | try { |
... | ... | @@ -67,6 +67,15 @@ public class JacksonUtil { |
67 | 67 | } |
68 | 68 | } |
69 | 69 | |
70 | + public static <T> T fromBytes(byte[] bytes, Class<T> clazz) { | |
71 | + try { | |
72 | + return bytes != null ? OBJECT_MAPPER.readValue(bytes, clazz) : null; | |
73 | + } catch (IOException e) { | |
74 | + throw new IllegalArgumentException("The given string value: " | |
75 | + + Arrays.toString(bytes) + " cannot be transformed to Json object", e); | |
76 | + } | |
77 | + } | |
78 | + | |
70 | 79 | public static JsonNode fromBytes(byte[] bytes) { |
71 | 80 | try { |
72 | 81 | return OBJECT_MAPPER.readTree(bytes); |
... | ... | @@ -96,7 +105,7 @@ public class JacksonUtil { |
96 | 105 | } |
97 | 106 | } |
98 | 107 | |
99 | - public static ObjectNode newObjectNode(){ | |
108 | + public static ObjectNode newObjectNode() { | |
100 | 109 | return OBJECT_MAPPER.createObjectNode(); |
101 | 110 | } |
102 | 111 | ... | ... |