Commit c4cd601dcbbbec90a83dfe8508766f7dd94e5d53

Authored by Andrew Shvayka
1 parent 7d72a467

Improvements to Tenant rules and plugins startup sequence

Showing 18 changed files with 114 additions and 97 deletions
... ... @@ -136,6 +136,9 @@ public class ActorSystemContext {
136 136 @Value("${actors.statistics.persist_frequency}")
137 137 @Getter private long statisticsPersistFrequency;
138 138
  139 + @Value("${actors.tenant.create_components_on_init}")
  140 + @Getter private boolean tenantComponentsInitEnabled;
  141 +
139 142 @Getter @Setter private ActorSystem actorSystem;
140 143
141 144 @Getter @Setter private ActorRef appActor;
... ...
... ... @@ -174,7 +174,7 @@ public class AppActor extends ContextAwareActor {
174 174 TenantId tenantId = toDeviceActorMsg.getTenantId();
175 175 ActorRef tenantActor = getOrCreateTenantActor(tenantId);
176 176 if (toDeviceActorMsg.getPayload().getMsgType().requiresRulesProcessing()) {
177   - tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain()), context().self());
  177 + tenantActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, ruleManager.getRuleChain(this.context())), context().self());
178 178 } else {
179 179 tenantActor.tell(toDeviceActorMsg, context().self());
180 180 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.actors.shared.plugin;
17 17
  18 +import akka.actor.ActorContext;
18 19 import org.thingsboard.server.actors.ActorSystemContext;
19 20 import org.thingsboard.server.actors.service.DefaultActorService;
20 21 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -30,6 +31,12 @@ public class TenantPluginManager extends PluginManager {
30 31 this.tenantId = tenantId;
31 32 }
32 33
  34 + public void init(ActorContext context) {
  35 + if (systemContext.isTenantComponentsInitEnabled()) {
  36 + super.init(context);
  37 + }
  38 + }
  39 +
33 40 @Override
34 41 FetchFunction<PluginMetaData> getFetchPluginsFunction() {
35 42 return link -> pluginService.findTenantPlugins(tenantId, link);
... ...
... ... @@ -25,7 +25,6 @@ import org.thingsboard.server.actors.rule.RuleActorChain;
25 25 import org.thingsboard.server.actors.rule.RuleActorMetaData;
26 26 import org.thingsboard.server.actors.rule.SimpleRuleActorChain;
27 27 import org.thingsboard.server.actors.service.ContextAwareActor;
28   -import org.thingsboard.server.actors.service.DefaultActorService;
29 28 import org.thingsboard.server.common.data.id.RuleId;
30 29 import org.thingsboard.server.common.data.id.TenantId;
31 30 import org.thingsboard.server.common.data.page.PageDataIterable;
... ... @@ -72,6 +71,9 @@ public abstract class RuleManager {
72 71 }
73 72
74 73 public Optional<ActorRef> update(ActorContext context, RuleId ruleId, ComponentLifecycleEvent event) {
  74 + if (ruleMap == null) {
  75 + init(context);
  76 + }
75 77 RuleMetaData rule;
76 78 if (event != ComponentLifecycleEvent.DELETED) {
77 79 rule = systemContext.getRuleService().findRuleById(ruleId);
... ... @@ -111,11 +113,13 @@ public abstract class RuleManager {
111 113 .withDispatcher(getDispatcherName()), rId.toString()));
112 114 }
113 115
114   - public RuleActorChain getRuleChain() {
  116 + public RuleActorChain getRuleChain(ActorContext context) {
  117 + if (ruleMap == null) {
  118 + init(context);
  119 + }
115 120 return ruleChain;
116 121 }
117 122
118   -
119 123 private void refreshRuleChain() {
120 124 Set<RuleActorMetaData> activeRuleSet = new HashSet<>();
121 125 for (Map.Entry<RuleMetaData, RuleActorMetaData> rule : ruleMap.entrySet()) {
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.actors.shared.rule;
17 17
  18 +import akka.actor.ActorContext;
18 19 import org.thingsboard.server.actors.ActorSystemContext;
19 20 import org.thingsboard.server.actors.service.DefaultActorService;
20 21 import org.thingsboard.server.common.data.id.TenantId;
... ... @@ -27,6 +28,12 @@ public class TenantRuleManager extends RuleManager {
27 28 super(systemContext, tenantId);
28 29 }
29 30
  31 + public void init(ActorContext context) {
  32 + if (systemContext.isTenantComponentsInitEnabled()) {
  33 + super.init(context);
  34 + }
  35 + }
  36 +
30 37 @Override
31 38 FetchFunction<RuleMetaData> getFetchRulesFunction() {
32 39 return link -> ruleService.findTenantRules(tenantId, link);
... ...
... ... @@ -151,18 +151,13 @@ public class TenantActor extends ContextAwareActor {
151 151 private void process(RuleChainDeviceMsg msg) {
152 152 ToDeviceActorMsg toDeviceActorMsg = msg.getToDeviceActorMsg();
153 153 ActorRef deviceActor = getOrCreateDeviceActor(toDeviceActorMsg.getDeviceId());
154   - RuleActorChain chain = new ComplexRuleActorChain(msg.getRuleChain(), ruleManager.getRuleChain());
  154 + RuleActorChain chain = new ComplexRuleActorChain(msg.getRuleChain(), ruleManager.getRuleChain(this.context()));
155 155 deviceActor.tell(new RuleChainDeviceMsg(toDeviceActorMsg, chain), context().self());
156 156 }
157 157
158 158 private ActorRef getOrCreateDeviceActor(DeviceId deviceId) {
159   - ActorRef deviceActor = deviceActors.get(deviceId);
160   - if (deviceActor == null) {
161   - deviceActor = context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId))
162   - .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), deviceId.toString());
163   - deviceActors.put(deviceId, deviceActor);
164   - }
165   - return deviceActor;
  159 + return deviceActors.computeIfAbsent(deviceId, k -> context().actorOf(Props.create(new DeviceActor.ActorCreator(systemContext, tenantId, deviceId))
  160 + .withDispatcher(DefaultActorService.CORE_DISPATCHER_NAME), deviceId.toString()));
166 161 }
167 162
168 163 public static class ActorCreator extends ContextBasedCreator<TenantActor> {
... ...
... ... @@ -15,30 +15,16 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
18   -import com.google.common.util.concurrent.ListenableFuture;
19 18 import org.apache.commons.lang3.StringUtils;
20 19 import org.springframework.http.HttpStatus;
21 20 import org.springframework.security.access.prepost.PreAuthorize;
22 21 import org.springframework.web.bind.annotation.*;
23   -import org.thingsboard.server.common.data.Customer;
24   -import org.thingsboard.server.common.data.Event;
25 22 import org.thingsboard.server.common.data.alarm.*;
26   -import org.thingsboard.server.common.data.asset.Asset;
27 23 import org.thingsboard.server.common.data.id.*;
28   -import org.thingsboard.server.common.data.page.TextPageData;
29   -import org.thingsboard.server.common.data.page.TextPageLink;
30 24 import org.thingsboard.server.common.data.page.TimePageData;
31 25 import org.thingsboard.server.common.data.page.TimePageLink;
32   -import org.thingsboard.server.dao.asset.AssetSearchQuery;
33   -import org.thingsboard.server.dao.exception.IncorrectParameterException;
34   -import org.thingsboard.server.dao.model.ModelConstants;
35 26 import org.thingsboard.server.exception.ThingsboardErrorCode;
36 27 import org.thingsboard.server.exception.ThingsboardException;
37   -import org.thingsboard.server.service.security.model.SecurityUser;
38   -
39   -import java.util.ArrayList;
40   -import java.util.List;
41   -import java.util.stream.Collectors;
42 28
43 29 @RestController
44 30 @RequestMapping("/api")
... ...
... ... @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
27 27 import org.thingsboard.server.common.data.id.TenantId;
28 28 import org.thingsboard.server.common.data.page.TextPageData;
29 29 import org.thingsboard.server.common.data.page.TextPageLink;
30   -import org.thingsboard.server.dao.asset.AssetSearchQuery;
  30 +import org.thingsboard.server.common.data.asset.AssetSearchQuery;
31 31 import org.thingsboard.server.dao.exception.IncorrectParameterException;
32 32 import org.thingsboard.server.dao.model.ModelConstants;
33 33 import org.thingsboard.server.exception.ThingsboardException;
... ...
... ... @@ -28,7 +28,7 @@ import org.thingsboard.server.common.data.id.TenantId;
28 28 import org.thingsboard.server.common.data.page.TextPageData;
29 29 import org.thingsboard.server.common.data.page.TextPageLink;
30 30 import org.thingsboard.server.common.data.security.DeviceCredentials;
31   -import org.thingsboard.server.dao.device.DeviceSearchQuery;
  31 +import org.thingsboard.server.common.data.device.DeviceSearchQuery;
32 32 import org.thingsboard.server.dao.exception.IncorrectParameterException;
33 33 import org.thingsboard.server.dao.model.ModelConstants;
34 34 import org.thingsboard.server.exception.ThingsboardException;
... ...
... ... @@ -159,6 +159,8 @@ cassandra:
159 159
160 160 # Actor system parameters
161 161 actors:
  162 + tenant:
  163 + create_components_on_init: true
162 164 session:
163 165 sync:
164 166 # Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds
... ...
... ... @@ -97,28 +97,28 @@ public abstract class AbstractControllerTest {
97 97
98 98 protected static final String SYS_ADMIN_EMAIL = "sysadmin@thingsboard.org";
99 99 private static final String SYS_ADMIN_PASSWORD = "sysadmin";
100   -
  100 +
101 101 protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
102 102 private static final String TENANT_ADMIN_PASSWORD = "tenant";
103 103
104 104 protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
105 105 private static final String CUSTOMER_USER_PASSWORD = "customer";
106   -
  106 +
107 107 protected MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
108 108 MediaType.APPLICATION_JSON.getSubtype(),
109 109 Charset.forName("utf8"));
110 110
111 111 protected MockMvc mockMvc;
112   -
  112 +
113 113 protected String token;
114 114 protected String refreshToken;
115 115 protected String username;
116 116
117 117 private TenantId tenantId;
118   -
  118 +
119 119 @SuppressWarnings("rawtypes")
120 120 private HttpMessageConverter mappingJackson2HttpMessageConverter;
121   -
  121 +
122 122 @Autowired
123 123 private WebApplicationContext webApplicationContext;
124 124
... ... @@ -132,7 +132,7 @@ public abstract class AbstractControllerTest {
132 132 log.info("Finished test: {}", description.getMethodName());
133 133 }
134 134 };
135   -
  135 +
136 136 @Autowired
137 137 void setConverters(HttpMessageConverter<?>[] converters) {
138 138
... ... @@ -144,7 +144,7 @@ public abstract class AbstractControllerTest {
144 144 Assert.assertNotNull("the JSON message converter must not be null",
145 145 this.mappingJackson2HttpMessageConverter);
146 146 }
147   -
  147 +
148 148 @Before
149 149 public void setup() throws Exception {
150 150 log.info("Executing setup");
... ... @@ -188,7 +188,7 @@ public abstract class AbstractControllerTest {
188 188 public void teardown() throws Exception {
189 189 log.info("Executing teardown");
190 190 loginSysAdmin();
191   - doDelete("/api/tenant/"+tenantId.getId().toString())
  191 + doDelete("/api/tenant/" + tenantId.getId().toString())
192 192 .andExpect(status().isOk());
193 193 log.info("Executed teardown");
194 194 }
... ... @@ -196,7 +196,7 @@ public abstract class AbstractControllerTest {
196 196 protected void loginSysAdmin() throws Exception {
197 197 login(SYS_ADMIN_EMAIL, SYS_ADMIN_PASSWORD);
198 198 }
199   -
  199 +
200 200 protected void loginTenantAdmin() throws Exception {
201 201 login(TENANT_ADMIN_EMAIL, TENANT_ADMIN_PASSWORD);
202 202 }
... ... @@ -204,13 +204,13 @@ public abstract class AbstractControllerTest {
204 204 protected void loginCustomerUser() throws Exception {
205 205 login(CUSTOMER_USER_EMAIL, CUSTOMER_USER_PASSWORD);
206 206 }
207   -
  207 +
208 208 protected User createUserAndLogin(User user, String password) throws Exception {
209 209 User savedUser = doPost("/api/user", user, User.class);
210 210 logout();
211 211 doGet("/api/noauth/activate?activateToken={activateToken}", TestMailService.currentActivateToken)
212   - .andExpect(status().isSeeOther())
213   - .andExpect(header().string(HttpHeaders.LOCATION, "/login/createPassword?activateToken=" + TestMailService.currentActivateToken));
  212 + .andExpect(status().isSeeOther())
  213 + .andExpect(header().string(HttpHeaders.LOCATION, "/login/createPassword?activateToken=" + TestMailService.currentActivateToken));
214 214 JsonNode tokenInfo = readResponse(doPost("/api/noauth/activate", "activateToken", TestMailService.currentActivateToken, "password", password).andExpect(status().isOk()), JsonNode.class);
215 215 validateAndSetJwtToken(tokenInfo, user.getEmail());
216 216 return savedUser;
... ... @@ -247,14 +247,14 @@ public abstract class AbstractControllerTest {
247 247 Assert.assertNotNull(token);
248 248 Assert.assertFalse(token.isEmpty());
249 249 int i = token.lastIndexOf('.');
250   - Assert.assertTrue(i>0);
251   - String withoutSignature = token.substring(0, i+1);
252   - Jwt<Header,Claims> jwsClaims = Jwts.parser().parseClaimsJwt(withoutSignature);
  250 + Assert.assertTrue(i > 0);
  251 + String withoutSignature = token.substring(0, i + 1);
  252 + Jwt<Header, Claims> jwsClaims = Jwts.parser().parseClaimsJwt(withoutSignature);
253 253 Claims claims = jwsClaims.getBody();
254 254 String subject = claims.getSubject();
255 255 Assert.assertEquals(username, subject);
256 256 }
257   -
  257 +
258 258 protected void logout() throws Exception {
259 259 this.token = null;
260 260 this.refreshToken = null;
... ... @@ -266,24 +266,24 @@ public abstract class AbstractControllerTest {
266 266 request.header(ThingsboardSecurityConfiguration.JWT_TOKEN_HEADER_PARAM, "Bearer " + this.token);
267 267 }
268 268 }
269   -
  269 +
270 270 protected ResultActions doGet(String urlTemplate, Object... urlVariables) throws Exception {
271 271 MockHttpServletRequestBuilder getRequest = get(urlTemplate, urlVariables);
272 272 setJwtToken(getRequest);
273 273 return mockMvc.perform(getRequest);
274 274 }
275   -
  275 +
276 276 protected <T> T doGet(String urlTemplate, Class<T> responseClass, Object... urlVariables) throws Exception {
277 277 return readResponse(doGet(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass);
278 278 }
279   -
  279 +
280 280 protected <T> T doGetTyped(String urlTemplate, TypeReference<T> responseType, Object... urlVariables) throws Exception {
281 281 return readResponse(doGet(urlTemplate, urlVariables).andExpect(status().isOk()), responseType);
282 282 }
283   -
  283 +
284 284 protected <T> T doGetTypedWithPageLink(String urlTemplate, TypeReference<T> responseType,
285   - TextPageLink pageLink,
286   - Object... urlVariables) throws Exception {
  285 + TextPageLink pageLink,
  286 + Object... urlVariables) throws Exception {
287 287 List<Object> pageLinkVariables = new ArrayList<>();
288 288 urlTemplate += "limit={limit}";
289 289 pageLinkVariables.add(pageLink.getLimit());
... ... @@ -299,18 +299,18 @@ public abstract class AbstractControllerTest {
299 299 urlTemplate += "&textOffset={textOffset}";
300 300 pageLinkVariables.add(pageLink.getTextOffset());
301 301 }
302   -
303   - Object[] vars = new Object[urlVariables.length + pageLinkVariables.size()];
  302 +
  303 + Object[] vars = new Object[urlVariables.length + pageLinkVariables.size()];
304 304 System.arraycopy(urlVariables, 0, vars, 0, urlVariables.length);
305 305 System.arraycopy(pageLinkVariables.toArray(), 0, vars, urlVariables.length, pageLinkVariables.size());
306   -
  306 +
307 307 return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType);
308 308 }
309   -
  309 +
310 310 protected <T> T doPost(String urlTemplate, Class<T> responseClass, String... params) throws Exception {
311 311 return readResponse(doPost(urlTemplate, params).andExpect(status().isOk()), responseClass);
312 312 }
313   -
  313 +
314 314 protected <T> T doPost(String urlTemplate, T content, Class<T> responseClass, String... params) throws Exception {
315 315 return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass);
316 316 }
... ... @@ -318,15 +318,15 @@ public abstract class AbstractControllerTest {
318 318 protected <T> T doDelete(String urlTemplate, Class<T> responseClass, String... params) throws Exception {
319 319 return readResponse(doDelete(urlTemplate, params).andExpect(status().isOk()), responseClass);
320 320 }
321   -
  321 +
322 322 protected ResultActions doPost(String urlTemplate, String... params) throws Exception {
323 323 MockHttpServletRequestBuilder postRequest = post(urlTemplate);
324 324 setJwtToken(postRequest);
325 325 populateParams(postRequest, params);
326 326 return mockMvc.perform(postRequest);
327 327 }
328   -
329   - protected <T> ResultActions doPost(String urlTemplate, T content, String... params) throws Exception {
  328 +
  329 + protected <T> ResultActions doPost(String urlTemplate, T content, String... params) throws Exception {
330 330 MockHttpServletRequestBuilder postRequest = post(urlTemplate);
331 331 setJwtToken(postRequest);
332 332 String json = json(content);
... ... @@ -334,25 +334,25 @@ public abstract class AbstractControllerTest {
334 334 populateParams(postRequest, params);
335 335 return mockMvc.perform(postRequest);
336 336 }
337   -
  337 +
338 338 protected ResultActions doDelete(String urlTemplate, String... params) throws Exception {
339 339 MockHttpServletRequestBuilder deleteRequest = delete(urlTemplate);
340 340 setJwtToken(deleteRequest);
341 341 populateParams(deleteRequest, params);
342 342 return mockMvc.perform(deleteRequest);
343 343 }
344   -
  344 +
345 345 protected void populateParams(MockHttpServletRequestBuilder request, String... params) {
346 346 if (params != null && params.length > 0) {
347 347 Assert.assertEquals(params.length % 2, 0);
348 348 MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<String, String>();
349   - for (int i=0;i<params.length;i+=2) {
350   - paramsMap.add(params[i], params[i+1]);
  349 + for (int i = 0; i < params.length; i += 2) {
  350 + paramsMap.add(params[i], params[i + 1]);
351 351 }
352 352 request.params(paramsMap);
353 353 }
354 354 }
355   -
  355 +
356 356 @SuppressWarnings("unchecked")
357 357 protected String json(Object o) throws IOException {
358 358 MockHttpOutputMessage mockHttpOutputMessage = new MockHttpOutputMessage();
... ... @@ -360,14 +360,14 @@ public abstract class AbstractControllerTest {
360 360 o, MediaType.APPLICATION_JSON, mockHttpOutputMessage);
361 361 return mockHttpOutputMessage.getBodyAsString();
362 362 }
363   -
  363 +
364 364 @SuppressWarnings("unchecked")
365 365 protected <T> T readResponse(ResultActions result, Class<T> responseClass) throws Exception {
366 366 byte[] content = result.andReturn().getResponse().getContentAsByteArray();
367 367 MockHttpInputMessage mockHttpInputMessage = new MockHttpInputMessage(content);
368 368 return (T) this.mappingJackson2HttpMessageConverter.read(responseClass, mockHttpInputMessage);
369 369 }
370   -
  370 +
371 371 protected <T> T readResponse(ResultActions result, TypeReference<T> type) throws Exception {
372 372 byte[] content = result.andReturn().getResponse().getContentAsByteArray();
373 373 ObjectMapper mapper = new ObjectMapper();
... ...
common/data/src/main/java/org/thingsboard/server/common/data/asset/AssetSearchQuery.java renamed from dao/src/main/java/org/thingsboard/server/dao/asset/AssetSearchQuery.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.asset;
  16 +package org.thingsboard.server.common.data.asset;
17 17
18 18 import lombok.Data;
19 19 import org.thingsboard.server.common.data.EntityType;
... ... @@ -22,7 +22,6 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
22 22 import org.thingsboard.server.common.data.relation.EntityTypeFilter;
23 23 import org.thingsboard.server.common.data.relation.RelationsSearchParameters;
24 24
25   -import javax.annotation.Nullable;
26 25 import java.util.Collections;
27 26 import java.util.List;
28 27
... ... @@ -33,9 +32,7 @@ import java.util.List;
33 32 public class AssetSearchQuery {
34 33
35 34 private RelationsSearchParameters parameters;
36   - @Nullable
37 35 private String relationType;
38   - @Nullable
39 36 private List<String> assetTypes;
40 37
41 38 public EntityRelationsQuery toEntitySearchQuery() {
... ...
dao/src/main/java/org/thingsboard/server/common/data/device/DeviceSearchQuery.java renamed from dao/src/main/java/org/thingsboard/server/dao/device/DeviceSearchQuery.java
... ... @@ -13,7 +13,7 @@
13 13 * See the License for the specific language governing permissions and
14 14 * limitations under the License.
15 15 */
16   -package org.thingsboard.server.dao.device;
  16 +package org.thingsboard.server.common.data.device;
17 17
18 18 import lombok.Data;
19 19 import org.thingsboard.server.common.data.EntityType;
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.asset;
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.EntitySubtype;
20 20 import org.thingsboard.server.common.data.asset.Asset;
  21 +import org.thingsboard.server.common.data.asset.AssetSearchQuery;
21 22 import org.thingsboard.server.common.data.id.AssetId;
22 23 import org.thingsboard.server.common.data.id.CustomerId;
23 24 import org.thingsboard.server.common.data.id.TenantId;
... ...
... ... @@ -29,6 +29,7 @@ import org.thingsboard.server.common.data.EntitySubtype;
29 29 import org.thingsboard.server.common.data.EntityType;
30 30 import org.thingsboard.server.common.data.Tenant;
31 31 import org.thingsboard.server.common.data.asset.Asset;
  32 +import org.thingsboard.server.common.data.asset.AssetSearchQuery;
32 33 import org.thingsboard.server.common.data.id.AssetId;
33 34 import org.thingsboard.server.common.data.id.CustomerId;
34 35 import org.thingsboard.server.common.data.id.EntityId;
... ...
... ... @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.device;
18 18 import com.google.common.util.concurrent.ListenableFuture;
19 19 import org.thingsboard.server.common.data.Device;
20 20 import org.thingsboard.server.common.data.EntitySubtype;
  21 +import org.thingsboard.server.common.data.device.DeviceSearchQuery;
21 22 import org.thingsboard.server.common.data.id.CustomerId;
22 23 import org.thingsboard.server.common.data.id.DeviceId;
23 24 import org.thingsboard.server.common.data.id.TenantId;
... ...
... ... @@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired;
25 25 import org.springframework.stereotype.Service;
26 26 import org.springframework.util.StringUtils;
27 27 import org.thingsboard.server.common.data.*;
  28 +import org.thingsboard.server.common.data.device.DeviceSearchQuery;
28 29 import org.thingsboard.server.common.data.id.CustomerId;
29 30 import org.thingsboard.server.common.data.id.DeviceId;
30 31 import org.thingsboard.server.common.data.id.EntityId;
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.transport.mqtt;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
  19 +import io.netty.channel.Channel;
19 20 import io.netty.channel.ChannelHandlerContext;
20 21 import io.netty.channel.ChannelInboundHandlerAdapter;
21 22 import io.netty.handler.codec.mqtt.*;
... ... @@ -45,6 +46,8 @@ import org.thingsboard.server.transport.mqtt.util.SslUtil;
45 46
46 47 import javax.net.ssl.SSLPeerUnverifiedException;
47 48 import javax.security.cert.X509Certificate;
  49 +import java.net.InetSocketAddress;
  50 +import java.net.SocketAddress;
48 51 import java.util.ArrayList;
49 52 import java.util.List;
50 53
... ... @@ -71,6 +74,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
71 74 private final RelationService relationService;
72 75 private final SslHandler sslHandler;
73 76 private volatile boolean connected;
  77 + private volatile InetSocketAddress address;
74 78 private volatile GatewaySessionCtx gatewaySessionCtx;
75 79
76 80 public MqttTransportHandler(SessionMsgProcessor processor, DeviceService deviceService, DeviceAuthService authService, RelationService relationService,
... ... @@ -94,30 +98,36 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
94 98 }
95 99
96 100 private void processMqttMsg(ChannelHandlerContext ctx, MqttMessage msg) {
97   - deviceSessionCtx.setChannel(ctx);
98   - switch (msg.fixedHeader().messageType()) {
99   - case CONNECT:
100   - processConnect(ctx, (MqttConnectMessage) msg);
101   - break;
102   - case PUBLISH:
103   - processPublish(ctx, (MqttPublishMessage) msg);
104   - break;
105   - case SUBSCRIBE:
106   - processSubscribe(ctx, (MqttSubscribeMessage) msg);
107   - break;
108   - case UNSUBSCRIBE:
109   - processUnsubscribe(ctx, (MqttUnsubscribeMessage) msg);
110   - break;
111   - case PINGREQ:
112   - if (checkConnected(ctx)) {
113   - ctx.writeAndFlush(new MqttMessage(new MqttFixedHeader(PINGRESP, false, AT_MOST_ONCE, false, 0)));
114   - }
115   - break;
116   - case DISCONNECT:
117   - if (checkConnected(ctx)) {
118   - processDisconnect(ctx);
119   - }
120   - break;
  101 + address = (InetSocketAddress) ctx.channel().remoteAddress();
  102 + if (msg.fixedHeader() == null) {
  103 + log.info("[{}:{}] Invalid message received", address.getHostName(), address.getPort());
  104 + processDisconnect(ctx);
  105 + } else {
  106 + deviceSessionCtx.setChannel(ctx);
  107 + switch (msg.fixedHeader().messageType()) {
  108 + case CONNECT:
  109 + processConnect(ctx, (MqttConnectMessage) msg);
  110 + break;
  111 + case PUBLISH:
  112 + processPublish(ctx, (MqttPublishMessage) msg);
  113 + break;
  114 + case SUBSCRIBE:
  115 + processSubscribe(ctx, (MqttSubscribeMessage) msg);
  116 + break;
  117 + case UNSUBSCRIBE:
  118 + processUnsubscribe(ctx, (MqttUnsubscribeMessage) msg);
  119 + break;
  120 + case PINGREQ:
  121 + if (checkConnected(ctx)) {
  122 + ctx.writeAndFlush(new MqttMessage(new MqttFixedHeader(PINGRESP, false, AT_MOST_ONCE, false, 0)));
  123 + }
  124 + break;
  125 + case DISCONNECT:
  126 + if (checkConnected(ctx)) {
  127 + processDisconnect(ctx);
  128 + }
  129 + break;
  130 + }
121 131 }
122 132 }
123 133
... ... @@ -313,9 +323,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
313 323
314 324 private void processDisconnect(ChannelHandlerContext ctx) {
315 325 ctx.close();
316   - processor.process(SessionCloseMsg.onDisconnect(deviceSessionCtx.getSessionId()));
317   - if (gatewaySessionCtx != null) {
318   - gatewaySessionCtx.onGatewayDisconnect();
  326 + if (connected) {
  327 + processor.process(SessionCloseMsg.onDisconnect(deviceSessionCtx.getSessionId()));
  328 + if (gatewaySessionCtx != null) {
  329 + gatewaySessionCtx.onGatewayDisconnect();
  330 + }
319 331 }
320 332 }
321 333
... ...