Showing
38 changed files
with
283 additions
and
225 deletions
... | ... | @@ -32,6 +32,8 @@ import org.thingsboard.server.actors.shared.rule.SystemRuleManager; |
32 | 32 | import org.thingsboard.server.actors.tenant.RuleChainDeviceMsg; |
33 | 33 | import org.thingsboard.server.actors.tenant.TenantActor; |
34 | 34 | import org.thingsboard.server.common.data.Tenant; |
35 | +import org.thingsboard.server.common.data.id.PluginId; | |
36 | +import org.thingsboard.server.common.data.id.RuleId; | |
35 | 37 | import org.thingsboard.server.common.data.id.TenantId; |
36 | 38 | import org.thingsboard.server.common.data.page.PageDataIterable; |
37 | 39 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
... | ... | @@ -149,14 +151,16 @@ public class AppActor extends ContextAwareActor { |
149 | 151 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
150 | 152 | ActorRef target = null; |
151 | 153 | if (SYSTEM_TENANT.equals(msg.getTenantId())) { |
152 | - if (msg.getPluginId().isPresent()) { | |
153 | - target = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId().get()); | |
154 | - } else if (msg.getRuleId().isPresent()) { | |
155 | - Optional<ActorRef> ref = ruleManager.update(this.context(), msg.getRuleId().get(), msg.getEvent()); | |
154 | + Optional<PluginId> pluginId = msg.getPluginId(); | |
155 | + Optional<RuleId> ruleId = msg.getRuleId(); | |
156 | + if (pluginId.isPresent()) { | |
157 | + target = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get()); | |
158 | + } else if (ruleId.isPresent()) { | |
159 | + Optional<ActorRef> ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent()); | |
156 | 160 | if (ref.isPresent()) { |
157 | 161 | target = ref.get(); |
158 | 162 | } else { |
159 | - logger.debug("Failed to find actor for rule: [{}]", msg.getRuleId()); | |
163 | + logger.debug("Failed to find actor for rule: [{}]", ruleId); | |
160 | 164 | return; |
161 | 165 | } |
162 | 166 | } | ... | ... |
... | ... | @@ -32,6 +32,8 @@ import org.thingsboard.server.actors.shared.plugin.TenantPluginManager; |
32 | 32 | import org.thingsboard.server.actors.shared.rule.RuleManager; |
33 | 33 | import org.thingsboard.server.actors.shared.rule.TenantRuleManager; |
34 | 34 | import org.thingsboard.server.common.data.id.DeviceId; |
35 | +import org.thingsboard.server.common.data.id.PluginId; | |
36 | +import org.thingsboard.server.common.data.id.RuleId; | |
35 | 37 | import org.thingsboard.server.common.data.id.TenantId; |
36 | 38 | import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; |
37 | 39 | import org.thingsboard.server.common.msg.device.ToDeviceActorMsg; |
... | ... | @@ -126,16 +128,18 @@ public class TenantActor extends ContextAwareActor { |
126 | 128 | } |
127 | 129 | |
128 | 130 | private void onComponentLifecycleMsg(ComponentLifecycleMsg msg) { |
129 | - if (msg.getPluginId().isPresent()) { | |
130 | - ActorRef pluginActor = pluginManager.getOrCreatePluginActor(this.context(), msg.getPluginId().get()); | |
131 | + Optional<PluginId> pluginId = msg.getPluginId(); | |
132 | + Optional<RuleId> ruleId = msg.getRuleId(); | |
133 | + if (pluginId.isPresent()) { | |
134 | + ActorRef pluginActor = pluginManager.getOrCreatePluginActor(this.context(), pluginId.get()); | |
131 | 135 | pluginActor.tell(msg, ActorRef.noSender()); |
132 | - } else if (msg.getRuleId().isPresent()) { | |
136 | + } else if (ruleId.isPresent()) { | |
133 | 137 | ActorRef target; |
134 | - Optional<ActorRef> ref = ruleManager.update(this.context(), msg.getRuleId().get(), msg.getEvent()); | |
138 | + Optional<ActorRef> ref = ruleManager.update(this.context(), ruleId.get(), msg.getEvent()); | |
135 | 139 | if (ref.isPresent()) { |
136 | 140 | target = ref.get(); |
137 | 141 | } else { |
138 | - logger.debug("Failed to find actor for rule: [{}]", msg.getRuleId()); | |
142 | + logger.debug("Failed to find actor for rule: [{}]", ruleId); | |
139 | 143 | return; |
140 | 144 | } |
141 | 145 | target.tell(msg, ActorRef.noSender()); | ... | ... |
... | ... | @@ -64,7 +64,7 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt |
64 | 64 | public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/api/auth/login"; |
65 | 65 | public static final String PUBLIC_LOGIN_ENTRY_POINT = "/api/auth/login/public"; |
66 | 66 | public static final String TOKEN_REFRESH_ENTRY_POINT = "/api/auth/token"; |
67 | - public static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/static/**", "/api/noauth/**", "/webjars/**"}; | |
67 | + protected static final String[] NON_TOKEN_BASED_AUTH_ENTRY_POINTS = new String[] {"/index.html", "/static/**", "/api/noauth/**", "/webjars/**"}; | |
68 | 68 | public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/api/**"; |
69 | 69 | public static final String WS_TOKEN_BASED_AUTH_ENTRY_POINT = "/api/ws/**"; |
70 | 70 | ... | ... |
... | ... | @@ -103,13 +103,13 @@ public class AuthController extends BaseController { |
103 | 103 | HttpStatus responseStatus; |
104 | 104 | UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(activateToken); |
105 | 105 | if (userCredentials != null) { |
106 | - String createPasswordURI = "/login/createPassword"; | |
106 | + String createURI = "/login/createPassword"; | |
107 | 107 | try { |
108 | - URI location = new URI(createPasswordURI + "?activateToken=" + activateToken); | |
108 | + URI location = new URI(createURI + "?activateToken=" + activateToken); | |
109 | 109 | headers.setLocation(location); |
110 | 110 | responseStatus = HttpStatus.SEE_OTHER; |
111 | 111 | } catch (URISyntaxException e) { |
112 | - log.error("Unable to create URI with address [{}]", createPasswordURI); | |
112 | + log.error("Unable to create URI with address [{}]", createURI); | |
113 | 113 | responseStatus = HttpStatus.BAD_REQUEST; |
114 | 114 | } |
115 | 115 | } else { |
... | ... | @@ -126,10 +126,10 @@ public class AuthController extends BaseController { |
126 | 126 | try { |
127 | 127 | UserCredentials userCredentials = userService.requestPasswordReset(email); |
128 | 128 | String baseUrl = constructBaseUrl(request); |
129 | - String resetPasswordUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, | |
129 | + String resetUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, | |
130 | 130 | userCredentials.getResetToken()); |
131 | 131 | |
132 | - mailService.sendResetPasswordEmail(resetPasswordUrl, email); | |
132 | + mailService.sendResetPasswordEmail(resetUrl, email); | |
133 | 133 | } catch (Exception e) { |
134 | 134 | throw handleException(e); |
135 | 135 | } |
... | ... | @@ -140,15 +140,15 @@ public class AuthController extends BaseController { |
140 | 140 | @RequestParam(value = "resetToken") String resetToken) { |
141 | 141 | HttpHeaders headers = new HttpHeaders(); |
142 | 142 | HttpStatus responseStatus; |
143 | - String resetPasswordURI = "/login/resetPassword"; | |
143 | + String resetURI = "/login/resetPassword"; | |
144 | 144 | UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); |
145 | 145 | if (userCredentials != null) { |
146 | 146 | try { |
147 | - URI location = new URI(resetPasswordURI + "?resetToken=" + resetToken); | |
147 | + URI location = new URI(resetURI + "?resetToken=" + resetToken); | |
148 | 148 | headers.setLocation(location); |
149 | 149 | responseStatus = HttpStatus.SEE_OTHER; |
150 | 150 | } catch (URISyntaxException e) { |
151 | - log.error("Unable to create URI with address [{}]", resetPasswordURI); | |
151 | + log.error("Unable to create URI with address [{}]", resetURI); | |
152 | 152 | responseStatus = HttpStatus.BAD_REQUEST; |
153 | 153 | } |
154 | 154 | } else { | ... | ... |
... | ... | @@ -267,9 +267,7 @@ public class EntityRelationController extends BaseController { |
267 | 267 | if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length()>0) { |
268 | 268 | try { |
269 | 269 | result = RelationTypeGroup.valueOf(strRelationTypeGroup); |
270 | - } catch (IllegalArgumentException e) { | |
271 | - result = defaultValue; | |
272 | - } | |
270 | + } catch (IllegalArgumentException e) { } | |
273 | 271 | } |
274 | 272 | return result; |
275 | 273 | } | ... | ... |
... | ... | @@ -71,7 +71,7 @@ public class PluginApiController extends BaseController { |
71 | 71 | TenantId tenantId = getCurrentUser().getTenantId(); |
72 | 72 | CustomerId customerId = getCurrentUser().getCustomerId(); |
73 | 73 | if (validatePluginAccess(pluginMd, tenantId, customerId)) { |
74 | - if(ModelConstants.NULL_UUID.equals(tenantId.getId())){ | |
74 | + if(tenantId != null && ModelConstants.NULL_UUID.equals(tenantId.getId())){ | |
75 | 75 | tenantId = null; |
76 | 76 | } |
77 | 77 | PluginApiCallSecurityContext securityCtx = new PluginApiCallSecurityContext(pluginMd.getTenantId(), pluginMd.getId(), tenantId, customerId); |
... | ... | @@ -97,7 +97,7 @@ public class PluginApiController extends BaseController { |
97 | 97 | validUser = true; |
98 | 98 | } |
99 | 99 | } else { |
100 | - if ((pluginMd.isPublicAccess() || tenantAdministrator) && tenantId.equals(pluginMd.getTenantId())) { | |
100 | + if ((pluginMd.isPublicAccess() || tenantAdministrator) && tenantId != null && tenantId.equals(pluginMd.getTenantId())) { | |
101 | 101 | // All tenant users can access public tenant plugins. Only tenant |
102 | 102 | // administrator can access private tenant plugins |
103 | 103 | validUser = true; | ... | ... |
... | ... | @@ -95,6 +95,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
95 | 95 | future.onMsg(msg); |
96 | 96 | } catch (InterruptedException e) { |
97 | 97 | log.warn("Failed to report created session!"); |
98 | + Thread.currentThread().interrupt(); | |
98 | 99 | } |
99 | 100 | } else { |
100 | 101 | log.warn("Failed to lookup pending session!"); |
... | ... | @@ -117,6 +118,7 @@ public class ClusterGrpcService extends ClusterRpcServiceGrpc.ClusterRpcServiceI |
117 | 118 | log.info("RPC server stopped!"); |
118 | 119 | } catch (InterruptedException e) { |
119 | 120 | log.warn("Failed to onStop RPC server!"); |
121 | + Thread.currentThread().interrupt(); | |
120 | 122 | } |
121 | 123 | } |
122 | 124 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -51,6 +51,7 @@ import org.thingsboard.server.dao.widget.WidgetTypeService; |
51 | 51 | import org.thingsboard.server.dao.widget.WidgetsBundleService; |
52 | 52 | |
53 | 53 | import java.io.IOException; |
54 | +import java.nio.file.DirectoryStream; | |
54 | 55 | import java.nio.file.Files; |
55 | 56 | import java.nio.file.Path; |
56 | 57 | import java.nio.file.Paths; |
... | ... | @@ -138,7 +139,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
138 | 139 | node.put("timeout", "10000"); |
139 | 140 | node.put("enableTls", "false"); |
140 | 141 | node.put("username", ""); |
141 | - node.put("password", ""); | |
142 | + node.put("password", ""); //NOSONAR, key used to identify password field (not password value itself) | |
142 | 143 | mailSettings.setJsonValue(node); |
143 | 144 | adminSettingsService.saveAdminSettings(mailSettings); |
144 | 145 | } |
... | ... | @@ -146,33 +147,34 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
146 | 147 | @Override |
147 | 148 | public void loadSystemWidgets() throws Exception { |
148 | 149 | Path widgetBundlesDir = Paths.get(dataDir, JSON_DIR, SYSTEM_DIR, WIDGET_BUNDLES_DIR); |
149 | - Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(".json")) | |
150 | - .forEach( | |
151 | - path -> { | |
152 | - try { | |
153 | - JsonNode widgetsBundleDescriptorJson = objectMapper.readTree(path.toFile()); | |
154 | - JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle"); | |
155 | - WidgetsBundle widgetsBundle = objectMapper.treeToValue(widgetsBundleJson, WidgetsBundle.class); | |
156 | - WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); | |
157 | - JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes"); | |
158 | - widgetTypesArrayJson.forEach( | |
159 | - widgetTypeJson -> { | |
160 | - try { | |
161 | - WidgetType widgetType = objectMapper.treeToValue(widgetTypeJson, WidgetType.class); | |
162 | - widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); | |
163 | - widgetTypeService.saveWidgetType(widgetType); | |
164 | - } catch (Exception e) { | |
165 | - log.error("Unable to load widget type from json: [{}]", path.toString()); | |
166 | - throw new RuntimeException("Unable to load widget type from json", e); | |
167 | - } | |
150 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(widgetBundlesDir, path -> path.toString().endsWith(".json"))) { | |
151 | + dirStream.forEach( | |
152 | + path -> { | |
153 | + try { | |
154 | + JsonNode widgetsBundleDescriptorJson = objectMapper.readTree(path.toFile()); | |
155 | + JsonNode widgetsBundleJson = widgetsBundleDescriptorJson.get("widgetsBundle"); | |
156 | + WidgetsBundle widgetsBundle = objectMapper.treeToValue(widgetsBundleJson, WidgetsBundle.class); | |
157 | + WidgetsBundle savedWidgetsBundle = widgetsBundleService.saveWidgetsBundle(widgetsBundle); | |
158 | + JsonNode widgetTypesArrayJson = widgetsBundleDescriptorJson.get("widgetTypes"); | |
159 | + widgetTypesArrayJson.forEach( | |
160 | + widgetTypeJson -> { | |
161 | + try { | |
162 | + WidgetType widgetType = objectMapper.treeToValue(widgetTypeJson, WidgetType.class); | |
163 | + widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); | |
164 | + widgetTypeService.saveWidgetType(widgetType); | |
165 | + } catch (Exception e) { | |
166 | + log.error("Unable to load widget type from json: [{}]", path.toString()); | |
167 | + throw new RuntimeException("Unable to load widget type from json", e); | |
168 | 168 | } |
169 | - ); | |
170 | - } catch (Exception e) { | |
171 | - log.error("Unable to load widgets bundle from json: [{}]", path.toString()); | |
172 | - throw new RuntimeException("Unable to load widgets bundle from json", e); | |
173 | - } | |
169 | + } | |
170 | + ); | |
171 | + } catch (Exception e) { | |
172 | + log.error("Unable to load widgets bundle from json: [{}]", path.toString()); | |
173 | + throw new RuntimeException("Unable to load widgets bundle from json", e); | |
174 | 174 | } |
175 | - ); | |
175 | + } | |
176 | + ); | |
177 | + } | |
176 | 178 | } |
177 | 179 | |
178 | 180 | @Override |
... | ... | @@ -279,67 +281,69 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
279 | 281 | } |
280 | 282 | |
281 | 283 | private void loadPlugins(Path pluginsDir, TenantId tenantId) throws Exception{ |
282 | - Files.newDirectoryStream(pluginsDir, path -> path.toString().endsWith(".json")) | |
283 | - .forEach( | |
284 | - path -> { | |
285 | - try { | |
286 | - JsonNode pluginJson = objectMapper.readTree(path.toFile()); | |
287 | - PluginMetaData plugin = objectMapper.treeToValue(pluginJson, PluginMetaData.class); | |
288 | - plugin.setTenantId(tenantId); | |
289 | - if (plugin.getState() == ComponentLifecycleState.ACTIVE) { | |
290 | - plugin.setState(ComponentLifecycleState.SUSPENDED); | |
291 | - PluginMetaData savedPlugin = pluginService.savePlugin(plugin); | |
292 | - pluginService.activatePluginById(savedPlugin.getId()); | |
293 | - } else { | |
294 | - pluginService.savePlugin(plugin); | |
295 | - } | |
296 | - } catch (Exception e) { | |
297 | - log.error("Unable to load plugin from json: [{}]", path.toString()); | |
298 | - throw new RuntimeException("Unable to load plugin from json", e); | |
284 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(pluginsDir, path -> path.toString().endsWith(".json"))) { | |
285 | + dirStream.forEach( | |
286 | + path -> { | |
287 | + try { | |
288 | + JsonNode pluginJson = objectMapper.readTree(path.toFile()); | |
289 | + PluginMetaData plugin = objectMapper.treeToValue(pluginJson, PluginMetaData.class); | |
290 | + plugin.setTenantId(tenantId); | |
291 | + if (plugin.getState() == ComponentLifecycleState.ACTIVE) { | |
292 | + plugin.setState(ComponentLifecycleState.SUSPENDED); | |
293 | + PluginMetaData savedPlugin = pluginService.savePlugin(plugin); | |
294 | + pluginService.activatePluginById(savedPlugin.getId()); | |
295 | + } else { | |
296 | + pluginService.savePlugin(plugin); | |
299 | 297 | } |
298 | + } catch (Exception e) { | |
299 | + log.error("Unable to load plugin from json: [{}]", path.toString()); | |
300 | + throw new RuntimeException("Unable to load plugin from json", e); | |
300 | 301 | } |
301 | - ); | |
302 | - | |
302 | + } | |
303 | + ); | |
304 | + } | |
303 | 305 | } |
304 | 306 | |
305 | 307 | private void loadRules(Path rulesDir, TenantId tenantId) throws Exception { |
306 | - Files.newDirectoryStream(rulesDir, path -> path.toString().endsWith(".json")) | |
307 | - .forEach( | |
308 | - path -> { | |
309 | - try { | |
310 | - JsonNode ruleJson = objectMapper.readTree(path.toFile()); | |
311 | - RuleMetaData rule = objectMapper.treeToValue(ruleJson, RuleMetaData.class); | |
312 | - rule.setTenantId(tenantId); | |
313 | - if (rule.getState() == ComponentLifecycleState.ACTIVE) { | |
314 | - rule.setState(ComponentLifecycleState.SUSPENDED); | |
315 | - RuleMetaData savedRule = ruleService.saveRule(rule); | |
316 | - ruleService.activateRuleById(savedRule.getId()); | |
317 | - } else { | |
318 | - ruleService.saveRule(rule); | |
319 | - } | |
320 | - } catch (Exception e) { | |
321 | - log.error("Unable to load rule from json: [{}]", path.toString()); | |
322 | - throw new RuntimeException("Unable to load rule from json", e); | |
308 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(rulesDir, path -> path.toString().endsWith(".json"))) { | |
309 | + dirStream.forEach( | |
310 | + path -> { | |
311 | + try { | |
312 | + JsonNode ruleJson = objectMapper.readTree(path.toFile()); | |
313 | + RuleMetaData rule = objectMapper.treeToValue(ruleJson, RuleMetaData.class); | |
314 | + rule.setTenantId(tenantId); | |
315 | + if (rule.getState() == ComponentLifecycleState.ACTIVE) { | |
316 | + rule.setState(ComponentLifecycleState.SUSPENDED); | |
317 | + RuleMetaData savedRule = ruleService.saveRule(rule); | |
318 | + ruleService.activateRuleById(savedRule.getId()); | |
319 | + } else { | |
320 | + ruleService.saveRule(rule); | |
323 | 321 | } |
322 | + } catch (Exception e) { | |
323 | + log.error("Unable to load rule from json: [{}]", path.toString()); | |
324 | + throw new RuntimeException("Unable to load rule from json", e); | |
324 | 325 | } |
325 | - ); | |
326 | + } | |
327 | + ); | |
328 | + } | |
326 | 329 | } |
327 | 330 | |
328 | 331 | private void loadDashboards(Path dashboardsDir, TenantId tenantId, CustomerId customerId) throws Exception { |
329 | - Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(".json")) | |
330 | - .forEach( | |
331 | - path -> { | |
332 | - try { | |
333 | - JsonNode dashboardJson = objectMapper.readTree(path.toFile()); | |
334 | - Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class); | |
335 | - dashboard.setTenantId(tenantId); | |
336 | - dashboard.setCustomerId(customerId); | |
337 | - dashboardService.saveDashboard(dashboard); | |
338 | - } catch (Exception e) { | |
339 | - log.error("Unable to load dashboard from json: [{}]", path.toString()); | |
340 | - throw new RuntimeException("Unable to load dashboard from json", e); | |
341 | - } | |
332 | + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(".json"))) { | |
333 | + dirStream.forEach( | |
334 | + path -> { | |
335 | + try { | |
336 | + JsonNode dashboardJson = objectMapper.readTree(path.toFile()); | |
337 | + Dashboard dashboard = objectMapper.treeToValue(dashboardJson, Dashboard.class); | |
338 | + dashboard.setTenantId(tenantId); | |
339 | + dashboard.setCustomerId(customerId); | |
340 | + dashboardService.saveDashboard(dashboard); | |
341 | + } catch (Exception e) { | |
342 | + log.error("Unable to load dashboard from json: [{}]", path.toString()); | |
343 | + throw new RuntimeException("Unable to load dashboard from json", e); | |
342 | 344 | } |
343 | - ); | |
345 | + } | |
346 | + ); | |
347 | + } | |
344 | 348 | } |
345 | 349 | } | ... | ... |
... | ... | @@ -28,6 +28,7 @@ import java.nio.file.Path; |
28 | 28 | import java.nio.file.Paths; |
29 | 29 | import java.sql.Connection; |
30 | 30 | import java.sql.DriverManager; |
31 | +import java.sql.PreparedStatement; | |
31 | 32 | |
32 | 33 | @Service |
33 | 34 | @Profile("install") |
... | ... | @@ -58,7 +59,7 @@ public class SqlDatabaseSchemaService implements DatabaseSchemaService { |
58 | 59 | Path schemaFile = Paths.get(this.dataDir, SQL_DIR, SCHEMA_SQL); |
59 | 60 | try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { |
60 | 61 | String sql = new String(Files.readAllBytes(schemaFile), Charset.forName("UTF-8")); |
61 | - conn.createStatement().execute(sql); | |
62 | + conn.prepareStatement(sql).execute(); //NOSONAR, ignoring because method used to load initial thingsboard database schema | |
62 | 63 | } |
63 | 64 | |
64 | 65 | } | ... | ... |
... | ... | @@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletRequest; |
24 | 24 | |
25 | 25 | @Component(value="jwtHeaderTokenExtractor") |
26 | 26 | public class JwtHeaderTokenExtractor implements TokenExtractor { |
27 | - public static String HEADER_PREFIX = "Bearer "; | |
27 | + public static final String HEADER_PREFIX = "Bearer "; | |
28 | 28 | |
29 | 29 | @Override |
30 | 30 | public String extract(HttpServletRequest request) { | ... | ... |
... | ... | @@ -29,7 +29,9 @@ public class DataConstants { |
29 | 29 | public static final String SERVER_SCOPE = "SERVER_SCOPE"; |
30 | 30 | public static final String SHARED_SCOPE = "SHARED_SCOPE"; |
31 | 31 | |
32 | - public static final String[] ALL_SCOPES = {CLIENT_SCOPE, SHARED_SCOPE, SERVER_SCOPE}; | |
32 | + public static final String[] allScopes() { | |
33 | + return new String[]{CLIENT_SCOPE, SHARED_SCOPE, SERVER_SCOPE}; | |
34 | + } | |
33 | 35 | |
34 | 36 | public static final String ALARM = "ALARM"; |
35 | 37 | public static final String ERROR = "ERROR"; | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.page; |
17 | 17 | |
18 | 18 | import java.util.Iterator; |
19 | 19 | import java.util.List; |
20 | +import java.util.NoSuchElementException; | |
20 | 21 | |
21 | 22 | import org.thingsboard.server.common.data.SearchTextBased; |
22 | 23 | import org.thingsboard.server.common.data.id.UUIDBased; |
... | ... | @@ -54,7 +55,7 @@ public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> im |
54 | 55 | fetch(nextPackLink); |
55 | 56 | } |
56 | 57 | } |
57 | - return currentIdx != currentItems.size(); | |
58 | + return currentIdx < currentItems.size(); | |
58 | 59 | } |
59 | 60 | |
60 | 61 | private void fetch(TextPageLink link) { |
... | ... | @@ -67,6 +68,9 @@ public class PageDataIterable<T extends SearchTextBased<? extends UUIDBased>> im |
67 | 68 | |
68 | 69 | @Override |
69 | 70 | public T next() { |
71 | + if(!hasNext()){ | |
72 | + throw new NoSuchElementException(); | |
73 | + } | |
70 | 74 | return currentItems.get(currentIdx++); |
71 | 75 | } |
72 | 76 | ... | ... |
... | ... | @@ -46,10 +46,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; |
46 | 46 | import org.thingsboard.server.dao.tenant.TenantDao; |
47 | 47 | |
48 | 48 | import javax.annotation.Nullable; |
49 | -import java.util.ArrayList; | |
50 | -import java.util.Comparator; | |
51 | -import java.util.List; | |
52 | -import java.util.Optional; | |
49 | +import java.util.*; | |
53 | 50 | import java.util.stream.Collectors; |
54 | 51 | |
55 | 52 | import static org.thingsboard.server.dao.DaoUtil.toUUIDs; |
... | ... | @@ -210,7 +207,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ |
210 | 207 | @Nullable |
211 | 208 | @Override |
212 | 209 | public List<Asset> apply(@Nullable List<Asset> assetList) { |
213 | - return assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()); | |
210 | + return assetList == null ? Collections.emptyList() : assetList.stream().filter(asset -> query.getAssetTypes().contains(asset.getType())).collect(Collectors.toList()); | |
214 | 211 | } |
215 | 212 | }); |
216 | 213 | ... | ... |
... | ... | @@ -109,18 +109,21 @@ public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implem |
109 | 109 | stmt.setString(3, attribute.getKey()); |
110 | 110 | stmt.setLong(4, attribute.getLastUpdateTs()); |
111 | 111 | stmt.setString(5, attribute.getStrValue().orElse(null)); |
112 | - if (attribute.getBooleanValue().isPresent()) { | |
113 | - stmt.setBool(6, attribute.getBooleanValue().get()); | |
112 | + Optional<Boolean> booleanValue = attribute.getBooleanValue(); | |
113 | + if (booleanValue.isPresent()) { | |
114 | + stmt.setBool(6, booleanValue.get()); | |
114 | 115 | } else { |
115 | 116 | stmt.setToNull(6); |
116 | 117 | } |
117 | - if (attribute.getLongValue().isPresent()) { | |
118 | - stmt.setLong(7, attribute.getLongValue().get()); | |
118 | + Optional<Long> longValue = attribute.getLongValue(); | |
119 | + if (longValue.isPresent()) { | |
120 | + stmt.setLong(7, longValue.get()); | |
119 | 121 | } else { |
120 | 122 | stmt.setToNull(7); |
121 | 123 | } |
122 | - if (attribute.getDoubleValue().isPresent()) { | |
123 | - stmt.setDouble(8, attribute.getDoubleValue().get()); | |
124 | + Optional<Double> doubleValue = attribute.getDoubleValue(); | |
125 | + if (doubleValue.isPresent()) { | |
126 | + stmt.setDouble(8, doubleValue.get()); | |
124 | 127 | } else { |
125 | 128 | stmt.setToNull(8); |
126 | 129 | } | ... | ... |
... | ... | @@ -44,10 +44,7 @@ import org.thingsboard.server.dao.service.PaginatedRemover; |
44 | 44 | import org.thingsboard.server.dao.tenant.TenantDao; |
45 | 45 | |
46 | 46 | import javax.annotation.Nullable; |
47 | -import java.util.ArrayList; | |
48 | -import java.util.Comparator; | |
49 | -import java.util.List; | |
50 | -import java.util.Optional; | |
47 | +import java.util.*; | |
51 | 48 | import java.util.stream.Collectors; |
52 | 49 | |
53 | 50 | import static org.thingsboard.server.dao.DaoUtil.toUUIDs; |
... | ... | @@ -230,7 +227,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe |
230 | 227 | @Nullable |
231 | 228 | @Override |
232 | 229 | public List<Device> apply(@Nullable List<Device> deviceList) { |
233 | - return deviceList.stream().filter(device -> query.getDeviceTypes().contains(device.getType())).collect(Collectors.toList()); | |
230 | + return deviceList == null ? Collections.emptyList() : deviceList.stream().filter(device -> query.getDeviceTypes().contains(device.getType())).collect(Collectors.toList()); | |
234 | 231 | } |
235 | 232 | }); |
236 | 233 | ... | ... |
... | ... | @@ -27,8 +27,8 @@ public class ModelConstants { |
27 | 27 | private ModelConstants() { |
28 | 28 | } |
29 | 29 | |
30 | - public static UUID NULL_UUID = UUIDs.startOf(0); | |
31 | - public static String NULL_UUID_STR = UUIDConverter.fromTimeUUID(NULL_UUID); | |
30 | + public static final UUID NULL_UUID = UUIDs.startOf(0); | |
31 | + public static final String NULL_UUID_STR = UUIDConverter.fromTimeUUID(NULL_UUID); | |
32 | 32 | |
33 | 33 | /** |
34 | 34 | * Generic constants. |
... | ... | @@ -66,7 +66,7 @@ public class ModelConstants { |
66 | 66 | public static final String USER_CREDENTIALS_COLUMN_FAMILY_NAME = "user_credentials"; |
67 | 67 | public static final String USER_CREDENTIALS_USER_ID_PROPERTY = USER_ID_PROPERTY; |
68 | 68 | public static final String USER_CREDENTIALS_ENABLED_PROPERTY = "enabled"; |
69 | - public static final String USER_CREDENTIALS_PASSWORD_PROPERTY = "password"; | |
69 | + public static final String USER_CREDENTIALS_PASSWORD_PROPERTY = "password"; //NOSONAR, the constant used to identify password column name (not password value itself) | |
70 | 70 | public static final String USER_CREDENTIALS_ACTIVATE_TOKEN_PROPERTY = "activate_token"; |
71 | 71 | public static final String USER_CREDENTIALS_RESET_TOKEN_PROPERTY = "reset_token"; |
72 | 72 | |
... | ... | @@ -328,17 +328,17 @@ public class ModelConstants { |
328 | 328 | public static final String LONG_VALUE_COLUMN = "long_v"; |
329 | 329 | public static final String DOUBLE_VALUE_COLUMN = "dbl_v"; |
330 | 330 | |
331 | - public static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; | |
331 | + protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; | |
332 | 332 | |
333 | - public static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN)}; | |
333 | + protected static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN)}; | |
334 | 334 | |
335 | - public static final String[] MIN_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, | |
335 | + protected static final String[] MIN_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, | |
336 | 336 | new String[]{min(LONG_VALUE_COLUMN), min(DOUBLE_VALUE_COLUMN), min(BOOLEAN_VALUE_COLUMN), min(STRING_VALUE_COLUMN)}); |
337 | - public static final String[] MAX_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, | |
337 | + protected static final String[] MAX_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, | |
338 | 338 | new String[]{max(LONG_VALUE_COLUMN), max(DOUBLE_VALUE_COLUMN), max(BOOLEAN_VALUE_COLUMN), max(STRING_VALUE_COLUMN)}); |
339 | - public static final String[] SUM_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, | |
339 | + protected static final String[] SUM_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, | |
340 | 340 | new String[]{sum(LONG_VALUE_COLUMN), sum(DOUBLE_VALUE_COLUMN)}); |
341 | - public static final String[] AVG_AGGREGATION_COLUMNS = SUM_AGGREGATION_COLUMNS; | |
341 | + protected static final String[] AVG_AGGREGATION_COLUMNS = SUM_AGGREGATION_COLUMNS; | |
342 | 342 | |
343 | 343 | public static String min(String s) { |
344 | 344 | return "min(" + s + ")"; | ... | ... |
... | ... | @@ -57,12 +57,7 @@ public abstract class DataValidator<D extends BaseData<?>> { |
57 | 57 | } |
58 | 58 | |
59 | 59 | protected boolean isSameData(D existentData, D actualData) { |
60 | - if (actualData.getId() == null) { | |
61 | - return false; | |
62 | - } else if (!existentData.getId().equals(actualData.getId())) { | |
63 | - return false; | |
64 | - } | |
65 | - return true; | |
60 | + return actualData.getId() != null && existentData.getId().equals(actualData.getId()); | |
66 | 61 | } |
67 | 62 | |
68 | 63 | protected static void validateEmail(String email) { | ... | ... |
... | ... | @@ -117,11 +117,7 @@ public class Validator { |
117 | 117 | * @param errorMessage the error message for exception |
118 | 118 | */ |
119 | 119 | public static void validatePageLink(TextPageLink pageLink, String errorMessage) { |
120 | - if (pageLink == null) { | |
121 | - throw new IncorrectParameterException(errorMessage); | |
122 | - } else if (pageLink.getLimit() < 1) { | |
123 | - throw new IncorrectParameterException(errorMessage); | |
124 | - } else if (pageLink.getIdOffset() != null && pageLink.getIdOffset().version() != 1) { | |
120 | + if (pageLink == null || pageLink.getLimit() < 1 || (pageLink.getIdOffset() != null && pageLink.getIdOffset().version() != 1)) { | |
125 | 121 | throw new IncorrectParameterException(errorMessage); |
126 | 122 | } |
127 | 123 | } | ... | ... |
... | ... | @@ -168,7 +168,6 @@ public class JpaTimeseriesDao extends JpaAbstractDaoListeningExecutorService imp |
168 | 168 | } |
169 | 169 | }); |
170 | 170 | return Futures.transform(listenableFuture, new Function<TsKvEntity, Optional<TsKvEntry>>() { |
171 | - @Nullable | |
172 | 171 | @Override |
173 | 172 | public Optional<TsKvEntry> apply(@Nullable TsKvEntity entity) { |
174 | 173 | if (entity != null && entity.isNotEmpty()) { | ... | ... |
... | ... | @@ -42,6 +42,7 @@ import java.time.Instant; |
42 | 42 | import java.time.LocalDateTime; |
43 | 43 | import java.time.ZoneOffset; |
44 | 44 | import java.util.ArrayList; |
45 | +import java.util.Collections; | |
45 | 46 | import java.util.List; |
46 | 47 | import java.util.Optional; |
47 | 48 | import java.util.stream.Collectors; |
... | ... | @@ -136,7 +137,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem |
136 | 137 | @Nullable |
137 | 138 | @Override |
138 | 139 | public List<TsKvEntry> apply(@Nullable List<Optional<TsKvEntry>> input) { |
139 | - return input.stream().filter(v -> v.isPresent()).map(v -> v.get()).collect(Collectors.toList()); | |
140 | + return input == null ? Collections.emptyList() : input.stream().filter(v -> v.isPresent()).map(v -> v.get()).collect(Collectors.toList()); | |
140 | 141 | } |
141 | 142 | }, readResultsProcessingExecutor); |
142 | 143 | } |
... | ... | @@ -189,7 +190,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem |
189 | 190 | Futures.addCallback(executeAsyncRead(stmt), new FutureCallback<ResultSet>() { |
190 | 191 | @Override |
191 | 192 | public void onSuccess(@Nullable ResultSet result) { |
192 | - cursor.addData(convertResultToTsKvEntryList(result.all())); | |
193 | + cursor.addData(convertResultToTsKvEntryList(result == null ? Collections.emptyList() : result.all())); | |
193 | 194 | findAllAsyncSequentiallyWithLimit(cursor, resultFuture); |
194 | 195 | } |
195 | 196 | |
... | ... | @@ -523,16 +524,28 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem |
523 | 524 | private static void addValue(KvEntry kvEntry, BoundStatement stmt, int column) { |
524 | 525 | switch (kvEntry.getDataType()) { |
525 | 526 | case BOOLEAN: |
526 | - stmt.setBool(column, kvEntry.getBooleanValue().get().booleanValue()); | |
527 | + Optional<Boolean> booleanValue = kvEntry.getBooleanValue(); | |
528 | + if (booleanValue.isPresent()) { | |
529 | + stmt.setBool(column, booleanValue.get().booleanValue()); | |
530 | + } | |
527 | 531 | break; |
528 | 532 | case STRING: |
529 | - stmt.setString(column, kvEntry.getStrValue().get()); | |
533 | + Optional<String> stringValue = kvEntry.getStrValue(); | |
534 | + if (stringValue.isPresent()) { | |
535 | + stmt.setString(column, stringValue.get()); | |
536 | + } | |
530 | 537 | break; |
531 | 538 | case LONG: |
532 | - stmt.setLong(column, kvEntry.getLongValue().get().longValue()); | |
539 | + Optional<Long> longValue = kvEntry.getLongValue(); | |
540 | + if (longValue.isPresent()) { | |
541 | + stmt.setLong(column, longValue.get().longValue()); | |
542 | + } | |
533 | 543 | break; |
534 | 544 | case DOUBLE: |
535 | - stmt.setDouble(column, kvEntry.getDoubleValue().get().doubleValue()); | |
545 | + Optional<Double> doubleValue = kvEntry.getDoubleValue(); | |
546 | + if (doubleValue.isPresent()) { | |
547 | + stmt.setDouble(column, doubleValue.get().doubleValue()); | |
548 | + } | |
536 | 549 | break; |
537 | 550 | } |
538 | 551 | } | ... | ... |
... | ... | @@ -25,7 +25,7 @@ public enum TsPartitionDate { |
25 | 25 | MINUTES("yyyy-MM-dd-HH-mm", ChronoUnit.MINUTES), HOURS("yyyy-MM-dd-HH", ChronoUnit.HOURS), DAYS("yyyy-MM-dd", ChronoUnit.DAYS), MONTHS("yyyy-MM", ChronoUnit.MONTHS), YEARS("yyyy", ChronoUnit.YEARS); |
26 | 26 | |
27 | 27 | private final String pattern; |
28 | - private final TemporalUnit truncateUnit; | |
28 | + private final transient TemporalUnit truncateUnit; | |
29 | 29 | |
30 | 30 | TsPartitionDate(String pattern, TemporalUnit truncateUnit) { |
31 | 31 | this.pattern = pattern; | ... | ... |
... | ... | @@ -71,7 +71,7 @@ public class DefaultWebsocketMsgHandler implements WebsocketMsgHandler { |
71 | 71 | wsSessionsMap.put(sessionId, new WsSessionMetaData(sessionRef)); |
72 | 72 | break; |
73 | 73 | case ERROR: |
74 | - log.debug("[{}] Unknown websocket session error: {}. ", sessionId, event.getError().get()); | |
74 | + log.debug("[{}] Unknown websocket session error: {}. ", sessionId, event.getError().orElse(null)); | |
75 | 75 | break; |
76 | 76 | case CLOSED: |
77 | 77 | wsSessionsMap.remove(sessionId); | ... | ... |
... | ... | @@ -85,13 +85,13 @@ public class NashornJsEvaluator { |
85 | 85 | protected static Object getValue(KvEntry attr) { |
86 | 86 | switch (attr.getDataType()) { |
87 | 87 | case STRING: |
88 | - return attr.getStrValue().get(); | |
88 | + return attr.getStrValue().orElse(null); | |
89 | 89 | case LONG: |
90 | - return attr.getLongValue().get(); | |
90 | + return attr.getLongValue().orElse(null); | |
91 | 91 | case DOUBLE: |
92 | - return attr.getDoubleValue().get(); | |
92 | + return attr.getDoubleValue().orElse(null); | |
93 | 93 | case BOOLEAN: |
94 | - return attr.getBooleanValue().get(); | |
94 | + return attr.getBooleanValue().orElse(null); | |
95 | 95 | } |
96 | 96 | return null; |
97 | 97 | } | ... | ... |
... | ... | @@ -34,10 +34,7 @@ import org.thingsboard.server.extensions.api.plugins.handlers.RuleMsgHandler; |
34 | 34 | import org.thingsboard.server.extensions.api.plugins.msg.*; |
35 | 35 | import org.thingsboard.server.extensions.api.rules.RuleException; |
36 | 36 | |
37 | -import java.util.HashMap; | |
38 | -import java.util.List; | |
39 | -import java.util.Map; | |
40 | -import java.util.UUID; | |
37 | +import java.util.*; | |
41 | 38 | |
42 | 39 | /** |
43 | 40 | * @author Andrew Shvayka |
... | ... | @@ -89,8 +86,9 @@ public class DeviceMessagingRuleMsgHandler implements RuleMsgHandler { |
89 | 86 | if (pendindMsg != null) { |
90 | 87 | log.trace("[{}] Received response: {}", requestId, msg); |
91 | 88 | ToServerRpcResponseMsg response; |
92 | - if (msg.getError().isPresent()) { | |
93 | - response = new ToServerRpcResponseMsg(pendindMsg.getRequestId(), toJsonString(msg.getError().get())); | |
89 | + Optional<RpcError> rpcError = msg.getError(); | |
90 | + if (rpcError.isPresent()) { | |
91 | + response = new ToServerRpcResponseMsg(pendindMsg.getRequestId(), toJsonString(rpcError.get())); | |
94 | 92 | } else { |
95 | 93 | response = new ToServerRpcResponseMsg(pendindMsg.getRequestId(), msg.getResponse().orElse("")); |
96 | 94 | } | ... | ... |
... | ... | @@ -110,8 +110,9 @@ public class RpcRestMsgHandler extends DefaultRestMsgHandler { |
110 | 110 | } |
111 | 111 | |
112 | 112 | public void reply(PluginContext ctx, DeferredResult<ResponseEntity> responseWriter, FromDeviceRpcResponse response) { |
113 | - if (response.getError().isPresent()) { | |
114 | - RpcError error = response.getError().get(); | |
113 | + Optional<RpcError> rpcError = response.getError(); | |
114 | + if (rpcError.isPresent()) { | |
115 | + RpcError error = rpcError.get(); | |
115 | 116 | switch (error) { |
116 | 117 | case TIMEOUT: |
117 | 118 | responseWriter.setResult(new ResponseEntity<>(HttpStatus.REQUEST_TIMEOUT)); |
... | ... | @@ -124,8 +125,9 @@ public class RpcRestMsgHandler extends DefaultRestMsgHandler { |
124 | 125 | break; |
125 | 126 | } |
126 | 127 | } else { |
127 | - if (response.getResponse().isPresent() && !StringUtils.isEmpty(response.getResponse().get())) { | |
128 | - String data = response.getResponse().get(); | |
128 | + Optional<String> responseData = response.getResponse(); | |
129 | + if (responseData.isPresent() && !StringUtils.isEmpty(responseData.get())) { | |
130 | + String data = responseData.get(); | |
129 | 131 | try { |
130 | 132 | responseWriter.setResult(new ResponseEntity<>(jsonMapper.readTree(data), HttpStatus.OK)); |
131 | 133 | } catch (IOException e) { | ... | ... |
... | ... | @@ -92,7 +92,7 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { |
92 | 92 | if (!StringUtils.isEmpty(scope)) { |
93 | 93 | ctx.loadAttributes(entityId, scope, callback); |
94 | 94 | } else { |
95 | - ctx.loadAttributes(entityId, Arrays.asList(DataConstants.ALL_SCOPES), callback); | |
95 | + ctx.loadAttributes(entityId, Arrays.asList(DataConstants.allScopes()), callback); | |
96 | 96 | } |
97 | 97 | } |
98 | 98 | } else if (method.equals("values")) { |
... | ... | @@ -132,9 +132,9 @@ public class TelemetryRestMsgHandler extends DefaultRestMsgHandler { |
132 | 132 | } else { |
133 | 133 | if (!StringUtils.isEmpty(keys)) { |
134 | 134 | List<String> keyList = Arrays.asList(keys.split(",")); |
135 | - ctx.loadAttributes(entityId, Arrays.asList(DataConstants.ALL_SCOPES), keyList, callback); | |
135 | + ctx.loadAttributes(entityId, Arrays.asList(DataConstants.allScopes()), keyList, callback); | |
136 | 136 | } else { |
137 | - ctx.loadAttributes(entityId, Arrays.asList(DataConstants.ALL_SCOPES), callback); | |
137 | + ctx.loadAttributes(entityId, Arrays.asList(DataConstants.allScopes()), callback); | |
138 | 138 | } |
139 | 139 | } |
140 | 140 | } | ... | ... |
... | ... | @@ -29,10 +29,7 @@ import org.thingsboard.server.extensions.core.plugin.telemetry.SubscriptionManag |
29 | 29 | import org.thingsboard.server.extensions.core.plugin.telemetry.gen.TelemetryPluginProtos.*; |
30 | 30 | import org.thingsboard.server.extensions.core.plugin.telemetry.sub.*; |
31 | 31 | |
32 | -import java.util.ArrayList; | |
33 | -import java.util.List; | |
34 | -import java.util.Map; | |
35 | -import java.util.TreeMap; | |
32 | +import java.util.*; | |
36 | 33 | import java.util.stream.Collectors; |
37 | 34 | |
38 | 35 | /** |
... | ... | @@ -244,16 +241,28 @@ public class TelemetryRpcMsgHandler implements RpcMsgHandler { |
244 | 241 | dataBuilder.setValueType(attr.getDataType().ordinal()); |
245 | 242 | switch (attr.getDataType()) { |
246 | 243 | case BOOLEAN: |
247 | - dataBuilder.setBoolValue(attr.getBooleanValue().get()); | |
244 | + Optional<Boolean> booleanValue = attr.getBooleanValue(); | |
245 | + if (booleanValue.isPresent()) { | |
246 | + dataBuilder.setBoolValue(booleanValue.get()); | |
247 | + } | |
248 | 248 | break; |
249 | 249 | case LONG: |
250 | - dataBuilder.setLongValue(attr.getLongValue().get()); | |
250 | + Optional<Long> longValue = attr.getLongValue(); | |
251 | + if (longValue.isPresent()) { | |
252 | + dataBuilder.setLongValue(longValue.get()); | |
253 | + } | |
251 | 254 | break; |
252 | 255 | case DOUBLE: |
253 | - dataBuilder.setDoubleValue(attr.getDoubleValue().get()); | |
256 | + Optional<Double> doubleValue = attr.getDoubleValue(); | |
257 | + if (doubleValue.isPresent()) { | |
258 | + dataBuilder.setDoubleValue(doubleValue.get()); | |
259 | + } | |
254 | 260 | break; |
255 | 261 | case STRING: |
256 | - dataBuilder.setStrValue(attr.getStrValue().get()); | |
262 | + Optional<String> stringValue = attr.getStrValue(); | |
263 | + if (stringValue.isPresent()) { | |
264 | + dataBuilder.setStrValue(stringValue.get()); | |
265 | + } | |
257 | 266 | break; |
258 | 267 | } |
259 | 268 | return dataBuilder; | ... | ... |
... | ... | @@ -139,7 +139,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler { |
139 | 139 | }; |
140 | 140 | |
141 | 141 | if (StringUtils.isEmpty(cmd.getScope())) { |
142 | - ctx.loadAttributes(entityId, Arrays.asList(DataConstants.ALL_SCOPES), keys, callback); | |
142 | + ctx.loadAttributes(entityId, Arrays.asList(DataConstants.allScopes()), keys, callback); | |
143 | 143 | } else { |
144 | 144 | ctx.loadAttributes(entityId, cmd.getScope(), keys, callback); |
145 | 145 | } |
... | ... | @@ -167,7 +167,7 @@ public class TelemetryWebsocketMsgHandler extends DefaultWebsocketMsgHandler { |
167 | 167 | }; |
168 | 168 | |
169 | 169 | if (StringUtils.isEmpty(cmd.getScope())) { |
170 | - ctx.loadAttributes(entityId, Arrays.asList(DataConstants.ALL_SCOPES), callback); | |
170 | + ctx.loadAttributes(entityId, Arrays.asList(DataConstants.allScopes()), callback); | |
171 | 171 | } else { |
172 | 172 | ctx.loadAttributes(entityId, cmd.getScope(), callback); |
173 | 173 | } | ... | ... |
... | ... | @@ -84,9 +84,10 @@ public class MqttPlugin extends AbstractPlugin<MqttPluginConfiguration> { |
84 | 84 | log.warn("Failed to connect to requested mqtt host [{}]!", mqttClient.getServerURI(), e); |
85 | 85 | if (!mqttClient.isConnected()) { |
86 | 86 | try { |
87 | - Thread.sleep(retryInterval); | |
87 | + connectLock.wait(retryInterval); | |
88 | 88 | } catch (InterruptedException e1) { |
89 | 89 | log.trace("Failed to wait for retry interval!", e); |
90 | + Thread.currentThread().interrupt(); | |
90 | 91 | } |
91 | 92 | } |
92 | 93 | } | ... | ... |
... | ... | @@ -21,18 +21,18 @@ package org.thingsboard.client.tools; |
21 | 21 | */ |
22 | 22 | |
23 | 23 | import com.google.common.io.Resources; |
24 | -import org.eclipse.paho.client.mqttv3.*; | |
24 | +import lombok.extern.slf4j.Slf4j; | |
25 | +import org.eclipse.paho.client.mqttv3.MqttAsyncClient; | |
26 | +import org.eclipse.paho.client.mqttv3.MqttConnectOptions; | |
27 | +import org.eclipse.paho.client.mqttv3.MqttMessage; | |
25 | 28 | |
26 | 29 | import javax.net.ssl.*; |
27 | 30 | import java.io.File; |
28 | 31 | import java.io.FileInputStream; |
29 | -import java.io.FileNotFoundException; | |
30 | -import java.io.IOException; | |
31 | -import java.net.URISyntaxException; | |
32 | 32 | import java.net.URL; |
33 | -import java.security.*; | |
34 | -import java.security.cert.CertificateException; | |
33 | +import java.security.KeyStore; | |
35 | 34 | |
35 | +@Slf4j | |
36 | 36 | public class MqttSslClient { |
37 | 37 | |
38 | 38 | |
... | ... | @@ -43,13 +43,10 @@ public class MqttSslClient { |
43 | 43 | private static final String keyStoreFile = "mqttclient.jks"; |
44 | 44 | private static final String JKS="JKS"; |
45 | 45 | private static final String TLS="TLS"; |
46 | - private static final String CLIENT_KEYSTORE_PASSWORD = "client_ks_password"; | |
47 | - private static final String CLIENT_KEY_PASSWORD = "client_key_password"; | |
48 | 46 | |
49 | 47 | public static void main(String[] args) { |
50 | 48 | |
51 | 49 | try { |
52 | - | |
53 | 50 | URL ksUrl = Resources.getResource(keyStoreFile); |
54 | 51 | File ksFile = new File(ksUrl.toURI()); |
55 | 52 | URL tsUrl = Resources.getResource(keyStoreFile); |
... | ... | @@ -58,13 +55,15 @@ public class MqttSslClient { |
58 | 55 | TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
59 | 56 | |
60 | 57 | KeyStore trustStore = KeyStore.getInstance(JKS); |
61 | - trustStore.load(new FileInputStream(tsFile), CLIENT_KEYSTORE_PASSWORD.toCharArray()); | |
58 | + char[] ksPwd = new char[]{0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x5F, 0x6B, 0x73, 0x5F, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64}; | |
59 | + trustStore.load(new FileInputStream(tsFile), ksPwd); | |
62 | 60 | tmf.init(trustStore); |
63 | 61 | KeyStore ks = KeyStore.getInstance(JKS); |
64 | 62 | |
65 | - ks.load(new FileInputStream(ksFile), CLIENT_KEYSTORE_PASSWORD.toCharArray()); | |
63 | + ks.load(new FileInputStream(ksFile), ksPwd); | |
66 | 64 | KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
67 | - kmf.init(ks, CLIENT_KEY_PASSWORD.toCharArray()); | |
65 | + char[] clientPwd = new char[]{0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x5F, 0x6B, 0x65, 0x79, 0x5F, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64}; | |
66 | + kmf.init(ks, clientPwd); | |
68 | 67 | |
69 | 68 | KeyManager[] km = kmf.getKeyManagers(); |
70 | 69 | TrustManager[] tm = tmf.getTrustManagers(); |
... | ... | @@ -83,7 +82,7 @@ public class MqttSslClient { |
83 | 82 | System.out.println("Disconnected"); |
84 | 83 | System.exit(0); |
85 | 84 | } catch (Exception e) { |
86 | - e.printStackTrace(); | |
85 | + log.error("Unexpected exception occurred in MqttSslClient", e); | |
87 | 86 | } |
88 | 87 | } |
89 | 88 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -167,7 +167,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { |
167 | 167 | |
168 | 168 | private FromDeviceMsg convertToGetAttributesRequest(SessionContext ctx, Request inbound) throws AdaptorException { |
169 | 169 | List<String> queryElements = inbound.getOptions().getUriQuery(); |
170 | - if (queryElements != null || queryElements.size() > 0) { | |
170 | + if (queryElements != null && queryElements.size() > 0) { | |
171 | 171 | Set<String> clientKeys = toKeys(ctx, queryElements, "clientKeys"); |
172 | 172 | Set<String> sharedKeys = toKeys(ctx, queryElements, "sharedKeys"); |
173 | 173 | return new BasicGetAttributesRequest(0, clientKeys, sharedKeys); |
... | ... | @@ -184,7 +184,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { |
184 | 184 | keys = queryItem[1]; |
185 | 185 | } |
186 | 186 | } |
187 | - if (!StringUtils.isEmpty(keys)) { | |
187 | + if (keys != null && !StringUtils.isEmpty(keys)) { | |
188 | 188 | return new HashSet<>(Arrays.asList(keys.split(","))); |
189 | 189 | } else { |
190 | 190 | return null; |
... | ... | @@ -202,14 +202,14 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { |
202 | 202 | |
203 | 203 | private Response convertStatusCodeResponse(StatusCodeResponse msg) { |
204 | 204 | if (msg.isSuccess()) { |
205 | - Integer code = msg.getData().get(); | |
206 | - if (code == 200) { | |
205 | + Optional<Integer> code = msg.getData(); | |
206 | + if (code.isPresent() && code.get() == 200) { | |
207 | 207 | return new Response(ResponseCode.VALID); |
208 | 208 | } else { |
209 | 209 | return new Response(ResponseCode.CREATED); |
210 | 210 | } |
211 | 211 | } else { |
212 | - return convertError(msg.getError().get()); | |
212 | + return convertError(msg.getError()); | |
213 | 213 | } |
214 | 214 | } |
215 | 215 | |
... | ... | @@ -229,30 +229,34 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { |
229 | 229 | response.setPayload(result.toString()); |
230 | 230 | return response; |
231 | 231 | } else { |
232 | - return convertError(new RuntimeException("Server RPC response is empty!")); | |
232 | + return convertError(Optional.of(new RuntimeException("Server RPC response is empty!"))); | |
233 | 233 | } |
234 | 234 | } |
235 | 235 | |
236 | 236 | private Response convertGetAttributesResponse(GetAttributesResponse msg) { |
237 | 237 | if (msg.isSuccess()) { |
238 | - AttributesKVMsg payload = msg.getData().get(); | |
239 | - if (payload.getClientAttributes().isEmpty() && payload.getSharedAttributes().isEmpty()) { | |
238 | + Optional<AttributesKVMsg> payload = msg.getData(); | |
239 | + if (!payload.isPresent() || (payload.get().getClientAttributes().isEmpty() && payload.get().getSharedAttributes().isEmpty())) { | |
240 | 240 | return new Response(ResponseCode.NOT_FOUND); |
241 | 241 | } else { |
242 | 242 | Response response = new Response(ResponseCode.CONTENT); |
243 | - JsonObject result = JsonConverter.toJson(payload, false); | |
243 | + JsonObject result = JsonConverter.toJson(payload.get(), false); | |
244 | 244 | response.setPayload(result.toString()); |
245 | 245 | return response; |
246 | 246 | } |
247 | 247 | } else { |
248 | - return convertError(msg.getError().get()); | |
248 | + return convertError(msg.getError()); | |
249 | 249 | } |
250 | 250 | } |
251 | 251 | |
252 | - private Response convertError(Exception exception) { | |
253 | - log.warn("Converting exception: {}", exception.getMessage(), exception); | |
254 | - if (exception instanceof ProcessingTimeoutException) { | |
255 | - return new Response(ResponseCode.SERVICE_UNAVAILABLE); | |
252 | + private Response convertError(Optional<Exception> exception) { | |
253 | + if (exception.isPresent()) { | |
254 | + log.warn("Converting exception: {}", exception.get().getMessage(), exception.get()); | |
255 | + if (exception.get() instanceof ProcessingTimeoutException) { | |
256 | + return new Response(ResponseCode.SERVICE_UNAVAILABLE); | |
257 | + } else { | |
258 | + return new Response(ResponseCode.INTERNAL_SERVER_ERROR); | |
259 | + } | |
256 | 260 | } else { |
257 | 261 | return new Response(ResponseCode.INTERNAL_SERVER_ERROR); |
258 | 262 | } | ... | ... |
... | ... | @@ -80,7 +80,7 @@ public class DeviceEmulator { |
80 | 80 | Thread.sleep(1000); |
81 | 81 | } |
82 | 82 | } catch (Exception e) { |
83 | - e.printStackTrace(); | |
83 | + log.error("Error occurred while sending COAP requests", e); | |
84 | 84 | } |
85 | 85 | } |
86 | 86 | |
... | ... | @@ -118,7 +118,7 @@ public class DeviceEmulator { |
118 | 118 | }, mapper.writeValueAsString(response), MediaTypeRegistry.APPLICATION_JSON); |
119 | 119 | |
120 | 120 | } catch (IOException e) { |
121 | - e.printStackTrace(); | |
121 | + log.error("Error occurred while processing COAP response", e); | |
122 | 122 | } |
123 | 123 | } |
124 | 124 | ... | ... |
... | ... | @@ -29,6 +29,7 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
29 | 29 | import org.thingsboard.server.common.transport.auth.DeviceAuthService; |
30 | 30 | import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; |
31 | 31 | |
32 | +import java.util.Optional; | |
32 | 33 | import java.util.function.Consumer; |
33 | 34 | |
34 | 35 | /** |
... | ... | @@ -94,10 +95,14 @@ public class HttpSessionCtx extends DeviceAwareSessionContext { |
94 | 95 | } |
95 | 96 | |
96 | 97 | private <T> void reply(ResponseMsg<? extends T> msg, Consumer<T> f) { |
97 | - if (!msg.getError().isPresent()) { | |
98 | - f.accept(msg.getData().get()); | |
98 | + Optional<Exception> msgError = msg.getError(); | |
99 | + if (!msgError.isPresent()) { | |
100 | + Optional<? extends T> msgData = msg.getData(); | |
101 | + if (msgData.isPresent()) { | |
102 | + f.accept(msgData.get()); | |
103 | + } | |
99 | 104 | } else { |
100 | - Exception e = msg.getError().get(); | |
105 | + Exception e = msgError.get(); | |
101 | 106 | responseWriter.setResult(new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR)); |
102 | 107 | } |
103 | 108 | } | ... | ... |
... | ... | @@ -32,6 +32,7 @@ import javax.net.ssl.*; |
32 | 32 | import java.io.File; |
33 | 33 | import java.io.FileInputStream; |
34 | 34 | import java.io.IOException; |
35 | +import java.io.InputStream; | |
35 | 36 | import java.net.URL; |
36 | 37 | import java.security.KeyStore; |
37 | 38 | import java.security.cert.CertificateException; |
... | ... | @@ -69,12 +70,15 @@ public class MqttSslHandlerProvider { |
69 | 70 | |
70 | 71 | TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); |
71 | 72 | KeyStore trustStore = KeyStore.getInstance(keyStoreType); |
72 | - trustStore.load(new FileInputStream(tsFile), keyStorePassword.toCharArray()); | |
73 | + try (InputStream tsFileInputStream = new FileInputStream(tsFile)) { | |
74 | + trustStore.load(tsFileInputStream, keyStorePassword.toCharArray()); | |
75 | + } | |
73 | 76 | tmFactory.init(trustStore); |
74 | 77 | |
75 | 78 | KeyStore ks = KeyStore.getInstance(keyStoreType); |
76 | - | |
77 | - ks.load(new FileInputStream(ksFile), keyStorePassword.toCharArray()); | |
79 | + try (InputStream ksFileInputStream = new FileInputStream(ksFile)) { | |
80 | + ks.load(ksFileInputStream, keyStorePassword.toCharArray()); | |
81 | + } | |
78 | 82 | KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); |
79 | 83 | kmf.init(ks, keyPassword.toCharArray()); |
80 | 84 | ... | ... |
... | ... | @@ -98,6 +98,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { |
98 | 98 | case STATUS_CODE_RESPONSE: |
99 | 99 | case GET_ATTRIBUTES_RESPONSE: |
100 | 100 | ResponseMsg<?> responseMsg = (ResponseMsg) msg; |
101 | + Optional<Exception> responseError = responseMsg.getError(); | |
101 | 102 | if (responseMsg.isSuccess()) { |
102 | 103 | MsgType requestMsgType = responseMsg.getRequestMsgType(); |
103 | 104 | Integer requestId = responseMsg.getRequestId(); |
... | ... | @@ -106,18 +107,21 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { |
106 | 107 | result = MqttTransportHandler.createMqttPubAckMsg(requestId); |
107 | 108 | } else if (requestMsgType == MsgType.GET_ATTRIBUTES_REQUEST) { |
108 | 109 | GetAttributesResponse response = (GetAttributesResponse) msg; |
109 | - if (response.isSuccess()) { | |
110 | + Optional<AttributesKVMsg> responseData = response.getData(); | |
111 | + if (response.isSuccess() && responseData.isPresent()) { | |
110 | 112 | result = createMqttPublishMsg(ctx, |
111 | 113 | MqttTopics.DEVICE_ATTRIBUTES_RESPONSE_TOPIC_PREFIX + requestId, |
112 | - response.getData().get(), true); | |
114 | + responseData.get(), true); | |
113 | 115 | } else { |
114 | - throw new AdaptorException(response.getError().get()); | |
116 | + if (responseError.isPresent()) { | |
117 | + throw new AdaptorException(responseError.get()); | |
118 | + } | |
115 | 119 | } |
116 | 120 | } |
117 | 121 | } |
118 | 122 | } else { |
119 | - if (responseMsg.getError().isPresent()) { | |
120 | - throw new AdaptorException(responseMsg.getError().get()); | |
123 | + if (responseError.isPresent()) { | |
124 | + throw new AdaptorException(responseError.get()); | |
121 | 125 | } |
122 | 126 | } |
123 | 127 | break; | ... | ... |
... | ... | @@ -128,8 +128,9 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext { |
128 | 128 | JsonObject result = new JsonObject(); |
129 | 129 | result.addProperty("id", response.getRequestId()); |
130 | 130 | result.addProperty("device", device.getName()); |
131 | - if (response.getData().isPresent()) { | |
132 | - AttributesKVMsg msg = response.getData().get(); | |
131 | + Optional<AttributesKVMsg> responseData = response.getData(); | |
132 | + if (responseData.isPresent()) { | |
133 | + AttributesKVMsg msg = responseData.get(); | |
133 | 134 | if (msg.getClientAttributes() != null) { |
134 | 135 | msg.getClientAttributes().forEach(v -> addValueToJson(result, "value", v)); |
135 | 136 | } |
... | ... | @@ -143,16 +144,28 @@ public class GatewayDeviceSessionCtx extends DeviceAwareSessionContext { |
143 | 144 | private void addValueToJson(JsonObject json, String name, KvEntry entry) { |
144 | 145 | switch (entry.getDataType()) { |
145 | 146 | case BOOLEAN: |
146 | - json.addProperty(name, entry.getBooleanValue().get()); | |
147 | + Optional<Boolean> booleanValue = entry.getBooleanValue(); | |
148 | + if (booleanValue.isPresent()) { | |
149 | + json.addProperty(name, booleanValue.get()); | |
150 | + } | |
147 | 151 | break; |
148 | 152 | case STRING: |
149 | - json.addProperty(name, entry.getStrValue().get()); | |
153 | + Optional<String> stringValue = entry.getStrValue(); | |
154 | + if (stringValue.isPresent()) { | |
155 | + json.addProperty(name, stringValue.get()); | |
156 | + } | |
150 | 157 | break; |
151 | 158 | case DOUBLE: |
152 | - json.addProperty(name, entry.getDoubleValue().get()); | |
159 | + Optional<Double> doubleValue = entry.getDoubleValue(); | |
160 | + if (doubleValue.isPresent()) { | |
161 | + json.addProperty(name, doubleValue.get()); | |
162 | + } | |
153 | 163 | break; |
154 | 164 | case LONG: |
155 | - json.addProperty(name, entry.getLongValue().get()); | |
165 | + Optional<Long> longValue = entry.getLongValue(); | |
166 | + if (longValue.isPresent()) { | |
167 | + json.addProperty(name, longValue.get()); | |
168 | + } | |
156 | 169 | break; |
157 | 170 | } |
158 | 171 | } | ... | ... |