Commit 3d3dd8871044a0733a7016eafc4a2e09f28a26c1
Merge remote-tracking branch 'origin/develop/2.5.1' into feature/edge
Showing
99 changed files
with
1691 additions
and
1091 deletions
Too many changes to show.
To preserve performance only 99 of 283 files are displayed.
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>application</artifactId> |
... | ... | @@ -34,10 +34,15 @@ |
34 | 34 | <properties> |
35 | 35 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> |
36 | 36 | <main.dir>${basedir}/..</main.dir> |
37 | + <pkg.type>java</pkg.type> | |
38 | + <pkg.disabled>false</pkg.disabled> | |
39 | + <pkg.process-resources.phase>process-resources</pkg.process-resources.phase> | |
40 | + <pkg.package.phase>package</pkg.package.phase> | |
37 | 41 | <pkg.name>thingsboard</pkg.name> |
38 | - <pkg.unixLogFolder>/var/log/${pkg.name}</pkg.unixLogFolder> | |
39 | - <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder> | |
40 | 42 | <pkg.win.dist>${project.build.directory}/windows</pkg.win.dist> |
43 | + <pkg.copyInstallScripts>true</pkg.copyInstallScripts> | |
44 | + <pkg.implementationTitle>ThingsBoard</pkg.implementationTitle> | |
45 | + <pkg.mainClass>org.thingsboard.server.ThingsboardServerApplication</pkg.mainClass> | |
41 | 46 | </properties> |
42 | 47 | |
43 | 48 | <dependencies> |
... | ... | @@ -313,6 +318,10 @@ |
313 | 318 | <plugins> |
314 | 319 | <plugin> |
315 | 320 | <groupId>org.apache.maven.plugins</groupId> |
321 | + <artifactId>maven-compiler-plugin</artifactId> | |
322 | + </plugin> | |
323 | + <plugin> | |
324 | + <groupId>org.apache.maven.plugins</groupId> | |
316 | 325 | <artifactId>maven-surefire-plugin</artifactId> |
317 | 326 | <version>${surfire.version}</version> |
318 | 327 | <configuration> |
... | ... | @@ -327,313 +336,30 @@ |
327 | 336 | <plugin> |
328 | 337 | <groupId>org.apache.maven.plugins</groupId> |
329 | 338 | <artifactId>maven-resources-plugin</artifactId> |
330 | - <executions> | |
331 | - <execution> | |
332 | - <id>copy-conf</id> | |
333 | - <phase>process-resources</phase> | |
334 | - <goals> | |
335 | - <goal>copy-resources</goal> | |
336 | - </goals> | |
337 | - <configuration> | |
338 | - <outputDirectory>${project.build.directory}/conf</outputDirectory> | |
339 | - <resources> | |
340 | - <resource> | |
341 | - <directory>src/main/resources</directory> | |
342 | - <excludes> | |
343 | - <exclude>logback.xml</exclude> | |
344 | - </excludes> | |
345 | - <filtering>false</filtering> | |
346 | - </resource> | |
347 | - </resources> | |
348 | - </configuration> | |
349 | - </execution> | |
350 | - <execution> | |
351 | - <id>copy-service-conf</id> | |
352 | - <phase>process-resources</phase> | |
353 | - <goals> | |
354 | - <goal>copy-resources</goal> | |
355 | - </goals> | |
356 | - <configuration> | |
357 | - <outputDirectory>${project.build.directory}/conf</outputDirectory> | |
358 | - <resources> | |
359 | - <resource> | |
360 | - <directory>src/main/conf</directory> | |
361 | - <filtering>true</filtering> | |
362 | - </resource> | |
363 | - </resources> | |
364 | - <filters> | |
365 | - <filter>src/main/filters/unix.properties</filter> | |
366 | - </filters> | |
367 | - </configuration> | |
368 | - </execution> | |
369 | - <execution> | |
370 | - <id>copy-win-conf</id> | |
371 | - <phase>process-resources</phase> | |
372 | - <goals> | |
373 | - <goal>copy-resources</goal> | |
374 | - </goals> | |
375 | - <configuration> | |
376 | - <outputDirectory>${pkg.win.dist}/conf</outputDirectory> | |
377 | - <resources> | |
378 | - <resource> | |
379 | - <directory>src/main/resources</directory> | |
380 | - <excludes> | |
381 | - <exclude>logback.xml</exclude> | |
382 | - </excludes> | |
383 | - <filtering>false</filtering> | |
384 | - </resource> | |
385 | - <resource> | |
386 | - <directory>src/main/conf</directory> | |
387 | - <excludes> | |
388 | - <exclude>thingsboard.conf</exclude> | |
389 | - </excludes> | |
390 | - <filtering>true</filtering> | |
391 | - </resource> | |
392 | - </resources> | |
393 | - <filters> | |
394 | - <filter>src/main/filters/windows.properties</filter> | |
395 | - </filters> | |
396 | - </configuration> | |
397 | - </execution> | |
398 | - <execution> | |
399 | - <id>copy-control</id> | |
400 | - <phase>process-resources</phase> | |
401 | - <goals> | |
402 | - <goal>copy-resources</goal> | |
403 | - </goals> | |
404 | - <configuration> | |
405 | - <outputDirectory>${project.build.directory}/control</outputDirectory> | |
406 | - <resources> | |
407 | - <resource> | |
408 | - <directory>src/main/scripts/control</directory> | |
409 | - <filtering>true</filtering> | |
410 | - </resource> | |
411 | - </resources> | |
412 | - <filters> | |
413 | - <filter>src/main/filters/unix.properties</filter> | |
414 | - </filters> | |
415 | - </configuration> | |
416 | - </execution> | |
417 | - <execution> | |
418 | - <id>copy-install</id> | |
419 | - <phase>process-resources</phase> | |
420 | - <goals> | |
421 | - <goal>copy-resources</goal> | |
422 | - </goals> | |
423 | - <configuration> | |
424 | - <outputDirectory>${project.build.directory}/bin/install</outputDirectory> | |
425 | - <resources> | |
426 | - <resource> | |
427 | - <directory>src/main/scripts/install</directory> | |
428 | - <includes> | |
429 | - <include>**/*.sh</include> | |
430 | - <include>**/*.xml</include> | |
431 | - </includes> | |
432 | - <filtering>true</filtering> | |
433 | - </resource> | |
434 | - </resources> | |
435 | - <filters> | |
436 | - <filter>src/main/filters/unix.properties</filter> | |
437 | - </filters> | |
438 | - </configuration> | |
439 | - </execution> | |
440 | - <execution> | |
441 | - <id>copy-windows-control</id> | |
442 | - <phase>process-resources</phase> | |
443 | - <goals> | |
444 | - <goal>copy-resources</goal> | |
445 | - </goals> | |
446 | - <configuration> | |
447 | - <outputDirectory>${pkg.win.dist}</outputDirectory> | |
448 | - <resources> | |
449 | - <resource> | |
450 | - <directory>src/main/scripts/windows</directory> | |
451 | - <filtering>true</filtering> | |
452 | - </resource> | |
453 | - </resources> | |
454 | - <filters> | |
455 | - <filter>src/main/filters/windows.properties</filter> | |
456 | - </filters> | |
457 | - </configuration> | |
458 | - </execution> | |
459 | - <execution> | |
460 | - <id>copy-windows-install</id> | |
461 | - <phase>process-resources</phase> | |
462 | - <goals> | |
463 | - <goal>copy-resources</goal> | |
464 | - </goals> | |
465 | - <configuration> | |
466 | - <outputDirectory>${pkg.win.dist}/install</outputDirectory> | |
467 | - <resources> | |
468 | - <resource> | |
469 | - <directory>src/main/scripts/install</directory> | |
470 | - <includes> | |
471 | - <include>logback.xml</include> | |
472 | - </includes> | |
473 | - <filtering>true</filtering> | |
474 | - </resource> | |
475 | - </resources> | |
476 | - <filters> | |
477 | - <filter>src/main/filters/windows.properties</filter> | |
478 | - </filters> | |
479 | - </configuration> | |
480 | - </execution> | |
481 | - <execution> | |
482 | - <id>copy-data</id> | |
483 | - <phase>process-resources</phase> | |
484 | - <goals> | |
485 | - <goal>copy-resources</goal> | |
486 | - </goals> | |
487 | - <configuration> | |
488 | - <outputDirectory>${project.build.directory}/data</outputDirectory> | |
489 | - <resources> | |
490 | - <resource> | |
491 | - <directory>src/main/data</directory> | |
492 | - </resource> | |
493 | - <resource> | |
494 | - <directory>../dao/src/main/resources</directory> | |
495 | - <includes> | |
496 | - <include>**/*.cql</include> | |
497 | - <include>**/*.sql</include> | |
498 | - </includes> | |
499 | - <filtering>false</filtering> | |
500 | - </resource> | |
501 | - </resources> | |
502 | - </configuration> | |
503 | - </execution> | |
504 | - </executions> | |
505 | 339 | </plugin> |
506 | 340 | <plugin> |
507 | 341 | <groupId>org.apache.maven.plugins</groupId> |
508 | 342 | <artifactId>maven-dependency-plugin</artifactId> |
509 | - <executions> | |
510 | - <execution> | |
511 | - <id>copy-winsw-service</id> | |
512 | - <phase>package</phase> | |
513 | - <goals> | |
514 | - <goal>copy</goal> | |
515 | - </goals> | |
516 | - <configuration> | |
517 | - <artifactItems> | |
518 | - <artifactItem> | |
519 | - <groupId>com.sun.winsw</groupId> | |
520 | - <artifactId>winsw</artifactId> | |
521 | - <classifier>bin</classifier> | |
522 | - <type>exe</type> | |
523 | - <destFileName>service.exe</destFileName> | |
524 | - </artifactItem> | |
525 | - </artifactItems> | |
526 | - <outputDirectory>${pkg.win.dist}</outputDirectory> | |
527 | - </configuration> | |
528 | - </execution> | |
529 | - </executions> | |
530 | 343 | </plugin> |
531 | 344 | <plugin> |
532 | 345 | <groupId>org.apache.maven.plugins</groupId> |
533 | 346 | <artifactId>maven-jar-plugin</artifactId> |
534 | - <configuration> | |
535 | - <excludes> | |
536 | - <exclude>**/logback.xml</exclude> | |
537 | - </excludes> | |
538 | - <archive> | |
539 | - <manifestEntries> | |
540 | - <Implementation-Title>ThingsBoard</Implementation-Title> | |
541 | - <Implementation-Version>${project.version}</Implementation-Version> | |
542 | - </manifestEntries> | |
543 | - </archive> | |
544 | - </configuration> | |
545 | 347 | </plugin> |
546 | 348 | <plugin> |
547 | 349 | <groupId>org.springframework.boot</groupId> |
548 | 350 | <artifactId>spring-boot-maven-plugin</artifactId> |
549 | - <configuration> | |
550 | - <mainClass>org.thingsboard.server.ThingsboardServerApplication</mainClass> | |
551 | - <classifier>boot</classifier> | |
552 | - <layout>ZIP</layout> | |
553 | - <executable>true</executable> | |
554 | - <excludeDevtools>true</excludeDevtools> | |
555 | - <embeddedLaunchScriptProperties> | |
556 | - <confFolder>${pkg.installFolder}/conf</confFolder> | |
557 | - <logFolder>${pkg.unixLogFolder}</logFolder> | |
558 | - <logFilename>${pkg.name}.out</logFilename> | |
559 | - <initInfoProvides>${pkg.name}</initInfoProvides> | |
560 | - </embeddedLaunchScriptProperties> | |
561 | - </configuration> | |
562 | - <executions> | |
563 | - <execution> | |
564 | - <goals> | |
565 | - <goal>repackage</goal> | |
566 | - </goals> | |
567 | - </execution> | |
568 | - </executions> | |
569 | 351 | </plugin> |
570 | 352 | <plugin> |
571 | 353 | <groupId>org.thingsboard</groupId> |
572 | 354 | <artifactId>gradle-maven-plugin</artifactId> |
573 | - <configuration> | |
574 | - <tasks> | |
575 | - <task>build</task> | |
576 | - <task>buildDeb</task> | |
577 | - <task>buildRpm</task> | |
578 | - </tasks> | |
579 | - <args> | |
580 | - <arg>-PprojectBuildDir=${project.build.directory}</arg> | |
581 | - <arg>-PprojectVersion=${project.version}</arg> | |
582 | - <arg>-PmainJar=${project.build.directory}/${project.build.finalName}-boot.${project.packaging} | |
583 | - </arg> | |
584 | - <arg>-PpkgName=${pkg.name}</arg> | |
585 | - <arg>-PpkgInstallFolder=${pkg.installFolder}</arg> | |
586 | - <arg>-PpkgLogFolder=${pkg.unixLogFolder}</arg> | |
587 | - </args> | |
588 | - </configuration> | |
589 | - <executions> | |
590 | - <execution> | |
591 | - <phase>package</phase> | |
592 | - <goals> | |
593 | - <goal>invoke</goal> | |
594 | - </goals> | |
595 | - </execution> | |
596 | - </executions> | |
597 | 355 | </plugin> |
598 | 356 | <plugin> |
599 | 357 | <groupId>org.apache.maven.plugins</groupId> |
600 | 358 | <artifactId>maven-assembly-plugin</artifactId> |
601 | - <configuration> | |
602 | - <finalName>${pkg.name}</finalName> | |
603 | - <descriptors> | |
604 | - <descriptor>src/main/assembly/windows.xml</descriptor> | |
605 | - </descriptors> | |
606 | - </configuration> | |
607 | - <executions> | |
608 | - <execution> | |
609 | - <id>assembly</id> | |
610 | - <phase>package</phase> | |
611 | - <goals> | |
612 | - <goal>single</goal> | |
613 | - </goals> | |
614 | - </execution> | |
615 | - </executions> | |
616 | 359 | </plugin> |
617 | 360 | <plugin> |
618 | 361 | <groupId>org.apache.maven.plugins</groupId> |
619 | 362 | <artifactId>maven-install-plugin</artifactId> |
620 | - <configuration> | |
621 | - <file>${project.build.directory}/${pkg.name}.deb</file> | |
622 | - <artifactId>${project.artifactId}</artifactId> | |
623 | - <groupId>${project.groupId}</groupId> | |
624 | - <version>${project.version}</version> | |
625 | - <classifier>deb</classifier> | |
626 | - <packaging>deb</packaging> | |
627 | - </configuration> | |
628 | - <executions> | |
629 | - <execution> | |
630 | - <id>install-deb</id> | |
631 | - <phase>package</phase> | |
632 | - <goals> | |
633 | - <goal>install-file</goal> | |
634 | - </goals> | |
635 | - </execution> | |
636 | - </executions> | |
637 | 363 | </plugin> |
638 | 364 | <plugin> |
639 | 365 | <groupId>org.xolstice.maven.plugins</groupId> | ... | ... |
... | ... | @@ -16,50 +16,85 @@ |
16 | 16 | |
17 | 17 | -- call create_partition_ts_kv_table(); |
18 | 18 | |
19 | -CREATE OR REPLACE PROCEDURE create_partition_ts_kv_table() LANGUAGE plpgsql AS $$ | |
19 | +CREATE OR REPLACE PROCEDURE create_partition_ts_kv_table() | |
20 | + LANGUAGE plpgsql AS | |
21 | +$$ | |
20 | 22 | |
21 | 23 | BEGIN |
22 | - ALTER TABLE ts_kv | |
23 | - RENAME TO ts_kv_old; | |
24 | - ALTER TABLE ts_kv_old | |
25 | - RENAME CONSTRAINT ts_kv_pkey TO ts_kv_pkey_old; | |
26 | - CREATE TABLE IF NOT EXISTS ts_kv | |
27 | - ( | |
28 | - LIKE ts_kv_old | |
29 | - ) | |
30 | - PARTITION BY RANGE (ts); | |
31 | - ALTER TABLE ts_kv | |
32 | - DROP COLUMN entity_type; | |
33 | - ALTER TABLE ts_kv | |
34 | - ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid; | |
35 | - ALTER TABLE ts_kv | |
36 | - ALTER COLUMN key TYPE integer USING key::integer; | |
37 | - ALTER TABLE ts_kv | |
38 | - ADD CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts); | |
24 | + ALTER TABLE ts_kv | |
25 | + DROP CONSTRAINT IF EXISTS ts_kv_unq_key; | |
26 | + ALTER TABLE ts_kv | |
27 | + DROP CONSTRAINT IF EXISTS ts_kv_pkey; | |
28 | + ALTER TABLE ts_kv | |
29 | + ADD CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_type, entity_id, key, ts); | |
30 | + ALTER TABLE ts_kv | |
31 | + RENAME TO ts_kv_old; | |
32 | + ALTER TABLE ts_kv_old | |
33 | + RENAME CONSTRAINT ts_kv_pkey TO ts_kv_pkey_old; | |
34 | + CREATE TABLE IF NOT EXISTS ts_kv | |
35 | + ( | |
36 | + LIKE ts_kv_old | |
37 | + ) | |
38 | + PARTITION BY RANGE (ts); | |
39 | + ALTER TABLE ts_kv | |
40 | + DROP COLUMN entity_type; | |
41 | + ALTER TABLE ts_kv | |
42 | + ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid; | |
43 | + ALTER TABLE ts_kv | |
44 | + ALTER COLUMN key TYPE integer USING key::integer; | |
45 | + ALTER TABLE ts_kv | |
46 | + ADD CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts); | |
47 | + CREATE TABLE IF NOT EXISTS ts_kv_indefinite PARTITION OF ts_kv DEFAULT; | |
39 | 48 | END; |
40 | 49 | $$; |
41 | 50 | |
42 | 51 | -- call create_new_ts_kv_latest_table(); |
43 | 52 | |
44 | -CREATE OR REPLACE PROCEDURE create_new_ts_kv_latest_table() LANGUAGE plpgsql AS $$ | |
53 | +CREATE OR REPLACE PROCEDURE create_new_ts_kv_latest_table() | |
54 | + LANGUAGE plpgsql AS | |
55 | +$$ | |
45 | 56 | |
46 | 57 | BEGIN |
47 | - ALTER TABLE ts_kv_latest | |
48 | - RENAME TO ts_kv_latest_old; | |
49 | - ALTER TABLE ts_kv_latest_old | |
50 | - RENAME CONSTRAINT ts_kv_latest_pkey TO ts_kv_latest_pkey_old; | |
51 | - CREATE TABLE IF NOT EXISTS ts_kv_latest | |
52 | - ( | |
53 | - LIKE ts_kv_latest_old | |
54 | - ); | |
55 | - ALTER TABLE ts_kv_latest | |
56 | - DROP COLUMN entity_type; | |
57 | - ALTER TABLE ts_kv_latest | |
58 | - ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid; | |
59 | - ALTER TABLE ts_kv_latest | |
60 | - ALTER COLUMN key TYPE integer USING key::integer; | |
61 | - ALTER TABLE ts_kv_latest | |
62 | - ADD CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key); | |
58 | + IF NOT EXISTS(SELECT FROM pg_tables WHERE schemaname = 'public' AND tablename = 'ts_kv_latest_old') THEN | |
59 | + ALTER TABLE ts_kv_latest | |
60 | + DROP CONSTRAINT IF EXISTS ts_kv_latest_unq_key; | |
61 | + ALTER TABLE ts_kv_latest | |
62 | + DROP CONSTRAINT IF EXISTS ts_kv_latest_pkey; | |
63 | + ALTER TABLE ts_kv_latest | |
64 | + ADD CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_type, entity_id, key); | |
65 | + ALTER TABLE ts_kv_latest | |
66 | + RENAME TO ts_kv_latest_old; | |
67 | + ALTER TABLE ts_kv_latest_old | |
68 | + RENAME CONSTRAINT ts_kv_latest_pkey TO ts_kv_latest_pkey_old; | |
69 | + CREATE TABLE IF NOT EXISTS ts_kv_latest | |
70 | + ( | |
71 | + LIKE ts_kv_latest_old | |
72 | + ); | |
73 | + ALTER TABLE ts_kv_latest | |
74 | + DROP COLUMN entity_type; | |
75 | + ALTER TABLE ts_kv_latest | |
76 | + ALTER COLUMN entity_id TYPE uuid USING entity_id::uuid; | |
77 | + ALTER TABLE ts_kv_latest | |
78 | + ALTER COLUMN key TYPE integer USING key::integer; | |
79 | + ALTER TABLE ts_kv_latest | |
80 | + ADD CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key); | |
81 | + ELSE | |
82 | + RAISE NOTICE 'ts_kv_latest_old table already exists!'; | |
83 | + IF NOT EXISTS(SELECT FROM pg_tables WHERE schemaname = 'public' AND tablename = 'ts_kv_latest') THEN | |
84 | + CREATE TABLE IF NOT EXISTS ts_kv_latest | |
85 | + ( | |
86 | + entity_id uuid NOT NULL, | |
87 | + key int NOT NULL, | |
88 | + ts bigint NOT NULL, | |
89 | + bool_v boolean, | |
90 | + str_v varchar(10000000), | |
91 | + long_v bigint, | |
92 | + dbl_v double precision, | |
93 | + json_v json, | |
94 | + CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) | |
95 | + ); | |
96 | + END IF; | |
97 | + END IF; | |
63 | 98 | END; |
64 | 99 | $$; |
65 | 100 | |
... | ... | @@ -93,8 +128,9 @@ BEGIN |
93 | 128 | RETURN QUERY SELECT SUBSTRING(year_date.year, 1, 4) AS partition_date, |
94 | 129 | (extract(epoch from (year_date.year)::timestamp) * 1000)::bigint AS from_ts, |
95 | 130 | (extract(epoch from (year_date.year::date + INTERVAL '1 YEAR')::timestamp) * |
96 | - 1000)::bigint AS to_ts | |
97 | - FROM (SELECT DISTINCT TO_CHAR(TO_TIMESTAMP(ts / 1000), 'YYYY_01_01') AS year FROM ts_kv_old) AS year_date; | |
131 | + 1000)::bigint AS to_ts | |
132 | + FROM (SELECT DISTINCT TO_CHAR(TO_TIMESTAMP(ts / 1000), 'YYYY_01_01') AS year | |
133 | + FROM ts_kv_old) AS year_date; | |
98 | 134 | ELSE |
99 | 135 | RAISE EXCEPTION 'Failed to parse partitioning property: % !', partition_type; |
100 | 136 | END CASE; |
... | ... | @@ -103,13 +139,16 @@ $$ LANGUAGE plpgsql; |
103 | 139 | |
104 | 140 | -- call create_partitions(); |
105 | 141 | |
106 | -CREATE OR REPLACE PROCEDURE create_partitions(IN partition_type varchar) LANGUAGE plpgsql AS $$ | |
142 | +CREATE OR REPLACE PROCEDURE create_partitions(IN partition_type varchar) | |
143 | + LANGUAGE plpgsql AS | |
144 | +$$ | |
107 | 145 | |
108 | 146 | DECLARE |
109 | 147 | partition_date varchar; |
110 | 148 | from_ts bigint; |
111 | 149 | to_ts bigint; |
112 | - partitions_cursor CURSOR FOR SELECT * FROM get_partitions_data(partition_type); | |
150 | + partitions_cursor CURSOR FOR SELECT * | |
151 | + FROM get_partitions_data(partition_type); | |
113 | 152 | BEGIN |
114 | 153 | OPEN partitions_cursor; |
115 | 154 | LOOP |
... | ... | @@ -127,21 +166,25 @@ $$; |
127 | 166 | |
128 | 167 | -- call create_ts_kv_dictionary_table(); |
129 | 168 | |
130 | -CREATE OR REPLACE PROCEDURE create_ts_kv_dictionary_table() LANGUAGE plpgsql AS $$ | |
169 | +CREATE OR REPLACE PROCEDURE create_ts_kv_dictionary_table() | |
170 | + LANGUAGE plpgsql AS | |
171 | +$$ | |
131 | 172 | |
132 | 173 | BEGIN |
133 | - CREATE TABLE IF NOT EXISTS ts_kv_dictionary | |
134 | - ( | |
135 | - key varchar(255) NOT NULL, | |
136 | - key_id serial UNIQUE, | |
137 | - CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) | |
138 | - ); | |
174 | + CREATE TABLE IF NOT EXISTS ts_kv_dictionary | |
175 | + ( | |
176 | + key varchar(255) NOT NULL, | |
177 | + key_id serial UNIQUE, | |
178 | + CONSTRAINT ts_key_id_pkey PRIMARY KEY (key) | |
179 | + ); | |
139 | 180 | END; |
140 | 181 | $$; |
141 | 182 | |
142 | 183 | -- call insert_into_dictionary(); |
143 | 184 | |
144 | -CREATE OR REPLACE PROCEDURE insert_into_dictionary() LANGUAGE plpgsql AS $$ | |
185 | +CREATE OR REPLACE PROCEDURE insert_into_dictionary() | |
186 | + LANGUAGE plpgsql AS | |
187 | +$$ | |
145 | 188 | |
146 | 189 | DECLARE |
147 | 190 | insert_record RECORD; |
... | ... | @@ -164,31 +207,89 @@ BEGIN |
164 | 207 | END; |
165 | 208 | $$; |
166 | 209 | |
167 | --- call insert_into_ts_kv(); | |
210 | +CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS | |
211 | +$$ | |
212 | +BEGIN | |
213 | + uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || | |
214 | + '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); | |
215 | +END; | |
216 | +$$ LANGUAGE plpgsql; | |
168 | 217 | |
169 | -CREATE OR REPLACE PROCEDURE insert_into_ts_kv() LANGUAGE plpgsql AS $$ | |
170 | -DECLARE | |
171 | - insert_size CONSTANT integer := 10000; | |
172 | - insert_counter integer DEFAULT 0; | |
173 | - insert_record RECORD; | |
174 | - insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id, | |
218 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv(IN path_to_file varchar) | |
219 | + LANGUAGE plpgsql AS | |
220 | +$$ | |
221 | +BEGIN | |
222 | + EXECUTE format('COPY (SELECT to_uuid(entity_id) AS entity_id, | |
175 | 223 | ts_kv_records.key AS key, |
176 | 224 | ts_kv_records.ts AS ts, |
177 | 225 | ts_kv_records.bool_v AS bool_v, |
178 | 226 | ts_kv_records.str_v AS str_v, |
179 | 227 | ts_kv_records.long_v AS long_v, |
180 | 228 | ts_kv_records.dbl_v AS dbl_v |
181 | - FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part, | |
182 | - SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part, | |
183 | - SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part, | |
184 | - SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part, | |
185 | - SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part, | |
229 | + FROM (SELECT entity_id AS entity_id, | |
230 | + key_id AS key, | |
231 | + ts, | |
232 | + bool_v, | |
233 | + str_v, | |
234 | + long_v, | |
235 | + dbl_v | |
236 | + FROM ts_kv_old | |
237 | + INNER JOIN ts_kv_dictionary ON (ts_kv_old.key = ts_kv_dictionary.key)) AS ts_kv_records) TO %L;', | |
238 | + path_to_file); | |
239 | + EXECUTE format('COPY ts_kv FROM %L', path_to_file); | |
240 | +END | |
241 | +$$; | |
242 | + | |
243 | +-- call insert_into_ts_kv_latest(); | |
244 | + | |
245 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest(IN path_to_file varchar) | |
246 | + LANGUAGE plpgsql AS | |
247 | +$$ | |
248 | +BEGIN | |
249 | + EXECUTE format('COPY (SELECT to_uuid(entity_id) AS entity_id, | |
250 | + ts_kv_latest_records.key AS key, | |
251 | + ts_kv_latest_records.ts AS ts, | |
252 | + ts_kv_latest_records.bool_v AS bool_v, | |
253 | + ts_kv_latest_records.str_v AS str_v, | |
254 | + ts_kv_latest_records.long_v AS long_v, | |
255 | + ts_kv_latest_records.dbl_v AS dbl_v | |
256 | + FROM (SELECT entity_id AS entity_id, | |
186 | 257 | key_id AS key, |
187 | 258 | ts, |
188 | 259 | bool_v, |
189 | 260 | str_v, |
190 | 261 | long_v, |
191 | 262 | dbl_v |
263 | + FROM ts_kv_latest_old | |
264 | + INNER JOIN ts_kv_dictionary ON (ts_kv_latest_old.key = ts_kv_dictionary.key)) AS ts_kv_latest_records) TO %L;', | |
265 | + path_to_file); | |
266 | + EXECUTE format('COPY ts_kv_latest FROM %L', path_to_file); | |
267 | +END; | |
268 | +$$; | |
269 | + | |
270 | +-- call insert_into_ts_kv_cursor(); | |
271 | + | |
272 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_cursor() | |
273 | + LANGUAGE plpgsql AS | |
274 | +$$ | |
275 | +DECLARE | |
276 | + insert_size CONSTANT integer := 10000; | |
277 | + insert_counter integer DEFAULT 0; | |
278 | + insert_record RECORD; | |
279 | + insert_cursor CURSOR FOR SELECT to_uuid(entity_id) AS entity_id, | |
280 | + ts_kv_records.key AS key, | |
281 | + ts_kv_records.ts AS ts, | |
282 | + ts_kv_records.bool_v AS bool_v, | |
283 | + ts_kv_records.str_v AS str_v, | |
284 | + ts_kv_records.long_v AS long_v, | |
285 | + ts_kv_records.dbl_v AS dbl_v | |
286 | + FROM (SELECT entity_id AS entity_id, | |
287 | + key_id AS key, | |
288 | + ts, | |
289 | + bool_v, | |
290 | + str_v, | |
291 | + long_v, | |
292 | + dbl_v | |
192 | 293 | FROM ts_kv_old |
193 | 294 | INNER JOIN ts_kv_dictionary ON (ts_kv_old.key = ts_kv_dictionary.key)) AS ts_kv_records; |
194 | 295 | BEGIN |
... | ... | @@ -211,26 +312,24 @@ BEGIN |
211 | 312 | END; |
212 | 313 | $$; |
213 | 314 | |
214 | --- call insert_into_ts_kv_latest(); | |
315 | +-- call insert_into_ts_kv_latest_cursor(); | |
215 | 316 | |
216 | -CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest() LANGUAGE plpgsql AS $$ | |
317 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_latest_cursor() | |
318 | + LANGUAGE plpgsql AS | |
319 | +$$ | |
217 | 320 | DECLARE |
218 | 321 | insert_size CONSTANT integer := 10000; |
219 | 322 | insert_counter integer DEFAULT 0; |
220 | 323 | insert_record RECORD; |
221 | - insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id, | |
222 | - ts_kv_latest_records.key AS key, | |
223 | - ts_kv_latest_records.ts AS ts, | |
224 | - ts_kv_latest_records.bool_v AS bool_v, | |
225 | - ts_kv_latest_records.str_v AS str_v, | |
226 | - ts_kv_latest_records.long_v AS long_v, | |
227 | - ts_kv_latest_records.dbl_v AS dbl_v | |
228 | - FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part, | |
229 | - SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part, | |
230 | - SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part, | |
231 | - SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part, | |
232 | - SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part, | |
233 | - key_id AS key, | |
324 | + insert_cursor CURSOR FOR SELECT to_uuid(entity_id) AS entity_id, | |
325 | + ts_kv_latest_records.key AS key, | |
326 | + ts_kv_latest_records.ts AS ts, | |
327 | + ts_kv_latest_records.bool_v AS bool_v, | |
328 | + ts_kv_latest_records.str_v AS str_v, | |
329 | + ts_kv_latest_records.long_v AS long_v, | |
330 | + ts_kv_latest_records.dbl_v AS dbl_v | |
331 | + FROM (SELECT entity_id AS entity_id, | |
332 | + key_id AS key, | |
234 | 333 | ts, |
235 | 334 | bool_v, |
236 | 335 | str_v, |
... | ... | @@ -258,4 +357,3 @@ BEGIN |
258 | 357 | END; |
259 | 358 | $$; |
260 | 359 | |
261 | - | ... | ... |
... | ... | @@ -96,51 +96,36 @@ BEGIN |
96 | 96 | END; |
97 | 97 | $$; |
98 | 98 | |
99 | --- call insert_into_ts_kv(); | |
99 | +CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS | |
100 | +$$ | |
101 | +BEGIN | |
102 | + uuid_id := substring(entity_id, 8, 8) || '-' || substring(entity_id, 4, 4) || '-1' || substring(entity_id, 1, 3) || | |
103 | + '-' || substring(entity_id, 16, 4) || '-' || substring(entity_id, 20, 12); | |
104 | +END; | |
105 | +$$ LANGUAGE plpgsql; | |
100 | 106 | |
101 | -CREATE OR REPLACE PROCEDURE insert_into_ts_kv() LANGUAGE plpgsql AS $$ | |
107 | +-- call insert_into_ts_kv(); | |
102 | 108 | |
103 | -DECLARE | |
104 | - insert_size CONSTANT integer := 10000; | |
105 | - insert_counter integer DEFAULT 0; | |
106 | - insert_record RECORD; | |
107 | - insert_cursor CURSOR FOR SELECT CONCAT(entity_id_uuid_first_part, '-', entity_id_uuid_second_part, '-1', entity_id_uuid_third_part, '-', entity_id_uuid_fourth_part, '-', entity_id_uuid_fifth_part)::uuid AS entity_id, | |
108 | - new_ts_kv_records.key AS key, | |
109 | - new_ts_kv_records.ts AS ts, | |
110 | - new_ts_kv_records.bool_v AS bool_v, | |
111 | - new_ts_kv_records.str_v AS str_v, | |
112 | - new_ts_kv_records.long_v AS long_v, | |
113 | - new_ts_kv_records.dbl_v AS dbl_v | |
114 | - FROM (SELECT SUBSTRING(entity_id, 8, 8) AS entity_id_uuid_first_part, | |
115 | - SUBSTRING(entity_id, 4, 4) AS entity_id_uuid_second_part, | |
116 | - SUBSTRING(entity_id, 1, 3) AS entity_id_uuid_third_part, | |
117 | - SUBSTRING(entity_id, 16, 4) AS entity_id_uuid_fourth_part, | |
118 | - SUBSTRING(entity_id, 20) AS entity_id_uuid_fifth_part, | |
119 | - key_id AS key, | |
120 | - ts, | |
121 | - bool_v, | |
122 | - str_v, | |
123 | - long_v, | |
124 | - dbl_v | |
125 | - FROM tenant_ts_kv_old | |
126 | - INNER JOIN ts_kv_dictionary ON (tenant_ts_kv_old.key = ts_kv_dictionary.key)) AS new_ts_kv_records; | |
109 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv(IN path_to_file varchar) LANGUAGE plpgsql AS $$ | |
127 | 110 | BEGIN |
128 | - OPEN insert_cursor; | |
129 | - LOOP | |
130 | - insert_counter := insert_counter + 1; | |
131 | - FETCH insert_cursor INTO insert_record; | |
132 | - IF NOT FOUND THEN | |
133 | - RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter - 1; | |
134 | - EXIT; | |
135 | - END IF; | |
136 | - INSERT INTO ts_kv(entity_id, key, ts, bool_v, str_v, long_v, dbl_v) | |
137 | - VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v, | |
138 | - insert_record.long_v, insert_record.dbl_v); | |
139 | - IF MOD(insert_counter, insert_size) = 0 THEN | |
140 | - RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter; | |
141 | - END IF; | |
142 | - END LOOP; | |
143 | - CLOSE insert_cursor; | |
111 | + | |
112 | + EXECUTE format ('COPY (SELECT to_uuid(entity_id) AS entity_id, | |
113 | + new_ts_kv_records.key AS key, | |
114 | + new_ts_kv_records.ts AS ts, | |
115 | + new_ts_kv_records.bool_v AS bool_v, | |
116 | + new_ts_kv_records.str_v AS str_v, | |
117 | + new_ts_kv_records.long_v AS long_v, | |
118 | + new_ts_kv_records.dbl_v AS dbl_v | |
119 | + FROM (SELECT entity_id AS entity_id, | |
120 | + key_id AS key, | |
121 | + ts, | |
122 | + bool_v, | |
123 | + str_v, | |
124 | + long_v, | |
125 | + dbl_v | |
126 | + FROM tenant_ts_kv_old | |
127 | + INNER JOIN ts_kv_dictionary ON (tenant_ts_kv_old.key = ts_kv_dictionary.key)) AS new_ts_kv_records) TO %L;', path_to_file); | |
128 | + EXECUTE format ('COPY ts_kv FROM %L', path_to_file); | |
144 | 129 | END; |
145 | 130 | $$; |
146 | 131 | |
... | ... | @@ -177,3 +162,47 @@ BEGIN |
177 | 162 | CLOSE insert_cursor; |
178 | 163 | END; |
179 | 164 | $$; |
165 | + | |
166 | +-- call insert_into_ts_kv_cursor(); | |
167 | + | |
168 | +CREATE OR REPLACE PROCEDURE insert_into_ts_kv_cursor() LANGUAGE plpgsql AS $$ | |
169 | + | |
170 | +DECLARE | |
171 | + insert_size CONSTANT integer := 10000; | |
172 | + insert_counter integer DEFAULT 0; | |
173 | + insert_record RECORD; | |
174 | + insert_cursor CURSOR FOR SELECT to_uuid(entity_id) AS entity_id, | |
175 | + new_ts_kv_records.key AS key, | |
176 | + new_ts_kv_records.ts AS ts, | |
177 | + new_ts_kv_records.bool_v AS bool_v, | |
178 | + new_ts_kv_records.str_v AS str_v, | |
179 | + new_ts_kv_records.long_v AS long_v, | |
180 | + new_ts_kv_records.dbl_v AS dbl_v | |
181 | + FROM (SELECT entity_id AS entity_id, | |
182 | + key_id AS key, | |
183 | + ts, | |
184 | + bool_v, | |
185 | + str_v, | |
186 | + long_v, | |
187 | + dbl_v | |
188 | + FROM tenant_ts_kv_old | |
189 | + INNER JOIN ts_kv_dictionary ON (tenant_ts_kv_old.key = ts_kv_dictionary.key)) AS new_ts_kv_records; | |
190 | +BEGIN | |
191 | + OPEN insert_cursor; | |
192 | + LOOP | |
193 | + insert_counter := insert_counter + 1; | |
194 | + FETCH insert_cursor INTO insert_record; | |
195 | + IF NOT FOUND THEN | |
196 | + RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter - 1; | |
197 | + EXIT; | |
198 | + END IF; | |
199 | + INSERT INTO ts_kv(entity_id, key, ts, bool_v, str_v, long_v, dbl_v) | |
200 | + VALUES (insert_record.entity_id, insert_record.key, insert_record.ts, insert_record.bool_v, insert_record.str_v, | |
201 | + insert_record.long_v, insert_record.dbl_v); | |
202 | + IF MOD(insert_counter, insert_size) = 0 THEN | |
203 | + RAISE NOTICE '% records have been inserted into the new ts_kv table!',insert_counter; | |
204 | + END IF; | |
205 | + END LOOP; | |
206 | + CLOSE insert_cursor; | |
207 | +END; | |
208 | +$$; | |
\ No newline at end of file | ... | ... |
... | ... | @@ -56,6 +56,7 @@ import org.thingsboard.server.dao.audit.AuditLogService; |
56 | 56 | import org.thingsboard.server.dao.cassandra.CassandraCluster; |
57 | 57 | import org.thingsboard.server.dao.customer.CustomerService; |
58 | 58 | import org.thingsboard.server.dao.dashboard.DashboardService; |
59 | +import org.thingsboard.server.dao.device.ClaimDevicesService; | |
59 | 60 | import org.thingsboard.server.dao.device.DeviceService; |
60 | 61 | import org.thingsboard.server.dao.edge.EdgeService; |
61 | 62 | import org.thingsboard.server.dao.entityview.EntityViewService; |
... | ... | @@ -219,6 +220,10 @@ public class ActorSystemContext { |
219 | 220 | @Getter |
220 | 221 | private MailService mailService; |
221 | 222 | |
223 | + @Autowired | |
224 | + @Getter | |
225 | + private ClaimDevicesService claimDevicesService; | |
226 | + | |
222 | 227 | //TODO: separate context for TbCore and TbRuleEngine |
223 | 228 | @Autowired(required = false) |
224 | 229 | @Getter | ... | ... |
... | ... | @@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; |
39 | 39 | import org.thingsboard.server.common.msg.queue.TbCallback; |
40 | 40 | import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; |
41 | 41 | import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; |
42 | +import org.thingsboard.server.gen.transport.TransportProtos; | |
42 | 43 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
43 | 44 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; |
44 | 45 | import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; |
... | ... | @@ -232,9 +233,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { |
232 | 233 | if (msg.hasSubscriptionInfo()) { |
233 | 234 | handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); |
234 | 235 | } |
236 | + if (msg.hasClaimDevice()) { | |
237 | + handleClaimDeviceMsg(context, msg.getSessionInfo(), msg.getClaimDevice()); | |
238 | + } | |
235 | 239 | callback.onSuccess(); |
236 | 240 | } |
237 | 241 | |
242 | + private void handleClaimDeviceMsg(ActorContext context, SessionInfoProto sessionInfo, TransportProtos.ClaimDeviceMsg msg) { | |
243 | + DeviceId deviceId = new DeviceId(new UUID(msg.getDeviceIdMSB(), msg.getDeviceIdLSB())); | |
244 | + systemContext.getClaimDevicesService().registerClaimingInfo(tenantId, deviceId, msg.getSecretKey(), msg.getDurationMs()); | |
245 | + } | |
246 | + | |
238 | 247 | private void reportSessionOpen() { |
239 | 248 | systemContext.getDeviceStateService().onDeviceConnect(deviceId); |
240 | 249 | } | ... | ... |
... | ... | @@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; |
28 | 28 | import org.springframework.web.bind.annotation.RestController; |
29 | 29 | import org.thingsboard.server.common.data.EntityType; |
30 | 30 | import org.thingsboard.server.common.data.alarm.Alarm; |
31 | -import org.thingsboard.server.common.data.id.AlarmId; | |
32 | 31 | import org.thingsboard.server.common.data.alarm.AlarmInfo; |
33 | 32 | import org.thingsboard.server.common.data.alarm.AlarmQuery; |
34 | 33 | import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
... | ... | @@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; |
37 | 36 | import org.thingsboard.server.common.data.audit.ActionType; |
38 | 37 | import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
39 | 38 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
39 | +import org.thingsboard.server.common.data.id.AlarmId; | |
40 | 40 | import org.thingsboard.server.common.data.id.EntityId; |
41 | 41 | import org.thingsboard.server.common.data.id.EntityIdFactory; |
42 | 42 | import org.thingsboard.server.common.data.page.TimePageData; |
... | ... | @@ -84,8 +84,9 @@ public class AlarmController extends BaseController { |
84 | 84 | public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException { |
85 | 85 | try { |
86 | 86 | alarm.setTenantId(getCurrentUser().getTenantId()); |
87 | - Operation operation = alarm.getId() == null ? Operation.CREATE : Operation.WRITE; | |
88 | - accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarm.getId(), alarm); | |
87 | + | |
88 | + checkEntity(alarm.getId(), alarm, Resource.ALARM); | |
89 | + | |
89 | 90 | Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm)); |
90 | 91 | logEntityAction(savedAlarm.getId(), savedAlarm, |
91 | 92 | getCurrentUser().getCustomerId(), | ... | ... |
... | ... | @@ -82,18 +82,15 @@ public class AssetController extends BaseController { |
82 | 82 | try { |
83 | 83 | asset.setTenantId(getCurrentUser().getTenantId()); |
84 | 84 | |
85 | - Operation operation = asset.getId() == null ? Operation.CREATE : Operation.WRITE; | |
85 | + checkEntity(asset.getId(), asset, Resource.ASSET); | |
86 | 86 | |
87 | - accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, | |
88 | - asset.getId(), asset); | |
89 | - | |
90 | - Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); | |
87 | + Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); | |
91 | 88 | |
92 | 89 | logEntityAction(savedAsset.getId(), savedAsset, |
93 | 90 | savedAsset.getCustomerId(), |
94 | 91 | asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); |
95 | 92 | |
96 | - return savedAsset; | |
93 | + return savedAsset; | |
97 | 94 | } catch (Exception e) { |
98 | 95 | logEntityAction(emptyId(EntityType.ASSET), asset, |
99 | 96 | null, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); |
... | ... | @@ -144,7 +141,7 @@ public class AssetController extends BaseController { |
144 | 141 | savedAsset.getCustomerId(), |
145 | 142 | ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName()); |
146 | 143 | |
147 | - return savedAsset; | |
144 | + return savedAsset; | |
148 | 145 | } catch (Exception e) { |
149 | 146 | |
150 | 147 | logEntityAction(emptyId(EntityType.ASSET), null, |
... | ... | @@ -224,7 +221,7 @@ public class AssetController extends BaseController { |
224 | 221 | try { |
225 | 222 | TenantId tenantId = getCurrentUser().getTenantId(); |
226 | 223 | TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
227 | - if (type != null && type.trim().length()>0) { | |
224 | + if (type != null && type.trim().length() > 0) { | |
228 | 225 | return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink)); |
229 | 226 | } else { |
230 | 227 | return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink)); |
... | ... | @@ -263,7 +260,7 @@ public class AssetController extends BaseController { |
263 | 260 | CustomerId customerId = new CustomerId(toUUID(strCustomerId)); |
264 | 261 | checkCustomerId(customerId, Operation.READ); |
265 | 262 | TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); |
266 | - if (type != null && type.trim().length()>0) { | |
263 | + if (type != null && type.trim().length() > 0) { | |
267 | 264 | return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); |
268 | 265 | } else { |
269 | 266 | return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); | ... | ... |
... | ... | @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value; |
26 | 26 | import org.springframework.security.core.Authentication; |
27 | 27 | import org.springframework.security.core.context.SecurityContextHolder; |
28 | 28 | import org.springframework.web.bind.annotation.ExceptionHandler; |
29 | +import org.thingsboard.server.common.data.BaseData; | |
29 | 30 | import org.thingsboard.server.common.data.Customer; |
30 | 31 | import org.thingsboard.server.common.data.Dashboard; |
31 | 32 | import org.thingsboard.server.common.data.DashboardInfo; |
... | ... | @@ -107,7 +108,6 @@ import org.thingsboard.server.service.state.DeviceStateService; |
107 | 108 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
108 | 109 | |
109 | 110 | import javax.mail.MessagingException; |
110 | -import javax.servlet.http.HttpServletRequest; | |
111 | 111 | import javax.servlet.http.HttpServletResponse; |
112 | 112 | import java.util.List; |
113 | 113 | import java.util.Optional; |
... | ... | @@ -337,11 +337,23 @@ public abstract class BaseController { |
337 | 337 | } |
338 | 338 | } |
339 | 339 | |
340 | + protected <I extends EntityId, T extends HasTenantId> void checkEntity(I entityId, T entity, Resource resource) throws ThingsboardException { | |
341 | + if (entityId == null) { | |
342 | + accessControlService | |
343 | + .checkPermission(getCurrentUser(), resource, Operation.CREATE, null, entity); | |
344 | + } else { | |
345 | + checkEntityId(entityId, Operation.WRITE); | |
346 | + } | |
347 | + } | |
348 | + | |
340 | 349 | protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException { |
341 | 350 | try { |
342 | 351 | checkNotNull(entityId); |
343 | 352 | validateId(entityId.getId(), "Incorrect entityId " + entityId); |
344 | 353 | switch (entityId.getEntityType()) { |
354 | + case ALARM: | |
355 | + checkAlarmId(new AlarmId(entityId.getId()), operation); | |
356 | + return; | |
345 | 357 | case DEVICE: |
346 | 358 | checkDeviceId(new DeviceId(entityId.getId()), operation); |
347 | 359 | return; |
... | ... | @@ -372,6 +384,12 @@ public abstract class BaseController { |
372 | 384 | case EDGE: |
373 | 385 | checkEdgeId(new EdgeId(entityId.getId()), operation); |
374 | 386 | return; |
387 | + case WIDGETS_BUNDLE: | |
388 | + checkWidgetsBundleId(new WidgetsBundleId(entityId.getId()), operation); | |
389 | + return; | |
390 | + case WIDGET_TYPE: | |
391 | + checkWidgetTypeId(new WidgetTypeId(entityId.getId()), operation); | |
392 | + return; | |
375 | 393 | default: |
376 | 394 | throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); |
377 | 395 | } | ... | ... |
... | ... | @@ -100,8 +100,7 @@ public class CustomerController extends BaseController { |
100 | 100 | try { |
101 | 101 | customer.setTenantId(getCurrentUser().getTenantId()); |
102 | 102 | |
103 | - Operation operation = customer.getId() == null ? Operation.CREATE : Operation.WRITE; | |
104 | - accessControlService.checkPermission(getCurrentUser(), Resource.CUSTOMER, operation, customer.getId(), customer); | |
103 | + checkEntity(customer.getId(), customer, Resource.CUSTOMER); | |
105 | 104 | |
106 | 105 | Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer)); |
107 | 106 | ... | ... |
... | ... | @@ -103,15 +103,12 @@ public class DashboardController extends BaseController { |
103 | 103 | |
104 | 104 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
105 | 105 | @RequestMapping(value = "/dashboard", method = RequestMethod.POST) |
106 | - @ResponseBody | |
106 | + @ResponseBody | |
107 | 107 | public Dashboard saveDashboard(@RequestBody Dashboard dashboard) throws ThingsboardException { |
108 | 108 | try { |
109 | 109 | dashboard.setTenantId(getCurrentUser().getTenantId()); |
110 | 110 | |
111 | - Operation operation = dashboard.getId() == null ? Operation.CREATE : Operation.WRITE; | |
112 | - | |
113 | - accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, | |
114 | - dashboard.getId(), dashboard); | |
111 | + checkEntity(dashboard.getId(), dashboard, Resource.DASHBOARD); | |
115 | 112 | |
116 | 113 | Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); |
117 | 114 | |
... | ... | @@ -155,9 +152,9 @@ public class DashboardController extends BaseController { |
155 | 152 | |
156 | 153 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
157 | 154 | @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST) |
158 | - @ResponseBody | |
155 | + @ResponseBody | |
159 | 156 | public Dashboard assignDashboardToCustomer(@PathVariable("customerId") String strCustomerId, |
160 | - @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | |
157 | + @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { | |
161 | 158 | checkParameter("customerId", strCustomerId); |
162 | 159 | checkParameter(DASHBOARD_ID, strDashboardId); |
163 | 160 | try { |
... | ... | @@ -166,7 +163,7 @@ public class DashboardController extends BaseController { |
166 | 163 | |
167 | 164 | DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); |
168 | 165 | checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); |
169 | - | |
166 | + | |
170 | 167 | Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); |
171 | 168 | |
172 | 169 | logEntityAction(dashboardId, savedDashboard, |
... | ... | @@ -187,7 +184,7 @@ public class DashboardController extends BaseController { |
187 | 184 | |
188 | 185 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
189 | 186 | @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) |
190 | - @ResponseBody | |
187 | + @ResponseBody | |
191 | 188 | public Dashboard unassignDashboardFromCustomer(@PathVariable("customerId") String strCustomerId, |
192 | 189 | @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { |
193 | 190 | checkParameter("customerId", strCustomerId); |
... | ... | @@ -421,7 +418,7 @@ public class DashboardController extends BaseController { |
421 | 418 | } |
422 | 419 | |
423 | 420 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
424 | - @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
421 | + @RequestMapping(value = "/tenant/{tenantId}/dashboards", params = {"limit"}, method = RequestMethod.GET) | |
425 | 422 | @ResponseBody |
426 | 423 | public TextPageData<DashboardInfo> getTenantDashboards( |
427 | 424 | @PathVariable("tenantId") String strTenantId, |
... | ... | @@ -440,7 +437,7 @@ public class DashboardController extends BaseController { |
440 | 437 | } |
441 | 438 | |
442 | 439 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
443 | - @RequestMapping(value = "/tenant/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
440 | + @RequestMapping(value = "/tenant/dashboards", params = {"limit"}, method = RequestMethod.GET) | |
444 | 441 | @ResponseBody |
445 | 442 | public TextPageData<DashboardInfo> getTenantDashboards( |
446 | 443 | @RequestParam int limit, |
... | ... | @@ -457,7 +454,7 @@ public class DashboardController extends BaseController { |
457 | 454 | } |
458 | 455 | |
459 | 456 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
460 | - @RequestMapping(value = "/customer/{customerId}/dashboards", params = { "limit" }, method = RequestMethod.GET) | |
457 | + @RequestMapping(value = "/customer/{customerId}/dashboards", params = {"limit"}, method = RequestMethod.GET) | |
461 | 458 | @ResponseBody |
462 | 459 | public TimePageData<DashboardInfo> getCustomerDashboards( |
463 | 460 | @PathVariable("customerId") String strCustomerId, | ... | ... |
... | ... | @@ -99,10 +99,7 @@ public class DeviceController extends BaseController { |
99 | 99 | try { |
100 | 100 | device.setTenantId(getCurrentUser().getTenantId()); |
101 | 101 | |
102 | - Operation operation = device.getId() == null ? Operation.CREATE : Operation.WRITE; | |
103 | - | |
104 | - accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, | |
105 | - device.getId(), device); | |
102 | + checkEntity(device.getId(), device, Resource.DEVICE); | |
106 | 103 | |
107 | 104 | Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); |
108 | 105 | ... | ... |
... | ... | @@ -97,10 +97,7 @@ public class EntityViewController extends BaseController { |
97 | 97 | try { |
98 | 98 | entityView.setTenantId(getCurrentUser().getTenantId()); |
99 | 99 | |
100 | - Operation operation = entityView.getId() == null ? Operation.CREATE : Operation.WRITE; | |
101 | - | |
102 | - accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, | |
103 | - entityView.getId(), entityView); | |
100 | + checkEntity(entityView.getId(), entityView, Resource.ENTITY_VIEW); | |
104 | 101 | |
105 | 102 | EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); |
106 | 103 | List<ListenableFuture<List<Void>>> futures = new ArrayList<>(); | ... | ... |
... | ... | @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; |
20 | 20 | import com.google.common.util.concurrent.FutureCallback; |
21 | 21 | import lombok.extern.slf4j.Slf4j; |
22 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | +import org.springframework.beans.factory.annotation.Value; | |
23 | 24 | import org.springframework.http.HttpStatus; |
24 | 25 | import org.springframework.http.ResponseEntity; |
25 | 26 | import org.springframework.security.access.prepost.PreAuthorize; |
... | ... | @@ -65,7 +66,6 @@ import java.util.UUID; |
65 | 66 | @Slf4j |
66 | 67 | public class RpcController extends BaseController { |
67 | 68 | |
68 | - public static final int DEFAULT_TIMEOUT = 10000; | |
69 | 69 | protected final ObjectMapper jsonMapper = new ObjectMapper(); |
70 | 70 | |
71 | 71 | @Autowired |
... | ... | @@ -74,6 +74,12 @@ public class RpcController extends BaseController { |
74 | 74 | @Autowired |
75 | 75 | private AccessValidator accessValidator; |
76 | 76 | |
77 | + @Value("${server.rest.server_side_rpc.min_timeout:5000}") | |
78 | + private long minTimeout; | |
79 | + | |
80 | + @Value("${server.rest.server_side_rpc.default_timeout:10000}") | |
81 | + private long defaultTimeout; | |
82 | + | |
77 | 83 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
78 | 84 | @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) |
79 | 85 | @ResponseBody |
... | ... | @@ -100,7 +106,8 @@ public class RpcController extends BaseController { |
100 | 106 | SecurityUser currentUser = getCurrentUser(); |
101 | 107 | TenantId tenantId = currentUser.getTenantId(); |
102 | 108 | final DeferredResult<ResponseEntity> response = new DeferredResult<>(); |
103 | - long timeout = System.currentTimeMillis() + (cmd.getTimeout() != null ? cmd.getTimeout() : DEFAULT_TIMEOUT); | |
109 | + long timeout = cmd.getTimeout() != null ? cmd.getTimeout() : defaultTimeout; | |
110 | + long expTime = System.currentTimeMillis() + Math.max(minTimeout, timeout); | |
104 | 111 | ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(cmd.getMethodName(), cmd.getRequestData()); |
105 | 112 | accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() { |
106 | 113 | @Override |
... | ... | @@ -109,7 +116,7 @@ public class RpcController extends BaseController { |
109 | 116 | tenantId, |
110 | 117 | deviceId, |
111 | 118 | oneWay, |
112 | - timeout, | |
119 | + expTime, | |
113 | 120 | body |
114 | 121 | ); |
115 | 122 | deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse)); | ... | ... |
... | ... | @@ -130,10 +130,7 @@ public class RuleChainController extends BaseController { |
130 | 130 | boolean created = ruleChain.getId() == null; |
131 | 131 | ruleChain.setTenantId(getCurrentUser().getTenantId()); |
132 | 132 | |
133 | - Operation operation = created ? Operation.CREATE : Operation.WRITE; | |
134 | - | |
135 | - accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation, | |
136 | - ruleChain.getId(), ruleChain); | |
133 | + checkEntity(ruleChain.getId(), ruleChain, Resource.RULE_CHAIN); | |
137 | 134 | |
138 | 135 | RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); |
139 | 136 | ... | ... |
... | ... | @@ -72,10 +72,8 @@ public class TenantController extends BaseController { |
72 | 72 | try { |
73 | 73 | boolean newTenant = tenant.getId() == null; |
74 | 74 | |
75 | - Operation operation = newTenant ? Operation.CREATE : Operation.WRITE; | |
75 | + checkEntity(tenant.getId(), tenant, Resource.TENANT); | |
76 | 76 | |
77 | - accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, | |
78 | - tenant.getId(), tenant); | |
79 | 77 | tenant = checkNotNull(tenantService.saveTenant(tenant)); |
80 | 78 | if (newTenant) { |
81 | 79 | installScripts.createDefaultRuleChains(tenant.getId()); | ... | ... |
... | ... | @@ -132,17 +132,13 @@ public class UserController extends BaseController { |
132 | 132 | @ResponseBody |
133 | 133 | public User saveUser(@RequestBody User user, |
134 | 134 | @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, |
135 | - HttpServletRequest request) throws ThingsboardException { | |
135 | + HttpServletRequest request) throws ThingsboardException { | |
136 | 136 | try { |
137 | - | |
138 | 137 | if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) { |
139 | 138 | user.setTenantId(getCurrentUser().getTenantId()); |
140 | 139 | } |
141 | 140 | |
142 | - Operation operation = user.getId() == null ? Operation.CREATE : Operation.WRITE; | |
143 | - | |
144 | - accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation, | |
145 | - user.getId(), user); | |
141 | + checkEntity(user.getId(), user, Resource.USER); | |
146 | 142 | |
147 | 143 | boolean sendEmail = user.getId() == null && sendActivationMail; |
148 | 144 | User savedUser = checkNotNull(userService.saveUser(user)); |
... | ... | @@ -250,7 +246,7 @@ public class UserController extends BaseController { |
250 | 246 | } |
251 | 247 | |
252 | 248 | @PreAuthorize("hasAuthority('SYS_ADMIN')") |
253 | - @RequestMapping(value = "/tenant/{tenantId}/users", params = { "limit" }, method = RequestMethod.GET) | |
249 | + @RequestMapping(value = "/tenant/{tenantId}/users", params = {"limit"}, method = RequestMethod.GET) | |
254 | 250 | @ResponseBody |
255 | 251 | public TextPageData<User> getTenantAdmins( |
256 | 252 | @PathVariable("tenantId") String strTenantId, |
... | ... | @@ -269,7 +265,7 @@ public class UserController extends BaseController { |
269 | 265 | } |
270 | 266 | |
271 | 267 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
272 | - @RequestMapping(value = "/customer/{customerId}/users", params = { "limit" }, method = RequestMethod.GET) | |
268 | + @RequestMapping(value = "/customer/{customerId}/users", params = {"limit"}, method = RequestMethod.GET) | |
273 | 269 | @ResponseBody |
274 | 270 | public TextPageData<User> getCustomerUsers( |
275 | 271 | @PathVariable("customerId") String strCustomerId, | ... | ... |
... | ... | @@ -66,10 +66,7 @@ public class WidgetTypeController extends BaseController { |
66 | 66 | widgetType.setTenantId(getCurrentUser().getTenantId()); |
67 | 67 | } |
68 | 68 | |
69 | - Operation operation = widgetType.getId() == null ? Operation.CREATE : Operation.WRITE; | |
70 | - | |
71 | - accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation, | |
72 | - widgetType.getId(), widgetType); | |
69 | + checkEntity(widgetType.getId(), widgetType, Resource.WIDGET_TYPE); | |
73 | 70 | |
74 | 71 | return checkNotNull(widgetTypeService.saveWidgetType(widgetType)); |
75 | 72 | } catch (Exception e) { |
... | ... | @@ -92,7 +89,7 @@ public class WidgetTypeController extends BaseController { |
92 | 89 | } |
93 | 90 | |
94 | 91 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
95 | - @RequestMapping(value = "/widgetTypes", params = { "isSystem", "bundleAlias"}, method = RequestMethod.GET) | |
92 | + @RequestMapping(value = "/widgetTypes", params = {"isSystem", "bundleAlias"}, method = RequestMethod.GET) | |
96 | 93 | @ResponseBody |
97 | 94 | public List<WidgetType> getBundleWidgetTypes( |
98 | 95 | @RequestParam boolean isSystem, |
... | ... | @@ -111,7 +108,7 @@ public class WidgetTypeController extends BaseController { |
111 | 108 | } |
112 | 109 | |
113 | 110 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
114 | - @RequestMapping(value = "/widgetType", params = { "isSystem", "bundleAlias", "alias" }, method = RequestMethod.GET) | |
111 | + @RequestMapping(value = "/widgetType", params = {"isSystem", "bundleAlias", "alias"}, method = RequestMethod.GET) | |
115 | 112 | @ResponseBody |
116 | 113 | public WidgetType getWidgetType( |
117 | 114 | @RequestParam boolean isSystem, | ... | ... |
... | ... | @@ -67,11 +67,7 @@ public class WidgetsBundleController extends BaseController { |
67 | 67 | widgetsBundle.setTenantId(getCurrentUser().getTenantId()); |
68 | 68 | } |
69 | 69 | |
70 | - Operation operation = widgetsBundle.getId() == null ? Operation.CREATE : Operation.WRITE; | |
71 | - | |
72 | - accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation, | |
73 | - widgetsBundle.getId(), widgetsBundle); | |
74 | - | |
70 | + checkEntity(widgetsBundle.getId(), widgetsBundle, Resource.WIDGETS_BUNDLE); | |
75 | 71 | return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); |
76 | 72 | } catch (Exception e) { |
77 | 73 | throw handleException(e); |
... | ... | @@ -93,7 +89,7 @@ public class WidgetsBundleController extends BaseController { |
93 | 89 | } |
94 | 90 | |
95 | 91 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") |
96 | - @RequestMapping(value = "/widgetsBundles", params = { "limit" }, method = RequestMethod.GET) | |
92 | + @RequestMapping(value = "/widgetsBundles", params = {"limit"}, method = RequestMethod.GET) | |
97 | 93 | @ResponseBody |
98 | 94 | public TextPageData<WidgetsBundle> getWidgetsBundles( |
99 | 95 | @RequestParam int limit, | ... | ... |
... | ... | @@ -133,13 +133,20 @@ public class ThingsboardInstallService { |
133 | 133 | databaseEntitiesUpgradeService.upgradeDatabase("2.4.2"); |
134 | 134 | |
135 | 135 | case "2.4.3": |
136 | - log.info("Upgrading ThingsBoard from version 2.4.3 to 2.5 ..."); | |
136 | + log.info("Upgrading ThingsBoard from version 2.4.3 to 2.5.0 ..."); | |
137 | 137 | |
138 | 138 | if (databaseTsUpgradeService != null) { |
139 | 139 | databaseTsUpgradeService.upgradeDatabase("2.4.3"); |
140 | 140 | } |
141 | 141 | databaseEntitiesUpgradeService.upgradeDatabase("2.4.3"); |
142 | 142 | |
143 | + case "2.5.0": | |
144 | + log.info("Upgrading ThingsBoard from version 2.5.0 to 2.5.1 ..."); | |
145 | + if (databaseTsUpgradeService != null) { | |
146 | + databaseTsUpgradeService.upgradeDatabase("2.5.0"); | |
147 | + } | |
148 | + | |
149 | + | |
143 | 150 | log.info("Updating system data..."); |
144 | 151 | |
145 | 152 | systemDataLoaderService.deleteSystemWidgetBundle("charts"); | ... | ... |
... | ... | @@ -34,6 +34,9 @@ public abstract class AbstractSqlTsDatabaseUpgradeService { |
34 | 34 | protected static final String CALL_REGEX = "call "; |
35 | 35 | protected static final String DROP_TABLE = "DROP TABLE "; |
36 | 36 | protected static final String DROP_PROCEDURE_IF_EXISTS = "DROP PROCEDURE IF EXISTS "; |
37 | + protected static final String TS_KV_SQL = "ts_kv.sql"; | |
38 | + protected static final String PATH_TO_USERS_PUBLIC_FOLDER = "C:\\Users\\Public"; | |
39 | + protected static final String THINGSBOARD_WINDOWS_UPGRADE_DIR = "THINGSBOARD_WINDOWS_UPGRADE_DIR"; | |
37 | 40 | |
38 | 41 | @Value("${spring.datasource.url}") |
39 | 42 | protected String dbUrl; | ... | ... |
... | ... | @@ -48,6 +48,8 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase |
48 | 48 | } |
49 | 49 | log.info("Schema updated."); |
50 | 50 | break; |
51 | + case "2.5.0": | |
52 | + break; | |
51 | 53 | default: |
52 | 54 | throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); |
53 | 55 | } | ... | ... |
application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java
... | ... | @@ -131,6 +131,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { |
131 | 131 | node.put("username", ""); |
132 | 132 | node.put("password", ""); |
133 | 133 | node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself) |
134 | + node.put("enableProxy", false); | |
134 | 135 | mailSettings.setJsonValue(node); |
135 | 136 | adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings); |
136 | 137 | } | ... | ... |
... | ... | @@ -37,8 +37,6 @@ public class PsqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaServic |
37 | 37 | @Override |
38 | 38 | public void createDatabaseSchema() throws Exception { |
39 | 39 | super.createDatabaseSchema(); |
40 | - if (partitionType.equals("INDEFINITE")) { | |
41 | - executeQuery("CREATE TABLE ts_kv_indefinite PARTITION OF ts_kv DEFAULT;"); | |
42 | - } | |
40 | + executeQuery("CREATE TABLE IF NOT EXISTS ts_kv_indefinite PARTITION OF ts_kv DEFAULT;"); | |
43 | 41 | } |
44 | 42 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -16,12 +16,17 @@ |
16 | 16 | package org.thingsboard.server.service.install; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.apache.commons.lang3.StringUtils; | |
20 | +import org.apache.commons.lang3.SystemUtils; | |
19 | 21 | import org.springframework.beans.factory.annotation.Value; |
20 | 22 | import org.springframework.context.annotation.Profile; |
21 | 23 | import org.springframework.stereotype.Service; |
22 | 24 | import org.thingsboard.server.dao.util.PsqlDao; |
23 | 25 | import org.thingsboard.server.dao.util.SqlTsDao; |
24 | 26 | |
27 | +import java.io.File; | |
28 | +import java.io.IOException; | |
29 | +import java.nio.file.Files; | |
25 | 30 | import java.nio.file.Path; |
26 | 31 | import java.nio.file.Paths; |
27 | 32 | import java.sql.Connection; |
... | ... | @@ -37,6 +42,7 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
37 | 42 | @Value("${sql.postgres.ts_key_value_partitioning:MONTHS}") |
38 | 43 | private String partitionType; |
39 | 44 | |
45 | + private static final String TS_KV_LATEST_SQL = "ts_kv_latest.sql"; | |
40 | 46 | private static final String LOAD_FUNCTIONS_SQL = "schema_update_psql_ts.sql"; |
41 | 47 | private static final String LOAD_TTL_FUNCTIONS_SQL = "schema_update_ttl.sql"; |
42 | 48 | private static final String LOAD_DROP_PARTITIONS_FUNCTIONS_SQL = "schema_update_psql_drop_partitions.sql"; |
... | ... | @@ -49,15 +55,17 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
49 | 55 | private static final String CREATE_PARTITIONS = "create_partitions(IN partition_type varchar)"; |
50 | 56 | private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()"; |
51 | 57 | private static final String INSERT_INTO_DICTIONARY = "insert_into_dictionary()"; |
52 | - private static final String INSERT_INTO_TS_KV = "insert_into_ts_kv()"; | |
53 | - private static final String INSERT_INTO_TS_KV_LATEST = "insert_into_ts_kv_latest()"; | |
58 | + private static final String INSERT_INTO_TS_KV = "insert_into_ts_kv(IN path_to_file varchar)"; | |
59 | + private static final String INSERT_INTO_TS_KV_LATEST = "insert_into_ts_kv_latest(IN path_to_file varchar)"; | |
60 | + private static final String INSERT_INTO_TS_KV_CURSOR = "insert_into_ts_kv_cursor()"; | |
61 | + private static final String INSERT_INTO_TS_KV_LATEST_CURSOR = "insert_into_ts_kv_latest_cursor()"; | |
54 | 62 | |
55 | 63 | private static final String CALL_CREATE_PARTITION_TS_KV_TABLE = CALL_REGEX + CREATE_PARTITION_TS_KV_TABLE; |
56 | 64 | private static final String CALL_CREATE_NEW_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_LATEST_TABLE; |
57 | 65 | private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE; |
58 | 66 | private static final String CALL_INSERT_INTO_DICTIONARY = CALL_REGEX + INSERT_INTO_DICTIONARY; |
59 | - private static final String CALL_INSERT_INTO_TS_KV = CALL_REGEX + INSERT_INTO_TS_KV; | |
60 | - private static final String CALL_INSERT_INTO_TS_KV_LATEST = CALL_REGEX + INSERT_INTO_TS_KV_LATEST; | |
67 | + private static final String CALL_INSERT_INTO_TS_KV_CURSOR = CALL_REGEX + INSERT_INTO_TS_KV_CURSOR; | |
68 | + private static final String CALL_INSERT_INTO_TS_KV_LATEST_CURSOR = CALL_REGEX + INSERT_INTO_TS_KV_LATEST_CURSOR; | |
61 | 69 | |
62 | 70 | private static final String DROP_TABLE_TS_KV_OLD = DROP_TABLE + TS_KV_OLD; |
63 | 71 | private static final String DROP_TABLE_TS_KV_LATEST_OLD = DROP_TABLE + TS_KV_LATEST_OLD; |
... | ... | @@ -69,6 +77,8 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
69 | 77 | private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY; |
70 | 78 | private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV; |
71 | 79 | private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; |
80 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_CURSOR = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_CURSOR; | |
81 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST_CURSOR = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST_CURSOR; | |
72 | 82 | private static final String DROP_FUNCTION_GET_PARTITION_DATA = "DROP FUNCTION IF EXISTS get_partitions_data;"; |
73 | 83 | |
74 | 84 | @Override |
... | ... | @@ -89,14 +99,63 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
89 | 99 | executeQuery(conn, CALL_CREATE_PARTITION_TS_KV_TABLE); |
90 | 100 | if (!partitionType.equals("INDEFINITE")) { |
91 | 101 | executeQuery(conn, "call create_partitions('" + partitionType + "')"); |
92 | - } else { | |
93 | - executeQuery(conn, "CREATE TABLE IF NOT EXISTS ts_kv_indefinite PARTITION OF ts_kv DEFAULT;"); | |
94 | 102 | } |
95 | 103 | executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); |
96 | 104 | executeQuery(conn, CALL_INSERT_INTO_DICTIONARY); |
97 | - executeQuery(conn, CALL_INSERT_INTO_TS_KV); | |
98 | - executeQuery(conn, CALL_CREATE_NEW_TS_KV_LATEST_TABLE); | |
99 | - executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST); | |
105 | + | |
106 | + Path pathToTempTsKvFile = null; | |
107 | + Path pathToTempTsKvLatestFile = null; | |
108 | + if (SystemUtils.IS_OS_WINDOWS) { | |
109 | + log.info("Lookup for environment variable: {} ...", THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
110 | + Path pathToDir; | |
111 | + String thingsboardWindowsUpgradeDir = System.getenv("THINGSBOARD_WINDOWS_UPGRADE_DIR"); | |
112 | + if (StringUtils.isNotEmpty(thingsboardWindowsUpgradeDir)) { | |
113 | + log.info("Environment variable: {} was found!", THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
114 | + pathToDir = Paths.get(thingsboardWindowsUpgradeDir); | |
115 | + } else { | |
116 | + log.info("Failed to lookup environment variable: {}", THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
117 | + pathToDir = Paths.get(PATH_TO_USERS_PUBLIC_FOLDER); | |
118 | + } | |
119 | + log.info("Directory: {} will be used for creation temporary upgrade files!", pathToDir); | |
120 | + try { | |
121 | + Path tsKvFile = Files.createTempFile(pathToDir, "ts_kv", ".sql"); | |
122 | + Path tsKvLatestFile = Files.createTempFile(pathToDir, "ts_kv_latest", ".sql"); | |
123 | + pathToTempTsKvFile = tsKvFile.toAbsolutePath(); | |
124 | + pathToTempTsKvLatestFile = tsKvLatestFile.toAbsolutePath(); | |
125 | + try { | |
126 | + copyTimeseries(conn, pathToTempTsKvFile, pathToTempTsKvLatestFile); | |
127 | + } catch (Exception e) { | |
128 | + insertTimeseries(conn); | |
129 | + } | |
130 | + } catch (IOException | SecurityException e) { | |
131 | + log.warn("Failed to create time-series upgrade files due to: {}", e.getMessage()); | |
132 | + insertTimeseries(conn); | |
133 | + } | |
134 | + } else { | |
135 | + try { | |
136 | + Path tempDirPath = Files.createTempDirectory("ts_kv"); | |
137 | + File tempDirAsFile = tempDirPath.toFile(); | |
138 | + boolean writable = tempDirAsFile.setWritable(true, false); | |
139 | + boolean readable = tempDirAsFile.setReadable(true, false); | |
140 | + boolean executable = tempDirAsFile.setExecutable(true, false); | |
141 | + pathToTempTsKvFile = tempDirPath.resolve(TS_KV_SQL).toAbsolutePath(); | |
142 | + pathToTempTsKvLatestFile = tempDirPath.resolve(TS_KV_LATEST_SQL).toAbsolutePath(); | |
143 | + try { | |
144 | + if (writable && readable && executable) { | |
145 | + copyTimeseries(conn, pathToTempTsKvFile, pathToTempTsKvLatestFile); | |
146 | + } else { | |
147 | + throw new RuntimeException("Failed to grant write permissions for the: " + tempDirPath + "folder!"); | |
148 | + } | |
149 | + } catch (Exception e) { | |
150 | + insertTimeseries(conn); | |
151 | + } | |
152 | + } catch (IOException | SecurityException e) { | |
153 | + log.warn("Failed to create time-series upgrade files due to: {}", e.getMessage()); | |
154 | + insertTimeseries(conn); | |
155 | + } | |
156 | + } | |
157 | + | |
158 | + removeUpgradeFiles(pathToTempTsKvFile, pathToTempTsKvLatestFile); | |
100 | 159 | |
101 | 160 | executeQuery(conn, DROP_TABLE_TS_KV_OLD); |
102 | 161 | executeQuery(conn, DROP_TABLE_TS_KV_LATEST_OLD); |
... | ... | @@ -108,6 +167,8 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
108 | 167 | executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV); |
109 | 168 | executeQuery(conn, DROP_PROCEDURE_CREATE_NEW_TS_KV_LATEST_TABLE); |
110 | 169 | executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST); |
170 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_CURSOR); | |
171 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST_CURSOR); | |
111 | 172 | executeQuery(conn, DROP_FUNCTION_GET_PARTITION_DATA); |
112 | 173 | |
113 | 174 | executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN IF NOT EXISTS json_v json;"); |
... | ... | @@ -128,11 +189,46 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe |
128 | 189 | } |
129 | 190 | } |
130 | 191 | break; |
192 | + case "2.5.0": | |
193 | + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | |
194 | + executeQuery(conn, "CREATE TABLE IF NOT EXISTS ts_kv_indefinite PARTITION OF ts_kv DEFAULT;"); | |
195 | + executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); | |
196 | + } | |
197 | + break; | |
131 | 198 | default: |
132 | 199 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); |
133 | 200 | } |
134 | 201 | } |
135 | 202 | |
203 | + private void removeUpgradeFiles(Path pathToTempTsKvFile, Path pathToTempTsKvLatestFile) { | |
204 | + if (pathToTempTsKvFile != null && pathToTempTsKvFile.toFile().exists()) { | |
205 | + boolean deleteTsKvFile = pathToTempTsKvFile.toFile().delete(); | |
206 | + if (deleteTsKvFile) { | |
207 | + log.info("Successfully deleted the temp file for ts_kv table upgrade!"); | |
208 | + } | |
209 | + } | |
210 | + if (pathToTempTsKvLatestFile != null && pathToTempTsKvLatestFile.toFile().exists()) { | |
211 | + boolean deleteTsKvLatestFile = pathToTempTsKvLatestFile.toFile().delete(); | |
212 | + if (deleteTsKvLatestFile) { | |
213 | + log.info("Successfully deleted the temp file for ts_kv_latest table upgrade!"); | |
214 | + } | |
215 | + } | |
216 | + } | |
217 | + | |
218 | + private void copyTimeseries(Connection conn, Path pathToTempTsKvFile, Path pathToTempTsKvLatestFile) { | |
219 | + executeQuery(conn, "call insert_into_ts_kv('" + pathToTempTsKvFile + "')"); | |
220 | + executeQuery(conn, CALL_CREATE_NEW_TS_KV_LATEST_TABLE); | |
221 | + executeQuery(conn, "call insert_into_ts_kv_latest('" + pathToTempTsKvLatestFile + "')"); | |
222 | + } | |
223 | + | |
224 | + private void insertTimeseries(Connection conn) { | |
225 | + log.warn("Upgrade script failed using the copy to/from files strategy!" + | |
226 | + " Trying to perfrom the upgrade using Inserts strategy ..."); | |
227 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV_CURSOR); | |
228 | + executeQuery(conn, CALL_CREATE_NEW_TS_KV_LATEST_TABLE); | |
229 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST_CURSOR); | |
230 | + } | |
231 | + | |
136 | 232 | @Override |
137 | 233 | protected void loadSql(Connection conn, String fileName) { |
138 | 234 | Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); | ... | ... |
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | package org.thingsboard.server.service.install; |
17 | 17 | |
18 | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.apache.commons.lang3.StringUtils; | |
20 | +import org.apache.commons.lang3.SystemUtils; | |
19 | 21 | import org.springframework.beans.factory.annotation.Autowired; |
20 | 22 | import org.springframework.beans.factory.annotation.Value; |
21 | 23 | import org.springframework.context.annotation.Profile; |
... | ... | @@ -23,6 +25,9 @@ import org.springframework.stereotype.Service; |
23 | 25 | import org.thingsboard.server.dao.util.PsqlDao; |
24 | 26 | import org.thingsboard.server.dao.util.TimescaleDBTsDao; |
25 | 27 | |
28 | +import java.io.File; | |
29 | +import java.io.IOException; | |
30 | +import java.nio.file.Files; | |
26 | 31 | import java.nio.file.Path; |
27 | 32 | import java.nio.file.Paths; |
28 | 33 | import java.sql.Connection; |
... | ... | @@ -47,15 +52,16 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
47 | 52 | private static final String CREATE_NEW_TS_KV_TABLE = "create_new_ts_kv_table()"; |
48 | 53 | private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()"; |
49 | 54 | private static final String INSERT_INTO_DICTIONARY = "insert_into_dictionary()"; |
50 | - private static final String INSERT_INTO_TS_KV = "insert_into_ts_kv()"; | |
55 | + private static final String INSERT_INTO_TS_KV = "insert_into_ts_kv(IN path_to_file varchar)"; | |
56 | + private static final String INSERT_INTO_TS_KV_CURSOR = "insert_into_ts_kv_cursor()"; | |
51 | 57 | private static final String INSERT_INTO_TS_KV_LATEST = "insert_into_ts_kv_latest()"; |
52 | 58 | |
53 | 59 | private static final String CALL_CREATE_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_TS_KV_LATEST_TABLE; |
54 | 60 | private static final String CALL_CREATE_NEW_TENANT_TS_KV_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_TABLE; |
55 | 61 | private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE; |
56 | 62 | private static final String CALL_INSERT_INTO_DICTIONARY = CALL_REGEX + INSERT_INTO_DICTIONARY; |
57 | - private static final String CALL_INSERT_INTO_TS_KV = CALL_REGEX + INSERT_INTO_TS_KV; | |
58 | 63 | private static final String CALL_INSERT_INTO_TS_KV_LATEST = CALL_REGEX + INSERT_INTO_TS_KV_LATEST; |
64 | + private static final String CALL_INSERT_INTO_TS_KV_CURSOR = CALL_REGEX + INSERT_INTO_TS_KV_CURSOR; | |
59 | 65 | |
60 | 66 | private static final String DROP_OLD_TENANT_TS_KV_TABLE = DROP_TABLE + TENANT_TS_KV_OLD_TABLE; |
61 | 67 | |
... | ... | @@ -63,7 +69,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
63 | 69 | private static final String DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY = DROP_PROCEDURE_IF_EXISTS + CREATE_NEW_TS_KV_TABLE; |
64 | 70 | private static final String DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE; |
65 | 71 | private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY; |
66 | - private static final String DROP_PROCEDURE_INSERT_INTO_TENANT_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV; | |
72 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV; | |
73 | + private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_CURSOR = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_CURSOR; | |
67 | 74 | private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; |
68 | 75 | |
69 | 76 | @Autowired |
... | ... | @@ -91,7 +98,56 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
91 | 98 | |
92 | 99 | executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); |
93 | 100 | executeQuery(conn, CALL_INSERT_INTO_DICTIONARY); |
94 | - executeQuery(conn, CALL_INSERT_INTO_TS_KV); | |
101 | + | |
102 | + Path pathToTempTsKvFile = null; | |
103 | + if (SystemUtils.IS_OS_WINDOWS) { | |
104 | + Path pathToDir; | |
105 | + log.info("Lookup for environment variable: {} ...", THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
106 | + String thingsboardWindowsUpgradeDir = System.getenv(THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
107 | + if (StringUtils.isNotEmpty(thingsboardWindowsUpgradeDir)) { | |
108 | + log.info("Environment variable: {} was found!", THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
109 | + pathToDir = Paths.get(thingsboardWindowsUpgradeDir); | |
110 | + } else { | |
111 | + log.info("Failed to lookup environment variable: {}", THINGSBOARD_WINDOWS_UPGRADE_DIR); | |
112 | + pathToDir = Paths.get(PATH_TO_USERS_PUBLIC_FOLDER); | |
113 | + } | |
114 | + log.info("Directory: {} will be used for creation temporary upgrade file!", pathToDir); | |
115 | + try { | |
116 | + Path tsKvFile = Files.createTempFile(pathToDir, "ts_kv", ".sql"); | |
117 | + pathToTempTsKvFile = tsKvFile.toAbsolutePath(); | |
118 | + try { | |
119 | + executeQuery(conn, "call insert_into_ts_kv('" + pathToTempTsKvFile + "')"); | |
120 | + } catch (Exception e) { | |
121 | + insertTimeseries(conn); | |
122 | + } | |
123 | + } catch (IOException | SecurityException e) { | |
124 | + log.warn("Failed to create time-series upgrade files due to: {}", e.getMessage()); | |
125 | + insertTimeseries(conn); | |
126 | + } | |
127 | + } else { | |
128 | + try { | |
129 | + Path tempDirPath = Files.createTempDirectory("ts_kv"); | |
130 | + File tempDirAsFile = tempDirPath.toFile(); | |
131 | + boolean writable = tempDirAsFile.setWritable(true, false); | |
132 | + boolean readable = tempDirAsFile.setReadable(true, false); | |
133 | + boolean executable = tempDirAsFile.setExecutable(true, false); | |
134 | + pathToTempTsKvFile = tempDirPath.resolve(TS_KV_SQL).toAbsolutePath(); | |
135 | + try { | |
136 | + if (writable && readable && executable) { | |
137 | + executeQuery(conn, "call insert_into_ts_kv('" + pathToTempTsKvFile + "')"); | |
138 | + } else { | |
139 | + throw new RuntimeException("Failed to grant write permissions for the: " + tempDirPath + "folder!"); | |
140 | + } | |
141 | + } catch (Exception e) { | |
142 | + insertTimeseries(conn); | |
143 | + } | |
144 | + } catch (IOException | SecurityException e) { | |
145 | + log.warn("Failed to create time-series upgrade files due to: {}", e.getMessage()); | |
146 | + insertTimeseries(conn); | |
147 | + } | |
148 | + } | |
149 | + removeUpgradeFile(pathToTempTsKvFile); | |
150 | + | |
95 | 151 | executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST); |
96 | 152 | |
97 | 153 | executeQuery(conn, DROP_OLD_TENANT_TS_KV_TABLE); |
... | ... | @@ -100,7 +156,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
100 | 156 | executeQuery(conn, DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY); |
101 | 157 | executeQuery(conn, DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE); |
102 | 158 | executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_DICTIONARY); |
103 | - executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TENANT_TS_KV); | |
159 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV); | |
160 | + executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_CURSOR); | |
104 | 161 | executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST); |
105 | 162 | |
106 | 163 | executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN IF NOT EXISTS json_v json;"); |
... | ... | @@ -115,11 +172,31 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr |
115 | 172 | } |
116 | 173 | } |
117 | 174 | break; |
175 | + case "2.5.0": | |
176 | + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | |
177 | + executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); | |
178 | + } | |
179 | + break; | |
118 | 180 | default: |
119 | 181 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); |
120 | 182 | } |
121 | 183 | } |
122 | 184 | |
185 | + private void insertTimeseries(Connection conn) { | |
186 | + log.warn("Upgrade script failed using the copy to/from files strategy!" + | |
187 | + " Trying to perfrom the upgrade using Inserts strategy ..."); | |
188 | + executeQuery(conn, CALL_INSERT_INTO_TS_KV_CURSOR); | |
189 | + } | |
190 | + | |
191 | + private void removeUpgradeFile(Path pathToTempTsKvFile) { | |
192 | + if (pathToTempTsKvFile != null && pathToTempTsKvFile.toFile().exists()) { | |
193 | + boolean deleteTsKvFile = pathToTempTsKvFile.toFile().delete(); | |
194 | + if (deleteTsKvFile) { | |
195 | + log.info("Successfully deleted the temp file for ts_kv table upgrade!"); | |
196 | + } | |
197 | + } | |
198 | + } | |
199 | + | |
123 | 200 | @Override |
124 | 201 | protected void loadSql(Connection conn, String fileName) { |
125 | 202 | Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); | ... | ... |
... | ... | @@ -115,6 +115,21 @@ public class DefaultMailService implements MailService { |
115 | 115 | if (enableTls && jsonConfig.has("tlsVersion") && StringUtils.isNoneEmpty(jsonConfig.get("tlsVersion").asText())) { |
116 | 116 | javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", jsonConfig.get("tlsVersion").asText()); |
117 | 117 | } |
118 | + | |
119 | + boolean enableProxy = jsonConfig.has("enableProxy") && jsonConfig.get("enableProxy").asBoolean(); | |
120 | + | |
121 | + if (enableProxy) { | |
122 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.host", jsonConfig.get("proxyHost").asText()); | |
123 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.port", jsonConfig.get("proxyPort").asText()); | |
124 | + String proxyUser = jsonConfig.get("proxyUser").asText(); | |
125 | + if (StringUtils.isNoneEmpty(proxyUser)) { | |
126 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.user", proxyUser); | |
127 | + } | |
128 | + String proxyPassword = jsonConfig.get("proxyPassword").asText(); | |
129 | + if (StringUtils.isNoneEmpty(proxyPassword)) { | |
130 | + javaMailProperties.put(MAIL_PROP + protocol + ".proxy.password", proxyPassword); | |
131 | + } | |
132 | + } | |
118 | 133 | return javaMailProperties; |
119 | 134 | } |
120 | 135 | ... | ... |
... | ... | @@ -46,6 +46,9 @@ import java.util.concurrent.atomic.AtomicInteger; |
46 | 46 | @Service |
47 | 47 | public class RemoteJsInvokeService extends AbstractJsInvokeService { |
48 | 48 | |
49 | + @Value("${queue.js.max_eval_requests_timeout}") | |
50 | + private long maxEvalRequestsTimeout; | |
51 | + | |
49 | 52 | @Value("${queue.js.max_requests_timeout}") |
50 | 53 | private long maxRequestsTimeout; |
51 | 54 | |
... | ... | @@ -59,22 +62,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
59 | 62 | @Value("${js.remote.stats.enabled:false}") |
60 | 63 | private boolean statsEnabled; |
61 | 64 | |
62 | - private final AtomicInteger kafkaPushedMsgs = new AtomicInteger(0); | |
63 | - private final AtomicInteger kafkaInvokeMsgs = new AtomicInteger(0); | |
64 | - private final AtomicInteger kafkaEvalMsgs = new AtomicInteger(0); | |
65 | - private final AtomicInteger kafkaFailedMsgs = new AtomicInteger(0); | |
66 | - private final AtomicInteger kafkaTimeoutMsgs = new AtomicInteger(0); | |
65 | + private final AtomicInteger queuePushedMsgs = new AtomicInteger(0); | |
66 | + private final AtomicInteger queueInvokeMsgs = new AtomicInteger(0); | |
67 | + private final AtomicInteger queueEvalMsgs = new AtomicInteger(0); | |
68 | + private final AtomicInteger queueFailedMsgs = new AtomicInteger(0); | |
69 | + private final AtomicInteger queueTimeoutMsgs = new AtomicInteger(0); | |
67 | 70 | |
68 | 71 | @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms}") |
69 | 72 | public void printStats() { |
70 | 73 | if (statsEnabled) { |
71 | - int pushedMsgs = kafkaPushedMsgs.getAndSet(0); | |
72 | - int invokeMsgs = kafkaInvokeMsgs.getAndSet(0); | |
73 | - int evalMsgs = kafkaEvalMsgs.getAndSet(0); | |
74 | - int failed = kafkaFailedMsgs.getAndSet(0); | |
75 | - int timedOut = kafkaTimeoutMsgs.getAndSet(0); | |
74 | + int pushedMsgs = queuePushedMsgs.getAndSet(0); | |
75 | + int invokeMsgs = queueInvokeMsgs.getAndSet(0); | |
76 | + int evalMsgs = queueEvalMsgs.getAndSet(0); | |
77 | + int failed = queueFailedMsgs.getAndSet(0); | |
78 | + int timedOut = queueTimeoutMsgs.getAndSet(0); | |
76 | 79 | if (pushedMsgs > 0 || invokeMsgs > 0 || evalMsgs > 0 || failed > 0 || timedOut > 0) { |
77 | - log.info("Kafka JS Invoke Stats: pushed [{}] received [{}] invoke [{}] eval [{}] failed [{}] timedOut [{}]", | |
80 | + log.info("Queue JS Invoke Stats: pushed [{}] received [{}] invoke [{}] eval [{}] failed [{}] timedOut [{}]", | |
78 | 81 | pushedMsgs, invokeMsgs + evalMsgs, invokeMsgs, evalMsgs, failed, timedOut); |
79 | 82 | } |
80 | 83 | } |
... | ... | @@ -113,22 +116,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
113 | 116 | |
114 | 117 | log.trace("Post compile request for scriptId [{}]", scriptId); |
115 | 118 | ListenableFuture<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); |
116 | - if (maxRequestsTimeout > 0) { | |
117 | - future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); | |
119 | + if (maxEvalRequestsTimeout > 0) { | |
120 | + future = Futures.withTimeout(future, maxEvalRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); | |
118 | 121 | } |
119 | - kafkaPushedMsgs.incrementAndGet(); | |
122 | + queuePushedMsgs.incrementAndGet(); | |
120 | 123 | Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() { |
121 | 124 | @Override |
122 | 125 | public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) { |
123 | - kafkaEvalMsgs.incrementAndGet(); | |
126 | + queueEvalMsgs.incrementAndGet(); | |
124 | 127 | } |
125 | 128 | |
126 | 129 | @Override |
127 | 130 | public void onFailure(Throwable t) { |
128 | 131 | if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { |
129 | - kafkaTimeoutMsgs.incrementAndGet(); | |
132 | + queueTimeoutMsgs.incrementAndGet(); | |
130 | 133 | } |
131 | - kafkaFailedMsgs.incrementAndGet(); | |
134 | + queueFailedMsgs.incrementAndGet(); | |
132 | 135 | } |
133 | 136 | }, MoreExecutors.directExecutor()); |
134 | 137 | return Futures.transform(future, response -> { |
... | ... | @@ -170,20 +173,20 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { |
170 | 173 | if (maxRequestsTimeout > 0) { |
171 | 174 | future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); |
172 | 175 | } |
173 | - kafkaPushedMsgs.incrementAndGet(); | |
176 | + queuePushedMsgs.incrementAndGet(); | |
174 | 177 | Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() { |
175 | 178 | @Override |
176 | 179 | public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) { |
177 | - kafkaInvokeMsgs.incrementAndGet(); | |
180 | + queueInvokeMsgs.incrementAndGet(); | |
178 | 181 | } |
179 | 182 | |
180 | 183 | @Override |
181 | 184 | public void onFailure(Throwable t) { |
182 | 185 | onScriptExecutionError(scriptId); |
183 | 186 | if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { |
184 | - kafkaTimeoutMsgs.incrementAndGet(); | |
187 | + queueTimeoutMsgs.incrementAndGet(); | |
185 | 188 | } |
186 | - kafkaFailedMsgs.incrementAndGet(); | |
189 | + queueFailedMsgs.incrementAndGet(); | |
187 | 190 | } |
188 | 191 | }, MoreExecutors.directExecutor()); |
189 | 192 | return Futures.transform(future, response -> { | ... | ... |
... | ... | @@ -15,6 +15,9 @@ |
15 | 15 | */ |
16 | 16 | package org.thingsboard.server.service.security.auth.oauth2; |
17 | 17 | |
18 | +import com.fasterxml.jackson.databind.ObjectMapper; | |
19 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
20 | +import com.google.common.base.Strings; | |
18 | 21 | import lombok.extern.slf4j.Slf4j; |
19 | 22 | import org.springframework.beans.factory.annotation.Autowired; |
20 | 23 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
... | ... | @@ -22,14 +25,21 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; |
22 | 25 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
23 | 26 | import org.springframework.util.StringUtils; |
24 | 27 | import org.thingsboard.server.common.data.Customer; |
28 | +import org.thingsboard.server.common.data.DashboardInfo; | |
25 | 29 | import org.thingsboard.server.common.data.Tenant; |
26 | 30 | import org.thingsboard.server.common.data.User; |
27 | 31 | import org.thingsboard.server.common.data.id.CustomerId; |
32 | +import org.thingsboard.server.common.data.id.DashboardId; | |
33 | +import org.thingsboard.server.common.data.id.IdBased; | |
28 | 34 | import org.thingsboard.server.common.data.id.TenantId; |
35 | +import org.thingsboard.server.common.data.page.TextPageData; | |
29 | 36 | import org.thingsboard.server.common.data.page.TextPageLink; |
37 | +import org.thingsboard.server.common.data.page.TimePageData; | |
38 | +import org.thingsboard.server.common.data.page.TimePageLink; | |
30 | 39 | import org.thingsboard.server.common.data.security.Authority; |
31 | 40 | import org.thingsboard.server.common.data.security.UserCredentials; |
32 | 41 | import org.thingsboard.server.dao.customer.CustomerService; |
42 | +import org.thingsboard.server.dao.dashboard.DashboardService; | |
33 | 43 | import org.thingsboard.server.dao.oauth2.OAuth2User; |
34 | 44 | import org.thingsboard.server.dao.tenant.TenantService; |
35 | 45 | import org.thingsboard.server.dao.user.UserService; |
... | ... | @@ -40,11 +50,15 @@ import org.thingsboard.server.service.security.model.UserPrincipal; |
40 | 50 | import java.io.IOException; |
41 | 51 | import java.util.List; |
42 | 52 | import java.util.Optional; |
53 | +import java.util.concurrent.ExecutionException; | |
43 | 54 | import java.util.concurrent.locks.Lock; |
44 | 55 | import java.util.concurrent.locks.ReentrantLock; |
45 | 56 | |
46 | 57 | @Slf4j |
47 | 58 | public abstract class AbstractOAuth2ClientMapper { |
59 | + private static final int DASHBOARDS_REQUEST_LIMIT = 10; | |
60 | + | |
61 | + private static final ObjectMapper objectMapper = new ObjectMapper(); | |
48 | 62 | |
49 | 63 | @Autowired |
50 | 64 | private UserService userService; |
... | ... | @@ -59,6 +73,9 @@ public abstract class AbstractOAuth2ClientMapper { |
59 | 73 | private CustomerService customerService; |
60 | 74 | |
61 | 75 | @Autowired |
76 | + private DashboardService dashboardService; | |
77 | + | |
78 | + @Autowired | |
62 | 79 | private InstallScripts installScripts; |
63 | 80 | |
64 | 81 | private final Lock userCreationLock = new ReentrantLock(); |
... | ... | @@ -92,6 +109,20 @@ public abstract class AbstractOAuth2ClientMapper { |
92 | 109 | user.setEmail(oauth2User.getEmail()); |
93 | 110 | user.setFirstName(oauth2User.getFirstName()); |
94 | 111 | user.setLastName(oauth2User.getLastName()); |
112 | + | |
113 | + if (!StringUtils.isEmpty(oauth2User.getDefaultDashboardName())) { | |
114 | + Optional<DashboardId> dashboardIdOpt = | |
115 | + user.getAuthority() == Authority.TENANT_ADMIN ? | |
116 | + getDashboardId(tenantId, oauth2User.getDefaultDashboardName()) | |
117 | + : getDashboardId(tenantId, customerId, oauth2User.getDefaultDashboardName()); | |
118 | + if (dashboardIdOpt.isPresent()) { | |
119 | + ObjectNode additionalInfo = objectMapper.createObjectNode(); | |
120 | + additionalInfo.put("defaultDashboardFullscreen", oauth2User.isAlwaysFullScreen()); | |
121 | + additionalInfo.put("defaultDashboardId", dashboardIdOpt.get().getId().toString()); | |
122 | + user.setAdditionalInfo(additionalInfo); | |
123 | + } | |
124 | + } | |
125 | + | |
95 | 126 | user = userService.saveUser(user); |
96 | 127 | if (activateUser) { |
97 | 128 | UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); |
... | ... | @@ -143,4 +174,32 @@ public abstract class AbstractOAuth2ClientMapper { |
143 | 174 | return customerService.saveCustomer(customer).getId(); |
144 | 175 | } |
145 | 176 | } |
177 | + | |
178 | + private Optional<DashboardId> getDashboardId(TenantId tenantId, String dashboardName) { | |
179 | + TextPageLink searchTextLink = new TextPageLink(1, dashboardName); | |
180 | + TextPageData<DashboardInfo> dashboardsPage = dashboardService.findDashboardsByTenantId(tenantId, searchTextLink); | |
181 | + return dashboardsPage.getData().stream() | |
182 | + .findAny() | |
183 | + .map(IdBased::getId); | |
184 | + } | |
185 | + | |
186 | + private Optional<DashboardId> getDashboardId(TenantId tenantId, CustomerId customerId, String dashboardName) { | |
187 | + TimePageData<DashboardInfo> dashboardsPage = null; | |
188 | + do { | |
189 | + TimePageLink timePageLink = dashboardsPage != null ? | |
190 | + dashboardsPage.getNextPageLink() : new TimePageLink(DASHBOARDS_REQUEST_LIMIT); | |
191 | + try { | |
192 | + dashboardsPage = dashboardService.findDashboardsByTenantIdAndCustomerId(tenantId, customerId, timePageLink).get(); | |
193 | + } catch (InterruptedException | ExecutionException e) { | |
194 | + throw new RuntimeException("Failed to get customer's dashboards.", e); | |
195 | + } | |
196 | + Optional<DashboardInfo> dashboardInfoOpt = dashboardsPage.getData().stream() | |
197 | + .filter(dashboardInfo -> dashboardName.equals(dashboardInfo.getName())) | |
198 | + .findAny(); | |
199 | + if (dashboardInfoOpt.isPresent()) { | |
200 | + return dashboardInfoOpt.map(DashboardInfo::getId); | |
201 | + } | |
202 | + } while (dashboardsPage.hasNext()); | |
203 | + return Optional.empty(); | |
204 | + } | |
146 | 205 | } | ... | ... |
... | ... | @@ -56,6 +56,10 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen |
56 | 56 | String customerName = sub.replace(config.getBasic().getCustomerNamePattern()); |
57 | 57 | oauth2User.setCustomerName(customerName); |
58 | 58 | } |
59 | + oauth2User.setAlwaysFullScreen(config.getBasic().isAlwaysFullScreen()); | |
60 | + if (!StringUtils.isEmpty(config.getBasic().getDefaultDashboardName())) { | |
61 | + oauth2User.setDefaultDashboardName(config.getBasic().getDefaultDashboardName()); | |
62 | + } | |
59 | 63 | |
60 | 64 | return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser()); |
61 | 65 | } | ... | ... |
... | ... | @@ -56,8 +56,8 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme |
56 | 56 | try { |
57 | 57 | return restTemplate.postForEntity(custom.getUrl(), request, OAuth2User.class).getBody(); |
58 | 58 | } catch (Exception e) { |
59 | - log.error("Can't connect to custom mapper endpoint", e); | |
60 | - throw new RuntimeException("Can't connect to custom mapper endpoint", e); | |
59 | + log.error("There was an error during connection to custom mapper endpoint", e); | |
60 | + throw new RuntimeException("Unable to login. Please contact your Administrator!"); | |
61 | 61 | } |
62 | 62 | } |
63 | 63 | } | ... | ... |
... | ... | @@ -32,6 +32,8 @@ import org.thingsboard.server.utils.MiscUtils; |
32 | 32 | import javax.servlet.http.HttpServletRequest; |
33 | 33 | import javax.servlet.http.HttpServletResponse; |
34 | 34 | import java.io.IOException; |
35 | +import java.net.URLEncoder; | |
36 | +import java.nio.charset.StandardCharsets; | |
35 | 37 | |
36 | 38 | @Component(value = "oauth2AuthenticationSuccessHandler") |
37 | 39 | @ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") |
... | ... | @@ -57,16 +59,22 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS |
57 | 59 | public void onAuthenticationSuccess(HttpServletRequest request, |
58 | 60 | HttpServletResponse response, |
59 | 61 | Authentication authentication) throws IOException { |
60 | - OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication; | |
61 | 62 | |
62 | - OAuth2Client oauth2Client = oauth2Configuration.getClientByRegistrationId(token.getAuthorizedClientRegistrationId()); | |
63 | - OAuth2ClientMapper mapper = oauth2ClientMapperProvider.getOAuth2ClientMapperByType(oauth2Client.getMapperConfig().getType()); | |
64 | - SecurityUser securityUser = mapper.getOrCreateUserByClientPrincipal(token, oauth2Client.getMapperConfig()); | |
63 | + String baseUrl = MiscUtils.constructBaseUrl(request); | |
64 | + try { | |
65 | + OAuth2AuthenticationToken token = (OAuth2AuthenticationToken) authentication; | |
65 | 66 | |
66 | - JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); | |
67 | - JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); | |
67 | + OAuth2Client oauth2Client = oauth2Configuration.getClientByRegistrationId(token.getAuthorizedClientRegistrationId()); | |
68 | + OAuth2ClientMapper mapper = oauth2ClientMapperProvider.getOAuth2ClientMapperByType(oauth2Client.getMapperConfig().getType()); | |
69 | + SecurityUser securityUser = mapper.getOrCreateUserByClientPrincipal(token, oauth2Client.getMapperConfig()); | |
68 | 70 | |
69 | - String baseUrl = MiscUtils.constructBaseUrl(request); | |
70 | - getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken()); | |
71 | + JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); | |
72 | + JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); | |
73 | + | |
74 | + getRedirectStrategy().sendRedirect(request, response, baseUrl + "/?accessToken=" + accessToken.getToken() + "&refreshToken=" + refreshToken.getToken()); | |
75 | + } catch (Exception e) { | |
76 | + getRedirectStrategy().sendRedirect(request, response, baseUrl + "/login?loginError=" + | |
77 | + URLEncoder.encode(e.getMessage(), StandardCharsets.UTF_8.toString())); | |
78 | + } | |
71 | 79 | } |
72 | 80 | } |
\ No newline at end of file | ... | ... |
... | ... | @@ -47,4 +47,13 @@ public enum Resource { |
47 | 47 | public Optional<EntityType> getEntityType() { |
48 | 48 | return Optional.ofNullable(entityType); |
49 | 49 | } |
50 | + | |
51 | + public static Resource of(EntityType entityType) { | |
52 | + for (Resource resource : Resource.values()) { | |
53 | + if (resource.getEntityType().get() == entityType) { | |
54 | + return resource; | |
55 | + } | |
56 | + } | |
57 | + throw new IllegalArgumentException("Unknown EntityType: " + entityType.name()); | |
58 | + } | |
50 | 59 | } | ... | ... |
... | ... | @@ -292,28 +292,38 @@ public class DefaultDeviceStateService implements DeviceStateService { |
292 | 292 | } |
293 | 293 | } |
294 | 294 | |
295 | + volatile Set<TopicPartitionInfo> pendingPartitions; | |
296 | + | |
295 | 297 | @Override |
296 | 298 | public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { |
297 | 299 | if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { |
298 | 300 | synchronized (this) { |
301 | + pendingPartitions = partitionChangeEvent.getPartitions(); | |
299 | 302 | if (!clusterUpdatePending) { |
300 | 303 | clusterUpdatePending = true; |
301 | 304 | queueExecutor.submit(() -> { |
302 | 305 | clusterUpdatePending = false; |
303 | - initStateFromDB(partitionChangeEvent.getPartitions()); | |
306 | + initStateFromDB(); | |
304 | 307 | }); |
305 | 308 | } |
306 | 309 | } |
307 | 310 | } |
308 | 311 | } |
309 | 312 | |
310 | - private void initStateFromDB(Set<TopicPartitionInfo> partitions) { | |
313 | + private void initStateFromDB() { | |
311 | 314 | try { |
312 | - Set<TopicPartitionInfo> addedPartitions = new HashSet<>(partitions); | |
315 | + log.info("CURRENT PARTITIONS: {}", partitionedDevices.keySet()); | |
316 | + log.info("NEW PARTITIONS: {}", pendingPartitions); | |
317 | + | |
318 | + Set<TopicPartitionInfo> addedPartitions = new HashSet<>(pendingPartitions); | |
313 | 319 | addedPartitions.removeAll(partitionedDevices.keySet()); |
314 | 320 | |
321 | + log.info("ADDED PARTITIONS: {}", addedPartitions); | |
322 | + | |
315 | 323 | Set<TopicPartitionInfo> removedPartitions = new HashSet<>(partitionedDevices.keySet()); |
316 | - removedPartitions.removeAll(partitions); | |
324 | + removedPartitions.removeAll(pendingPartitions); | |
325 | + | |
326 | + log.info("REMOVED PARTITIONS: {}", removedPartitions); | |
317 | 327 | |
318 | 328 | // We no longer manage current partition of devices; |
319 | 329 | removedPartitions.forEach(partition -> { | ... | ... |
... | ... | @@ -224,7 +224,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer |
224 | 224 | return null; |
225 | 225 | } |
226 | 226 | }, |
227 | - s -> (StringUtils.isEmpty(s.getScope()) || scope.equals(s.getScope().name())), | |
227 | + s -> (TbAttributeSubscriptionScope.ANY_SCOPE.equals(s.getScope()) || scope.equals(s.getScope().name())), | |
228 | 228 | s -> { |
229 | 229 | List<TsKvEntry> subscriptionUpdate = null; |
230 | 230 | for (AttributeKvEntry kv : attributes) { | ... | ... |
... | ... | @@ -345,7 +345,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
345 | 345 | keys.forEach(key -> subState.put(key, 0L)); |
346 | 346 | attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); |
347 | 347 | |
348 | - TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.SERVER_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
348 | + TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.ANY_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
349 | 349 | |
350 | 350 | TbAttributeSubscription sub = TbAttributeSubscription.builder() |
351 | 351 | .serviceId(serviceId) |
... | ... | @@ -442,7 +442,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi |
442 | 442 | Map<String, Long> subState = new HashMap<>(attributesData.size()); |
443 | 443 | attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); |
444 | 444 | |
445 | - TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.SERVER_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
445 | + TbAttributeSubscriptionScope scope = StringUtils.isEmpty(cmd.getScope()) ? TbAttributeSubscriptionScope.ANY_SCOPE : TbAttributeSubscriptionScope.valueOf(cmd.getScope()); | |
446 | 446 | |
447 | 447 | TbAttributeSubscription sub = TbAttributeSubscription.builder() |
448 | 448 | .serviceId(serviceId) | ... | ... |
... | ... | @@ -17,6 +17,7 @@ package org.thingsboard.server.service.transport; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.core.JsonProcessingException; |
19 | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | +import com.fasterxml.jackson.databind.node.ObjectNode; | |
20 | 21 | import com.google.common.util.concurrent.Futures; |
21 | 22 | import com.google.common.util.concurrent.ListenableFuture; |
22 | 23 | import com.google.common.util.concurrent.MoreExecutors; |
... | ... | @@ -24,13 +25,18 @@ import lombok.extern.slf4j.Slf4j; |
24 | 25 | import org.springframework.beans.factory.annotation.Autowired; |
25 | 26 | import org.springframework.stereotype.Service; |
26 | 27 | import org.springframework.util.StringUtils; |
28 | +import org.thingsboard.server.common.data.DataConstants; | |
27 | 29 | import org.thingsboard.server.common.data.Device; |
28 | 30 | import org.thingsboard.server.common.data.Tenant; |
31 | +import org.thingsboard.server.common.data.id.CustomerId; | |
29 | 32 | import org.thingsboard.server.common.data.id.DeviceId; |
30 | 33 | import org.thingsboard.server.common.data.id.TenantId; |
31 | 34 | import org.thingsboard.server.common.data.relation.EntityRelation; |
32 | 35 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
33 | 36 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
37 | +import org.thingsboard.server.common.msg.TbMsg; | |
38 | +import org.thingsboard.server.common.msg.TbMsgDataType; | |
39 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | |
34 | 40 | import org.thingsboard.server.dao.device.DeviceCredentialsService; |
35 | 41 | import org.thingsboard.server.dao.device.DeviceService; |
36 | 42 | import org.thingsboard.server.dao.relation.RelationService; |
... | ... | @@ -48,6 +54,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509Ce |
48 | 54 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
49 | 55 | import org.thingsboard.server.queue.util.TbCoreComponent; |
50 | 56 | import org.thingsboard.server.service.executors.DbCallbackExecutorService; |
57 | +import org.thingsboard.server.service.queue.TbClusterService; | |
51 | 58 | import org.thingsboard.server.service.state.DeviceStateService; |
52 | 59 | |
53 | 60 | import java.util.UUID; |
... | ... | @@ -82,6 +89,9 @@ public class DefaultTransportApiService implements TransportApiService { |
82 | 89 | @Autowired |
83 | 90 | private DbCallbackExecutorService dbCallbackExecutorService; |
84 | 91 | |
92 | + @Autowired | |
93 | + protected TbClusterService tbClusterService; | |
94 | + | |
85 | 95 | private ReentrantLock deviceCreationLock = new ReentrantLock(); |
86 | 96 | |
87 | 97 | @Override |
... | ... | @@ -119,14 +129,27 @@ public class DefaultTransportApiService implements TransportApiService { |
119 | 129 | try { |
120 | 130 | Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), requestMsg.getDeviceName()); |
121 | 131 | if (device == null) { |
132 | + TenantId tenantId = gateway.getTenantId(); | |
122 | 133 | device = new Device(); |
123 | - device.setTenantId(gateway.getTenantId()); | |
134 | + device.setTenantId(tenantId); | |
124 | 135 | device.setName(requestMsg.getDeviceName()); |
125 | 136 | device.setType(requestMsg.getDeviceType()); |
126 | 137 | device.setCustomerId(gateway.getCustomerId()); |
127 | 138 | device = deviceService.saveDevice(device); |
128 | 139 | relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created")); |
129 | 140 | deviceStateService.onDeviceAdded(device); |
141 | + | |
142 | + TbMsgMetaData metaData = new TbMsgMetaData(); | |
143 | + CustomerId customerId = gateway.getCustomerId(); | |
144 | + if (customerId != null && !customerId.isNullUid()) { | |
145 | + metaData.putValue("customerId", customerId.toString()); | |
146 | + } | |
147 | + metaData.putValue("gatewayId", gatewayId.toString()); | |
148 | + | |
149 | + DeviceId deviceId = device.getId(); | |
150 | + ObjectNode entityNode = mapper.valueToTree(device); | |
151 | + TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_CREATED, deviceId, metaData, TbMsgDataType.JSON, mapper.writeValueAsString(entityNode)); | |
152 | + tbClusterService.pushMsgToRuleEngine(tenantId, deviceId, tbMsg, null); | |
130 | 153 | } |
131 | 154 | return TransportApiResponseMsg.newBuilder() |
132 | 155 | .setGetOrCreateDeviceResponseMsg(GetOrCreateDeviceFromGatewayResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build(); | ... | ... |
... | ... | @@ -54,6 +54,13 @@ server: |
54 | 54 | customer: |
55 | 55 | enabled: "${TB_SERVER_REST_LIMITS_CUSTOMER_ENABLED:false}" |
56 | 56 | configuration: "${TB_SERVER_REST_LIMITS_CUSTOMER_CONFIGURATION:50:1,1000:60}" |
57 | + server_side_rpc: | |
58 | + # Minimum value of the server side RPC timeout. May override value provided in the REST API call. | |
59 | + # Since 2.5 migration to queues, the RPC delay depends on the size of the pending messages in the queue, | |
60 | + # so default UI parameter of 500ms may not be sufficient for loaded environments. | |
61 | + min_timeout: "${MIN_SERVER_SIDE_RPC_TIMEOUT:5000}" | |
62 | + # Default value of the server side RPC timeout. | |
63 | + default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}" | |
57 | 64 | |
58 | 65 | # Zookeeper connection parameters. Used for service discovery. |
59 | 66 | zk: |
... | ... | @@ -148,6 +155,10 @@ security: |
148 | 155 | # If this field is not empty, user will be created as a user under defined Customer |
149 | 156 | # %{attribute_key} as placeholder for attribute value of attributes of external user object |
150 | 157 | customerNamePattern: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_CUSTOMER_NAME_PATTERN:}" |
158 | + # If this field is not empty, user will be created with default defined Dashboard | |
159 | + defaultDashboardName: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_DEFAULT_DASHBOARD_NAME:}" | |
160 | + # If this field is set 'true' along with non-empty 'defaultDashboardName', user will start from the defined Dashboard in fullscreen mode | |
161 | + alwaysFullScreen: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_ALWAYS_FULL_SCREEN:false}" | |
151 | 162 | custom: |
152 | 163 | url: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_URL:}" |
153 | 164 | username: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_USERNAME:}" |
... | ... | @@ -676,7 +687,7 @@ queue: |
676 | 687 | topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" |
677 | 688 | poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" |
678 | 689 | partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" |
679 | - pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
690 | + pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:2000}" | |
680 | 691 | stats: |
681 | 692 | enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" |
682 | 693 | print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:60000}" |
... | ... | @@ -688,6 +699,8 @@ queue: |
688 | 699 | # JS Eval max pending requests |
689 | 700 | max_pending_requests: "${REMOTE_JS_MAX_PENDING_REQUESTS:10000}" |
690 | 701 | # JS Eval max request timeout |
702 | + max_eval_requests_timeout: "${REMOTE_JS_MAX_EVAL_REQUEST_TIMEOUT:60000}" | |
703 | + # JS max request timeout | |
691 | 704 | max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" |
692 | 705 | # JS response poll interval |
693 | 706 | response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" |
... | ... | @@ -696,7 +709,7 @@ queue: |
696 | 709 | rule-engine: |
697 | 710 | topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" |
698 | 711 | poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" |
699 | - pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
712 | + pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:2000}" | |
700 | 713 | stats: |
701 | 714 | enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" |
702 | 715 | print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" |
... | ... | @@ -705,7 +718,7 @@ queue: |
705 | 718 | topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" |
706 | 719 | poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" |
707 | 720 | partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" |
708 | - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
721 | + pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:2000}" | |
709 | 722 | submit-strategy: |
710 | 723 | type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL |
711 | 724 | # For BATCH only |
... | ... | @@ -720,7 +733,7 @@ queue: |
720 | 733 | topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" |
721 | 734 | poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" |
722 | 735 | partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" |
723 | - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
736 | + pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:2000}" | |
724 | 737 | submit-strategy: |
725 | 738 | type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL |
726 | 739 | # For BATCH only |
... | ... | @@ -735,7 +748,7 @@ queue: |
735 | 748 | topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" |
736 | 749 | poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" |
737 | 750 | partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" |
738 | - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}" | |
751 | + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:2000}" | |
739 | 752 | submit-strategy: |
740 | 753 | type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL |
741 | 754 | # For BATCH only | ... | ... |
... | ... | @@ -33,7 +33,6 @@ import org.junit.rules.TestRule; |
33 | 33 | import org.junit.rules.TestWatcher; |
34 | 34 | import org.junit.runner.Description; |
35 | 35 | import org.junit.runner.RunWith; |
36 | -import org.mockito.Mockito; | |
37 | 36 | import org.springframework.beans.factory.annotation.Autowired; |
38 | 37 | import org.springframework.boot.test.context.SpringBootContextLoader; |
39 | 38 | import org.springframework.boot.test.context.SpringBootTest; |
... | ... | @@ -49,7 +48,6 @@ import org.springframework.mock.http.MockHttpOutputMessage; |
49 | 48 | import org.springframework.test.annotation.DirtiesContext; |
50 | 49 | import org.springframework.test.context.ActiveProfiles; |
51 | 50 | import org.springframework.test.context.ContextConfiguration; |
52 | -import org.springframework.test.context.TestPropertySource; | |
53 | 51 | import org.springframework.test.context.junit4.SpringRunner; |
54 | 52 | import org.springframework.test.context.web.WebAppConfiguration; |
55 | 53 | import org.springframework.test.web.servlet.MockMvc; |
... | ... | @@ -75,7 +73,6 @@ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; |
75 | 73 | import org.thingsboard.server.service.security.auth.rest.LoginRequest; |
76 | 74 | |
77 | 75 | import java.io.IOException; |
78 | -import java.nio.charset.Charset; | |
79 | 76 | import java.util.ArrayList; |
80 | 77 | import java.util.Arrays; |
81 | 78 | import java.util.Comparator; |
... | ... | @@ -223,6 +220,27 @@ public abstract class AbstractControllerTest { |
223 | 220 | login(CUSTOMER_USER_EMAIL, CUSTOMER_USER_PASSWORD); |
224 | 221 | } |
225 | 222 | |
223 | + private Tenant savedDifferentTenant; | |
224 | + protected void loginDifferentTenant() throws Exception { | |
225 | + loginSysAdmin(); | |
226 | + Tenant tenant = new Tenant(); | |
227 | + tenant.setTitle("Different tenant"); | |
228 | + savedDifferentTenant = doPost("/api/tenant", tenant, Tenant.class); | |
229 | + Assert.assertNotNull(savedDifferentTenant); | |
230 | + User differentTenantAdmin = new User(); | |
231 | + differentTenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
232 | + differentTenantAdmin.setTenantId(savedDifferentTenant.getId()); | |
233 | + differentTenantAdmin.setEmail("different_tenant@thingsboard.org"); | |
234 | + | |
235 | + createUserAndLogin(differentTenantAdmin, "testPassword"); | |
236 | + } | |
237 | + | |
238 | + protected void deleteDifferentTenant() throws Exception { | |
239 | + loginSysAdmin(); | |
240 | + doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString()) | |
241 | + .andExpect(status().isOk()); | |
242 | + } | |
243 | + | |
226 | 244 | protected User createUserAndLogin(User user, String password) throws Exception { |
227 | 245 | User savedUser = doPost("/api/user", user, User.class); |
228 | 246 | logout(); | ... | ... |
... | ... | @@ -99,6 +99,18 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { |
99 | 99 | } |
100 | 100 | |
101 | 101 | @Test |
102 | + public void testUpdateAssetFromDifferentTenant() throws Exception { | |
103 | + Asset asset = new Asset(); | |
104 | + asset.setName("My asset"); | |
105 | + asset.setType("default"); | |
106 | + Asset savedAsset = doPost("/api/asset", asset, Asset.class); | |
107 | + | |
108 | + loginDifferentTenant(); | |
109 | + doPost("/api/asset", savedAsset, Asset.class, status().isForbidden()); | |
110 | + deleteDifferentTenant(); | |
111 | + } | |
112 | + | |
113 | + @Test | |
102 | 114 | public void testFindAssetById() throws Exception { |
103 | 115 | Asset asset = new Asset(); |
104 | 116 | asset.setName("My asset"); | ... | ... |
... | ... | @@ -23,6 +23,8 @@ import java.util.Collections; |
23 | 23 | import java.util.List; |
24 | 24 | |
25 | 25 | import org.apache.commons.lang3.RandomStringUtils; |
26 | +import org.junit.After; | |
27 | +import org.junit.Before; | |
26 | 28 | import org.thingsboard.server.common.data.Customer; |
27 | 29 | import org.thingsboard.server.common.data.Tenant; |
28 | 30 | import org.thingsboard.server.common.data.User; |
... | ... | @@ -38,25 +40,39 @@ import com.fasterxml.jackson.core.type.TypeReference; |
38 | 40 | public abstract class BaseCustomerControllerTest extends AbstractControllerTest { |
39 | 41 | |
40 | 42 | private IdComparator<Customer> idComparator = new IdComparator<>(); |
41 | - | |
42 | - @Test | |
43 | - public void testSaveCustomer() throws Exception { | |
43 | + | |
44 | + private Tenant savedTenant; | |
45 | + private User tenantAdmin; | |
46 | + | |
47 | + @Before | |
48 | + public void beforeTest() throws Exception { | |
44 | 49 | loginSysAdmin(); |
45 | 50 | |
46 | 51 | Tenant tenant = new Tenant(); |
47 | 52 | tenant.setTitle("My tenant"); |
48 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
53 | + savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
49 | 54 | Assert.assertNotNull(savedTenant); |
50 | - | |
51 | - User tenantAdmin = new User(); | |
55 | + | |
56 | + tenantAdmin = new User(); | |
52 | 57 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
53 | 58 | tenantAdmin.setTenantId(savedTenant.getId()); |
54 | 59 | tenantAdmin.setEmail("tenant2@thingsboard.org"); |
55 | 60 | tenantAdmin.setFirstName("Joe"); |
56 | 61 | tenantAdmin.setLastName("Downs"); |
57 | - | |
62 | + | |
58 | 63 | tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
59 | - | |
64 | + } | |
65 | + | |
66 | + @After | |
67 | + public void afterTest() throws Exception { | |
68 | + loginSysAdmin(); | |
69 | + | |
70 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
71 | + .andExpect(status().isOk()); | |
72 | + } | |
73 | + | |
74 | + @Test | |
75 | + public void testSaveCustomer() throws Exception { | |
60 | 76 | Customer customer = new Customer(); |
61 | 77 | customer.setTitle("My customer"); |
62 | 78 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
... | ... | @@ -66,266 +82,159 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
66 | 82 | Assert.assertEquals(customer.getTitle(), savedCustomer.getTitle()); |
67 | 83 | savedCustomer.setTitle("My new customer"); |
68 | 84 | doPost("/api/customer", savedCustomer, Customer.class); |
69 | - | |
70 | - Customer foundCustomer = doGet("/api/customer/"+savedCustomer.getId().getId().toString(), Customer.class); | |
85 | + | |
86 | + Customer foundCustomer = doGet("/api/customer/"+savedCustomer.getId().getId().toString(), Customer.class); | |
71 | 87 | Assert.assertEquals(foundCustomer.getTitle(), savedCustomer.getTitle()); |
72 | - | |
88 | + | |
73 | 89 | doDelete("/api/customer/"+savedCustomer.getId().getId().toString()) |
74 | 90 | .andExpect(status().isOk()); |
75 | - | |
76 | - loginSysAdmin(); | |
77 | - | |
78 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
79 | - .andExpect(status().isOk()); | |
80 | 91 | } |
81 | - | |
92 | + | |
82 | 93 | @Test |
83 | - public void testFindCustomerById() throws Exception { | |
84 | - | |
85 | - loginSysAdmin(); | |
94 | + public void testUpdateCustomerFromDifferentTenant() throws Exception { | |
95 | + Customer customer = new Customer(); | |
96 | + customer.setTitle("My customer"); | |
97 | + Customer savedCustomer = doPost("/api/customer", customer, Customer.class); | |
98 | + doPost("/api/customer", savedCustomer, Customer.class); | |
86 | 99 | |
87 | - Tenant tenant = new Tenant(); | |
88 | - tenant.setTitle("My tenant"); | |
89 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
90 | - Assert.assertNotNull(savedTenant); | |
91 | - | |
92 | - User tenantAdmin = new User(); | |
93 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
94 | - tenantAdmin.setTenantId(savedTenant.getId()); | |
95 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
96 | - tenantAdmin.setFirstName("Joe"); | |
97 | - tenantAdmin.setLastName("Downs"); | |
98 | - | |
99 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
100 | - | |
100 | + loginDifferentTenant(); | |
101 | + doPost("/api/customer", savedCustomer, Customer.class, status().isForbidden()); | |
102 | + deleteDifferentTenant(); | |
103 | + | |
104 | + login(tenantAdmin.getName(), "testPassword1"); | |
105 | + doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) | |
106 | + .andExpect(status().isOk()); | |
107 | + } | |
108 | + | |
109 | + @Test | |
110 | + public void testFindCustomerById() throws Exception { | |
101 | 111 | Customer customer = new Customer(); |
102 | 112 | customer.setTitle("My customer"); |
103 | 113 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
104 | - | |
105 | - Customer foundCustomer = doGet("/api/customer/"+savedCustomer.getId().getId().toString(), Customer.class); | |
114 | + | |
115 | + Customer foundCustomer = doGet("/api/customer/" + savedCustomer.getId().getId().toString(), Customer.class); | |
106 | 116 | Assert.assertNotNull(foundCustomer); |
107 | 117 | Assert.assertEquals(savedCustomer, foundCustomer); |
108 | - | |
109 | - doDelete("/api/customer/"+savedCustomer.getId().getId().toString()) | |
110 | - .andExpect(status().isOk()); | |
111 | - | |
112 | - loginSysAdmin(); | |
113 | - | |
114 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
115 | - .andExpect(status().isOk()); | |
118 | + | |
119 | + doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) | |
120 | + .andExpect(status().isOk()); | |
116 | 121 | } |
117 | - | |
122 | + | |
118 | 123 | @Test |
119 | 124 | public void testDeleteCustomer() throws Exception { |
120 | - | |
121 | - loginSysAdmin(); | |
122 | - | |
123 | - Tenant tenant = new Tenant(); | |
124 | - tenant.setTitle("My tenant"); | |
125 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
126 | - Assert.assertNotNull(savedTenant); | |
127 | - | |
128 | - User tenantAdmin = new User(); | |
129 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
130 | - tenantAdmin.setTenantId(savedTenant.getId()); | |
131 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
132 | - tenantAdmin.setFirstName("Joe"); | |
133 | - tenantAdmin.setLastName("Downs"); | |
134 | - | |
135 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
136 | - | |
137 | 125 | Customer customer = new Customer(); |
138 | 126 | customer.setTitle("My customer"); |
139 | 127 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
140 | - | |
141 | - doDelete("/api/customer/"+savedCustomer.getId().getId().toString()) | |
142 | - .andExpect(status().isOk()); | |
143 | 128 | |
144 | - doGet("/api/customer/"+savedCustomer.getId().getId().toString()) | |
145 | - .andExpect(status().isNotFound()); | |
146 | - | |
147 | - loginSysAdmin(); | |
148 | - | |
149 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
150 | - .andExpect(status().isOk()); | |
129 | + doDelete("/api/customer/" + savedCustomer.getId().getId().toString()) | |
130 | + .andExpect(status().isOk()); | |
131 | + | |
132 | + doGet("/api/customer/" + savedCustomer.getId().getId().toString()) | |
133 | + .andExpect(status().isNotFound()); | |
151 | 134 | } |
152 | - | |
135 | + | |
153 | 136 | @Test |
154 | 137 | public void testSaveCustomerWithEmptyTitle() throws Exception { |
155 | - | |
156 | - loginSysAdmin(); | |
157 | - | |
158 | - Tenant tenant = new Tenant(); | |
159 | - tenant.setTitle("My tenant"); | |
160 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
161 | - Assert.assertNotNull(savedTenant); | |
162 | - | |
163 | - User tenantAdmin = new User(); | |
164 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
165 | - tenantAdmin.setTenantId(savedTenant.getId()); | |
166 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
167 | - tenantAdmin.setFirstName("Joe"); | |
168 | - tenantAdmin.setLastName("Downs"); | |
169 | - | |
170 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
171 | - | |
172 | 138 | Customer customer = new Customer(); |
173 | 139 | doPost("/api/customer", customer) |
174 | - .andExpect(status().isBadRequest()) | |
175 | - .andExpect(statusReason(containsString("Customer title should be specified"))); | |
176 | - | |
177 | - loginSysAdmin(); | |
178 | - | |
179 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
180 | - .andExpect(status().isOk()); | |
140 | + .andExpect(status().isBadRequest()) | |
141 | + .andExpect(statusReason(containsString("Customer title should be specified"))); | |
181 | 142 | } |
182 | - | |
143 | + | |
183 | 144 | @Test |
184 | 145 | public void testSaveCustomerWithInvalidEmail() throws Exception { |
185 | - | |
186 | - loginSysAdmin(); | |
187 | - | |
188 | - Tenant tenant = new Tenant(); | |
189 | - tenant.setTitle("My tenant"); | |
190 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
191 | - Assert.assertNotNull(savedTenant); | |
192 | - | |
193 | - User tenantAdmin = new User(); | |
194 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
195 | - tenantAdmin.setTenantId(savedTenant.getId()); | |
196 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
197 | - tenantAdmin.setFirstName("Joe"); | |
198 | - tenantAdmin.setLastName("Downs"); | |
199 | - | |
200 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
201 | - | |
202 | 146 | Customer customer = new Customer(); |
203 | 147 | customer.setTitle("My customer"); |
204 | 148 | customer.setEmail("invalid@mail"); |
205 | 149 | doPost("/api/customer", customer) |
206 | - .andExpect(status().isBadRequest()) | |
207 | - .andExpect(statusReason(containsString("Invalid email address format 'invalid@mail'"))); | |
208 | - | |
209 | - loginSysAdmin(); | |
210 | - | |
211 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
212 | - .andExpect(status().isOk()); | |
150 | + .andExpect(status().isBadRequest()) | |
151 | + .andExpect(statusReason(containsString("Invalid email address format 'invalid@mail'"))); | |
152 | + | |
153 | +// loginSysAdmin(); | |
154 | +// | |
155 | +// doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
156 | +// .andExpect(status().isOk()); | |
213 | 157 | } |
214 | - | |
158 | + | |
215 | 159 | @Test |
216 | 160 | public void testFindCustomers() throws Exception { |
217 | - loginSysAdmin(); | |
218 | - | |
219 | - Tenant tenant = new Tenant(); | |
220 | - tenant.setTitle("My tenant"); | |
221 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
222 | - Assert.assertNotNull(savedTenant); | |
223 | - | |
224 | 161 | TenantId tenantId = savedTenant.getId(); |
225 | - | |
226 | - User tenantAdmin = new User(); | |
227 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
228 | - tenantAdmin.setTenantId(tenantId); | |
229 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
230 | - tenantAdmin.setFirstName("Joe"); | |
231 | - tenantAdmin.setLastName("Downs"); | |
232 | - | |
233 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
234 | - | |
162 | + | |
235 | 163 | List<Customer> customers = new ArrayList<>(); |
236 | - for (int i=0;i<135;i++) { | |
164 | + for (int i = 0; i < 135; i++) { | |
237 | 165 | Customer customer = new Customer(); |
238 | 166 | customer.setTenantId(tenantId); |
239 | - customer.setTitle("Customer"+i); | |
167 | + customer.setTitle("Customer" + i); | |
240 | 168 | customers.add(doPost("/api/customer", customer, Customer.class)); |
241 | 169 | } |
242 | - | |
170 | + | |
243 | 171 | List<Customer> loadedCustomers = new ArrayList<>(); |
244 | 172 | TextPageLink pageLink = new TextPageLink(23); |
245 | 173 | TextPageData<Customer> pageData = null; |
246 | 174 | do { |
247 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
175 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() { | |
176 | + }, pageLink); | |
248 | 177 | loadedCustomers.addAll(pageData.getData()); |
249 | 178 | if (pageData.hasNext()) { |
250 | 179 | pageLink = pageData.getNextPageLink(); |
251 | 180 | } |
252 | 181 | } while (pageData.hasNext()); |
253 | - | |
182 | + | |
254 | 183 | Collections.sort(customers, idComparator); |
255 | 184 | Collections.sort(loadedCustomers, idComparator); |
256 | - | |
185 | + | |
257 | 186 | Assert.assertEquals(customers, loadedCustomers); |
258 | - | |
259 | - loginSysAdmin(); | |
260 | - | |
261 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
262 | - .andExpect(status().isOk()); | |
263 | 187 | } |
264 | - | |
188 | + | |
265 | 189 | @Test |
266 | 190 | public void testFindCustomersByTitle() throws Exception { |
267 | - | |
268 | - loginSysAdmin(); | |
269 | - | |
270 | - Tenant tenant = new Tenant(); | |
271 | - tenant.setTitle("My tenant"); | |
272 | - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
273 | - Assert.assertNotNull(savedTenant); | |
274 | - | |
275 | 191 | TenantId tenantId = savedTenant.getId(); |
276 | - | |
277 | - User tenantAdmin = new User(); | |
278 | - tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
279 | - tenantAdmin.setTenantId(tenantId); | |
280 | - tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
281 | - tenantAdmin.setFirstName("Joe"); | |
282 | - tenantAdmin.setLastName("Downs"); | |
283 | - | |
284 | - tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
285 | - | |
192 | + | |
286 | 193 | String title1 = "Customer title 1"; |
287 | 194 | List<Customer> customersTitle1 = new ArrayList<>(); |
288 | - for (int i=0;i<143;i++) { | |
195 | + for (int i = 0; i < 143; i++) { | |
289 | 196 | Customer customer = new Customer(); |
290 | 197 | customer.setTenantId(tenantId); |
291 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); | |
292 | - String title = title1+suffix; | |
198 | + String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)); | |
199 | + String title = title1 + suffix; | |
293 | 200 | title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); |
294 | 201 | customer.setTitle(title); |
295 | 202 | customersTitle1.add(doPost("/api/customer", customer, Customer.class)); |
296 | 203 | } |
297 | 204 | String title2 = "Customer title 2"; |
298 | 205 | List<Customer> customersTitle2 = new ArrayList<>(); |
299 | - for (int i=0;i<175;i++) { | |
206 | + for (int i = 0; i < 175; i++) { | |
300 | 207 | Customer customer = new Customer(); |
301 | 208 | customer.setTenantId(tenantId); |
302 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); | |
303 | - String title = title2+suffix; | |
209 | + String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)); | |
210 | + String title = title2 + suffix; | |
304 | 211 | title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); |
305 | 212 | customer.setTitle(title); |
306 | 213 | customersTitle2.add(doPost("/api/customer", customer, Customer.class)); |
307 | 214 | } |
308 | - | |
215 | + | |
309 | 216 | List<Customer> loadedCustomersTitle1 = new ArrayList<>(); |
310 | 217 | TextPageLink pageLink = new TextPageLink(15, title1); |
311 | 218 | TextPageData<Customer> pageData = null; |
312 | 219 | do { |
313 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
220 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() { | |
221 | + }, pageLink); | |
314 | 222 | loadedCustomersTitle1.addAll(pageData.getData()); |
315 | 223 | if (pageData.hasNext()) { |
316 | 224 | pageLink = pageData.getNextPageLink(); |
317 | 225 | } |
318 | 226 | } while (pageData.hasNext()); |
319 | - | |
227 | + | |
320 | 228 | Collections.sort(customersTitle1, idComparator); |
321 | 229 | Collections.sort(loadedCustomersTitle1, idComparator); |
322 | - | |
230 | + | |
323 | 231 | Assert.assertEquals(customersTitle1, loadedCustomersTitle1); |
324 | - | |
232 | + | |
325 | 233 | List<Customer> loadedCustomersTitle2 = new ArrayList<>(); |
326 | 234 | pageLink = new TextPageLink(4, title2); |
327 | 235 | do { |
328 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
236 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() { | |
237 | + }, pageLink); | |
329 | 238 | loadedCustomersTitle2.addAll(pageData.getData()); |
330 | 239 | if (pageData.hasNext()) { |
331 | 240 | pageLink = pageData.getNextPageLink(); |
... | ... | @@ -334,33 +243,30 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest |
334 | 243 | |
335 | 244 | Collections.sort(customersTitle2, idComparator); |
336 | 245 | Collections.sort(loadedCustomersTitle2, idComparator); |
337 | - | |
246 | + | |
338 | 247 | Assert.assertEquals(customersTitle2, loadedCustomersTitle2); |
339 | - | |
248 | + | |
340 | 249 | for (Customer customer : loadedCustomersTitle1) { |
341 | - doDelete("/api/customer/"+customer.getId().getId().toString()) | |
342 | - .andExpect(status().isOk()); | |
250 | + doDelete("/api/customer/" + customer.getId().getId().toString()) | |
251 | + .andExpect(status().isOk()); | |
343 | 252 | } |
344 | - | |
253 | + | |
345 | 254 | pageLink = new TextPageLink(4, title1); |
346 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
255 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() { | |
256 | + }, pageLink); | |
347 | 257 | Assert.assertFalse(pageData.hasNext()); |
348 | 258 | Assert.assertEquals(0, pageData.getData().size()); |
349 | - | |
259 | + | |
350 | 260 | for (Customer customer : loadedCustomersTitle2) { |
351 | - doDelete("/api/customer/"+customer.getId().getId().toString()) | |
352 | - .andExpect(status().isOk()); | |
261 | + doDelete("/api/customer/" + customer.getId().getId().toString()) | |
262 | + .andExpect(status().isOk()); | |
353 | 263 | } |
354 | - | |
264 | + | |
355 | 265 | pageLink = new TextPageLink(4, title2); |
356 | - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); | |
266 | + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() { | |
267 | + }, pageLink); | |
357 | 268 | Assert.assertFalse(pageData.hasNext()); |
358 | 269 | Assert.assertEquals(0, pageData.getData().size()); |
359 | - | |
360 | - loginSysAdmin(); | |
361 | - | |
362 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
363 | - .andExpect(status().isOk()); | |
364 | 270 | } |
365 | - | |
271 | + | |
366 | 272 | } | ... | ... |
... | ... | @@ -16,10 +16,8 @@ |
16 | 16 | package org.thingsboard.server.controller; |
17 | 17 | |
18 | 18 | import static org.hamcrest.Matchers.containsString; |
19 | -import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; | |
20 | 19 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
21 | 20 | |
22 | -import java.sql.Time; | |
23 | 21 | import java.util.ArrayList; |
24 | 22 | import java.util.Collections; |
25 | 23 | import java.util.List; |
... | ... | @@ -33,7 +31,6 @@ import org.thingsboard.server.common.data.page.TextPageLink; |
33 | 31 | import org.thingsboard.server.common.data.page.TimePageData; |
34 | 32 | import org.thingsboard.server.common.data.page.TimePageLink; |
35 | 33 | import org.thingsboard.server.common.data.security.Authority; |
36 | -import org.thingsboard.server.dao.model.ModelConstants; | |
37 | 34 | import org.junit.After; |
38 | 35 | import org.junit.Assert; |
39 | 36 | import org.junit.Before; |
... | ... | @@ -93,6 +90,17 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest |
93 | 90 | Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); |
94 | 91 | Assert.assertEquals(foundDashboard.getTitle(), savedDashboard.getTitle()); |
95 | 92 | } |
93 | + | |
94 | + @Test | |
95 | + public void testUpdateDashboardFromDifferentTenant() throws Exception { | |
96 | + Dashboard dashboard = new Dashboard(); | |
97 | + dashboard.setTitle("My dashboard"); | |
98 | + Dashboard savedDashboard = doPost("/api/dashboard", dashboard, Dashboard.class); | |
99 | + | |
100 | + loginDifferentTenant(); | |
101 | + doPost("/api/dashboard", savedDashboard, Dashboard.class, status().isForbidden()); | |
102 | + deleteDifferentTenant(); | |
103 | + } | |
96 | 104 | |
97 | 105 | @Test |
98 | 106 | public void testFindDashboardById() throws Exception { | ... | ... |
... | ... | @@ -107,6 +107,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
107 | 107 | Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); |
108 | 108 | Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); |
109 | 109 | } |
110 | + | |
111 | + @Test | |
112 | + public void testUpdateDeviceFromDifferentTenant() throws Exception { | |
113 | + Device device = new Device(); | |
114 | + device.setName("My device"); | |
115 | + device.setType("default"); | |
116 | + Device savedDevice = doPost("/api/device", device, Device.class); | |
117 | + loginDifferentTenant(); | |
118 | + doPost("/api/device", savedDevice, Device.class, status().isForbidden()); | |
119 | + deleteDifferentTenant(); | |
120 | + } | |
110 | 121 | |
111 | 122 | @Test |
112 | 123 | public void testFindDeviceById() throws Exception { | ... | ... |
... | ... | @@ -25,7 +25,6 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; |
25 | 25 | import org.junit.After; |
26 | 26 | import org.junit.Assert; |
27 | 27 | import org.junit.Before; |
28 | -import org.junit.Ignore; | |
29 | 28 | import org.junit.Test; |
30 | 29 | import org.thingsboard.server.common.data.Customer; |
31 | 30 | import org.thingsboard.server.common.data.Device; |
... | ... | @@ -132,6 +131,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes |
132 | 131 | assertEquals(foundEntityView.getKeys(), telemetry); |
133 | 132 | } |
134 | 133 | |
134 | + | |
135 | + @Test | |
136 | + public void testUpdateEntityViewFromDifferentTenant() throws Exception { | |
137 | + EntityView savedView = getNewSavedEntityView("Test entity view"); | |
138 | + loginDifferentTenant(); | |
139 | + doPost("/api/entityView", savedView, EntityView.class, status().isForbidden()); | |
140 | + deleteDifferentTenant(); | |
141 | + } | |
142 | + | |
135 | 143 | @Test |
136 | 144 | public void testDeleteEntityView() throws Exception { |
137 | 145 | EntityView view = getNewSavedEntityView("Test entity view"); | ... | ... |
... | ... | @@ -38,21 +38,23 @@ import java.util.List; |
38 | 38 | |
39 | 39 | import static org.hamcrest.Matchers.containsString; |
40 | 40 | import static org.hamcrest.Matchers.is; |
41 | -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | |
41 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; | |
42 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; | |
43 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | |
42 | 44 | |
43 | 45 | public abstract class BaseUserControllerTest extends AbstractControllerTest { |
44 | - | |
46 | + | |
45 | 47 | private IdComparator<User> idComparator = new IdComparator<>(); |
46 | 48 | |
47 | 49 | @Test |
48 | 50 | public void testSaveUser() throws Exception { |
49 | 51 | loginSysAdmin(); |
50 | - | |
52 | + | |
51 | 53 | Tenant tenant = new Tenant(); |
52 | 54 | tenant.setTitle("My tenant"); |
53 | 55 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
54 | 56 | Assert.assertNotNull(savedTenant); |
55 | - | |
57 | + | |
56 | 58 | String email = "tenant2@thingsboard.org"; |
57 | 59 | User user = new User(); |
58 | 60 | user.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -66,13 +68,13 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
66 | 68 | Assert.assertTrue(savedUser.getCreatedTime() > 0); |
67 | 69 | Assert.assertEquals(user.getEmail(), savedUser.getEmail()); |
68 | 70 | |
69 | - User foundUser = doGet("/api/user/"+savedUser.getId().getId().toString(), User.class); | |
71 | + User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class); | |
70 | 72 | Assert.assertEquals(foundUser, savedUser); |
71 | - | |
73 | + | |
72 | 74 | logout(); |
73 | 75 | doGet("/api/noauth/activate?activateToken={activateToken}", TestMailService.currentActivateToken) |
74 | - .andExpect(status().isSeeOther()) | |
75 | - .andExpect(header().string(HttpHeaders.LOCATION, "/login/createPassword?activateToken=" + TestMailService.currentActivateToken)); | |
76 | + .andExpect(status().isSeeOther()) | |
77 | + .andExpect(header().string(HttpHeaders.LOCATION, "/login/createPassword?activateToken=" + TestMailService.currentActivateToken)); | |
76 | 78 | |
77 | 79 | JsonNode activateRequest = new ObjectMapper().createObjectNode() |
78 | 80 | .put("activateToken", TestMailService.currentActivateToken) |
... | ... | @@ -82,36 +84,61 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
82 | 84 | validateAndSetJwtToken(tokenInfo, email); |
83 | 85 | |
84 | 86 | doGet("/api/auth/user") |
85 | - .andExpect(status().isOk()) | |
86 | - .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) | |
87 | - .andExpect(jsonPath("$.email",is(email))); | |
88 | - | |
87 | + .andExpect(status().isOk()) | |
88 | + .andExpect(jsonPath("$.authority", is(Authority.TENANT_ADMIN.name()))) | |
89 | + .andExpect(jsonPath("$.email", is(email))); | |
90 | + | |
89 | 91 | logout(); |
90 | - | |
92 | + | |
91 | 93 | login(email, "testPassword"); |
92 | - | |
94 | + | |
93 | 95 | doGet("/api/auth/user") |
94 | - .andExpect(status().isOk()) | |
95 | - .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) | |
96 | - .andExpect(jsonPath("$.email",is(email))); | |
97 | - | |
96 | + .andExpect(status().isOk()) | |
97 | + .andExpect(jsonPath("$.authority", is(Authority.TENANT_ADMIN.name()))) | |
98 | + .andExpect(jsonPath("$.email", is(email))); | |
99 | + | |
98 | 100 | loginSysAdmin(); |
99 | - doDelete("/api/user/"+savedUser.getId().getId().toString()) | |
100 | - .andExpect(status().isOk()); | |
101 | - | |
102 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
103 | - .andExpect(status().isOk()); | |
101 | + doDelete("/api/user/" + savedUser.getId().getId().toString()) | |
102 | + .andExpect(status().isOk()); | |
103 | + | |
104 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
105 | + .andExpect(status().isOk()); | |
104 | 106 | } |
105 | - | |
107 | + | |
108 | + @Test | |
109 | + public void testUpdateUserFromDifferentTenant() throws Exception { | |
110 | + loginSysAdmin(); | |
111 | + Tenant tenant = new Tenant(); | |
112 | + tenant.setTitle("My tenant"); | |
113 | + Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); | |
114 | + Assert.assertNotNull(savedTenant); | |
115 | + | |
116 | + User tenantAdmin = new User(); | |
117 | + tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | |
118 | + tenantAdmin.setTenantId(savedTenant.getId()); | |
119 | + tenantAdmin.setEmail("tenant2@thingsboard.org"); | |
120 | + tenantAdmin.setFirstName("Joe"); | |
121 | + tenantAdmin.setLastName("Downs"); | |
122 | + tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | |
123 | + | |
124 | + loginDifferentTenant(); | |
125 | + doPost("/api/user", tenantAdmin, User.class, status().isForbidden()); | |
126 | + deleteDifferentTenant(); | |
127 | + | |
128 | + loginSysAdmin(); | |
129 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
130 | + .andExpect(status().isOk()); | |
131 | + } | |
132 | + | |
106 | 133 | @Test |
107 | 134 | public void testResetPassword() throws Exception { |
108 | 135 | loginSysAdmin(); |
109 | - | |
136 | + | |
110 | 137 | Tenant tenant = new Tenant(); |
111 | 138 | tenant.setTitle("My tenant"); |
112 | 139 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
113 | 140 | Assert.assertNotNull(savedTenant); |
114 | - | |
141 | + | |
115 | 142 | String email = "tenant2@thingsboard.org"; |
116 | 143 | User user = new User(); |
117 | 144 | user.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -119,7 +146,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
119 | 146 | user.setEmail(email); |
120 | 147 | user.setFirstName("Joe"); |
121 | 148 | user.setLastName("Downs"); |
122 | - | |
149 | + | |
123 | 150 | User savedUser = createUserAndLogin(user, "testPassword1"); |
124 | 151 | logout(); |
125 | 152 | |
... | ... | @@ -127,10 +154,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
127 | 154 | .put("email", email); |
128 | 155 | |
129 | 156 | doPost("/api/noauth/resetPasswordByEmail", resetPasswordByEmailRequest) |
130 | - .andExpect(status().isOk()); | |
157 | + .andExpect(status().isOk()); | |
131 | 158 | doGet("/api/noauth/resetPassword?resetToken={resetToken}", TestMailService.currentResetPasswordToken) |
132 | - .andExpect(status().isSeeOther()) | |
133 | - .andExpect(header().string(HttpHeaders.LOCATION, "/login/resetPassword?resetToken=" + TestMailService.currentResetPasswordToken)); | |
159 | + .andExpect(status().isSeeOther()) | |
160 | + .andExpect(header().string(HttpHeaders.LOCATION, "/login/resetPassword?resetToken=" + TestMailService.currentResetPasswordToken)); | |
134 | 161 | |
135 | 162 | JsonNode resetPasswordRequest = new ObjectMapper().createObjectNode() |
136 | 163 | .put("resetToken", TestMailService.currentResetPasswordToken) |
... | ... | @@ -140,35 +167,35 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
140 | 167 | validateAndSetJwtToken(tokenInfo, email); |
141 | 168 | |
142 | 169 | doGet("/api/auth/user") |
143 | - .andExpect(status().isOk()) | |
144 | - .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) | |
145 | - .andExpect(jsonPath("$.email",is(email))); | |
146 | - | |
170 | + .andExpect(status().isOk()) | |
171 | + .andExpect(jsonPath("$.authority", is(Authority.TENANT_ADMIN.name()))) | |
172 | + .andExpect(jsonPath("$.email", is(email))); | |
173 | + | |
147 | 174 | logout(); |
148 | - | |
175 | + | |
149 | 176 | login(email, "testPassword2"); |
150 | 177 | doGet("/api/auth/user") |
151 | - .andExpect(status().isOk()) | |
152 | - .andExpect(jsonPath("$.authority",is(Authority.TENANT_ADMIN.name()))) | |
153 | - .andExpect(jsonPath("$.email",is(email))); | |
154 | - | |
178 | + .andExpect(status().isOk()) | |
179 | + .andExpect(jsonPath("$.authority", is(Authority.TENANT_ADMIN.name()))) | |
180 | + .andExpect(jsonPath("$.email", is(email))); | |
181 | + | |
155 | 182 | loginSysAdmin(); |
156 | - doDelete("/api/user/"+savedUser.getId().getId().toString()) | |
157 | - .andExpect(status().isOk()); | |
158 | - | |
159 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
160 | - .andExpect(status().isOk()); | |
183 | + doDelete("/api/user/" + savedUser.getId().getId().toString()) | |
184 | + .andExpect(status().isOk()); | |
185 | + | |
186 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
187 | + .andExpect(status().isOk()); | |
161 | 188 | } |
162 | - | |
189 | + | |
163 | 190 | @Test |
164 | 191 | public void testFindUserById() throws Exception { |
165 | 192 | loginSysAdmin(); |
166 | - | |
193 | + | |
167 | 194 | Tenant tenant = new Tenant(); |
168 | 195 | tenant.setTitle("My tenant"); |
169 | 196 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
170 | 197 | Assert.assertNotNull(savedTenant); |
171 | - | |
198 | + | |
172 | 199 | String email = "tenant2@thingsboard.org"; |
173 | 200 | User user = new User(); |
174 | 201 | user.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -176,25 +203,25 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
176 | 203 | user.setEmail(email); |
177 | 204 | user.setFirstName("Joe"); |
178 | 205 | user.setLastName("Downs"); |
179 | - | |
206 | + | |
180 | 207 | User savedUser = doPost("/api/user", user, User.class); |
181 | - User foundUser = doGet("/api/user/"+savedUser.getId().getId().toString(), User.class); | |
208 | + User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class); | |
182 | 209 | Assert.assertNotNull(foundUser); |
183 | 210 | Assert.assertEquals(savedUser, foundUser); |
184 | - | |
185 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
186 | - .andExpect(status().isOk()); | |
211 | + | |
212 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
213 | + .andExpect(status().isOk()); | |
187 | 214 | } |
188 | - | |
215 | + | |
189 | 216 | @Test |
190 | 217 | public void testSaveUserWithSameEmail() throws Exception { |
191 | 218 | loginSysAdmin(); |
192 | - | |
219 | + | |
193 | 220 | Tenant tenant = new Tenant(); |
194 | 221 | tenant.setTitle("My tenant"); |
195 | 222 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
196 | 223 | Assert.assertNotNull(savedTenant); |
197 | - | |
224 | + | |
198 | 225 | String email = TENANT_ADMIN_EMAIL; |
199 | 226 | User user = new User(); |
200 | 227 | user.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -202,24 +229,24 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
202 | 229 | user.setEmail(email); |
203 | 230 | user.setFirstName("Joe"); |
204 | 231 | user.setLastName("Downs"); |
205 | - | |
232 | + | |
206 | 233 | doPost("/api/user", user) |
207 | - .andExpect(status().isBadRequest()) | |
208 | - .andExpect(statusReason(containsString("User with email '" + email + "' already present in database"))); | |
209 | - | |
210 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
211 | - .andExpect(status().isOk()); | |
234 | + .andExpect(status().isBadRequest()) | |
235 | + .andExpect(statusReason(containsString("User with email '" + email + "' already present in database"))); | |
236 | + | |
237 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
238 | + .andExpect(status().isOk()); | |
212 | 239 | } |
213 | - | |
240 | + | |
214 | 241 | @Test |
215 | 242 | public void testSaveUserWithInvalidEmail() throws Exception { |
216 | 243 | loginSysAdmin(); |
217 | - | |
244 | + | |
218 | 245 | Tenant tenant = new Tenant(); |
219 | 246 | tenant.setTitle("My tenant"); |
220 | 247 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
221 | 248 | Assert.assertNotNull(savedTenant); |
222 | - | |
249 | + | |
223 | 250 | String email = "tenant_thingsboard.org"; |
224 | 251 | User user = new User(); |
225 | 252 | user.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -227,62 +254,62 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
227 | 254 | user.setEmail(email); |
228 | 255 | user.setFirstName("Joe"); |
229 | 256 | user.setLastName("Downs"); |
230 | - | |
257 | + | |
231 | 258 | doPost("/api/user", user) |
232 | - .andExpect(status().isBadRequest()) | |
233 | - .andExpect(statusReason(containsString("Invalid email address format '" + email + "'"))); | |
234 | - | |
235 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
236 | - .andExpect(status().isOk()); | |
259 | + .andExpect(status().isBadRequest()) | |
260 | + .andExpect(statusReason(containsString("Invalid email address format '" + email + "'"))); | |
261 | + | |
262 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
263 | + .andExpect(status().isOk()); | |
237 | 264 | } |
238 | - | |
265 | + | |
239 | 266 | @Test |
240 | 267 | public void testSaveUserWithEmptyEmail() throws Exception { |
241 | 268 | loginSysAdmin(); |
242 | - | |
269 | + | |
243 | 270 | Tenant tenant = new Tenant(); |
244 | 271 | tenant.setTitle("My tenant"); |
245 | 272 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
246 | 273 | Assert.assertNotNull(savedTenant); |
247 | - | |
274 | + | |
248 | 275 | User user = new User(); |
249 | 276 | user.setAuthority(Authority.TENANT_ADMIN); |
250 | 277 | user.setTenantId(savedTenant.getId()); |
251 | 278 | user.setFirstName("Joe"); |
252 | 279 | user.setLastName("Downs"); |
253 | - | |
280 | + | |
254 | 281 | doPost("/api/user", user) |
255 | - .andExpect(status().isBadRequest()) | |
256 | - .andExpect(statusReason(containsString("User email should be specified"))); | |
257 | - | |
258 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
259 | - .andExpect(status().isOk()); | |
282 | + .andExpect(status().isBadRequest()) | |
283 | + .andExpect(statusReason(containsString("User email should be specified"))); | |
284 | + | |
285 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
286 | + .andExpect(status().isOk()); | |
260 | 287 | } |
261 | - | |
288 | + | |
262 | 289 | @Test |
263 | 290 | public void testSaveUserWithoutTenant() throws Exception { |
264 | 291 | loginSysAdmin(); |
265 | - | |
292 | + | |
266 | 293 | User user = new User(); |
267 | 294 | user.setAuthority(Authority.TENANT_ADMIN); |
268 | 295 | user.setEmail("tenant2@thingsboard.org"); |
269 | 296 | user.setFirstName("Joe"); |
270 | 297 | user.setLastName("Downs"); |
271 | - | |
298 | + | |
272 | 299 | doPost("/api/user", user) |
273 | - .andExpect(status().isBadRequest()) | |
274 | - .andExpect(statusReason(containsString("Tenant administrator should be assigned to tenant"))); | |
300 | + .andExpect(status().isBadRequest()) | |
301 | + .andExpect(statusReason(containsString("Tenant administrator should be assigned to tenant"))); | |
275 | 302 | } |
276 | - | |
303 | + | |
277 | 304 | @Test |
278 | 305 | public void testDeleteUser() throws Exception { |
279 | 306 | loginSysAdmin(); |
280 | - | |
307 | + | |
281 | 308 | Tenant tenant = new Tenant(); |
282 | 309 | tenant.setTitle("My tenant"); |
283 | 310 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
284 | 311 | Assert.assertNotNull(savedTenant); |
285 | - | |
312 | + | |
286 | 313 | String email = "tenant2@thingsboard.org"; |
287 | 314 | User user = new User(); |
288 | 315 | user.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -290,176 +317,182 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
290 | 317 | user.setEmail(email); |
291 | 318 | user.setFirstName("Joe"); |
292 | 319 | user.setLastName("Downs"); |
293 | - | |
320 | + | |
294 | 321 | User savedUser = doPost("/api/user", user, User.class); |
295 | - User foundUser = doGet("/api/user/"+savedUser.getId().getId().toString(), User.class); | |
322 | + User foundUser = doGet("/api/user/" + savedUser.getId().getId().toString(), User.class); | |
296 | 323 | Assert.assertNotNull(foundUser); |
297 | - | |
298 | - doDelete("/api/user/"+savedUser.getId().getId().toString()) | |
299 | - .andExpect(status().isOk()); | |
300 | - | |
301 | - doGet("/api/user/"+savedUser.getId().getId().toString()) | |
302 | - .andExpect(status().isNotFound()); | |
303 | - | |
304 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
305 | - .andExpect(status().isOk()); | |
324 | + | |
325 | + doDelete("/api/user/" + savedUser.getId().getId().toString()) | |
326 | + .andExpect(status().isOk()); | |
327 | + | |
328 | + doGet("/api/user/" + savedUser.getId().getId().toString()) | |
329 | + .andExpect(status().isNotFound()); | |
330 | + | |
331 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
332 | + .andExpect(status().isOk()); | |
306 | 333 | } |
307 | - | |
334 | + | |
308 | 335 | @Test |
309 | 336 | public void testFindTenantAdmins() throws Exception { |
310 | 337 | loginSysAdmin(); |
311 | - | |
338 | + | |
312 | 339 | Tenant tenant = new Tenant(); |
313 | 340 | tenant.setTitle("My tenant"); |
314 | 341 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
315 | 342 | Assert.assertNotNull(savedTenant); |
316 | - | |
343 | + | |
317 | 344 | TenantId tenantId = savedTenant.getId(); |
318 | - | |
345 | + | |
319 | 346 | List<User> tenantAdmins = new ArrayList<>(); |
320 | - for (int i=0;i<64;i++) { | |
347 | + for (int i = 0; i < 64; i++) { | |
321 | 348 | User user = new User(); |
322 | 349 | user.setAuthority(Authority.TENANT_ADMIN); |
323 | 350 | user.setTenantId(tenantId); |
324 | 351 | user.setEmail("testTenant" + i + "@thingsboard.org"); |
325 | 352 | tenantAdmins.add(doPost("/api/user", user, User.class)); |
326 | 353 | } |
327 | - | |
354 | + | |
328 | 355 | List<User> loadedTenantAdmins = new ArrayList<>(); |
329 | 356 | TextPageLink pageLink = new TextPageLink(33); |
330 | 357 | TextPageData<User> pageData = null; |
331 | 358 | do { |
332 | - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
333 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
359 | + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
360 | + new TypeReference<TextPageData<User>>() { | |
361 | + }, pageLink); | |
334 | 362 | loadedTenantAdmins.addAll(pageData.getData()); |
335 | 363 | if (pageData.hasNext()) { |
336 | 364 | pageLink = pageData.getNextPageLink(); |
337 | 365 | } |
338 | 366 | } while (pageData.hasNext()); |
339 | - | |
367 | + | |
340 | 368 | Collections.sort(tenantAdmins, idComparator); |
341 | 369 | Collections.sort(loadedTenantAdmins, idComparator); |
342 | - | |
370 | + | |
343 | 371 | Assert.assertEquals(tenantAdmins, loadedTenantAdmins); |
344 | - | |
345 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
346 | - .andExpect(status().isOk()); | |
347 | - | |
372 | + | |
373 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
374 | + .andExpect(status().isOk()); | |
375 | + | |
348 | 376 | pageLink = new TextPageLink(33); |
349 | - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
350 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
377 | + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
378 | + new TypeReference<TextPageData<User>>() { | |
379 | + }, pageLink); | |
351 | 380 | Assert.assertFalse(pageData.hasNext()); |
352 | 381 | Assert.assertTrue(pageData.getData().isEmpty()); |
353 | 382 | } |
354 | - | |
383 | + | |
355 | 384 | @Test |
356 | 385 | public void testFindTenantAdminsByEmail() throws Exception { |
357 | - | |
386 | + | |
358 | 387 | loginSysAdmin(); |
359 | - | |
388 | + | |
360 | 389 | Tenant tenant = new Tenant(); |
361 | 390 | tenant.setTitle("My tenant"); |
362 | 391 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
363 | 392 | Assert.assertNotNull(savedTenant); |
364 | - | |
393 | + | |
365 | 394 | TenantId tenantId = savedTenant.getId(); |
366 | - | |
367 | - String email1 = "testEmail1"; | |
395 | + | |
396 | + String email1 = "testEmail1"; | |
368 | 397 | List<User> tenantAdminsEmail1 = new ArrayList<>(); |
369 | - | |
370 | - for (int i=0;i<124;i++) { | |
398 | + | |
399 | + for (int i = 0; i < 124; i++) { | |
371 | 400 | User user = new User(); |
372 | 401 | user.setAuthority(Authority.TENANT_ADMIN); |
373 | 402 | user.setTenantId(tenantId); |
374 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); | |
375 | - String email = email1+suffix+ "@thingsboard.org"; | |
403 | + String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)); | |
404 | + String email = email1 + suffix + "@thingsboard.org"; | |
376 | 405 | email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); |
377 | 406 | user.setEmail(email); |
378 | 407 | tenantAdminsEmail1.add(doPost("/api/user", user, User.class)); |
379 | 408 | } |
380 | - | |
381 | - String email2 = "testEmail2"; | |
409 | + | |
410 | + String email2 = "testEmail2"; | |
382 | 411 | List<User> tenantAdminsEmail2 = new ArrayList<>(); |
383 | - | |
384 | - for (int i=0;i<112;i++) { | |
412 | + | |
413 | + for (int i = 0; i < 112; i++) { | |
385 | 414 | User user = new User(); |
386 | 415 | user.setAuthority(Authority.TENANT_ADMIN); |
387 | 416 | user.setTenantId(tenantId); |
388 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); | |
389 | - String email = email2+suffix+ "@thingsboard.org"; | |
417 | + String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)); | |
418 | + String email = email2 + suffix + "@thingsboard.org"; | |
390 | 419 | email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); |
391 | 420 | user.setEmail(email); |
392 | 421 | tenantAdminsEmail2.add(doPost("/api/user", user, User.class)); |
393 | 422 | } |
394 | - | |
423 | + | |
395 | 424 | List<User> loadedTenantAdminsEmail1 = new ArrayList<>(); |
396 | 425 | TextPageLink pageLink = new TextPageLink(33, email1); |
397 | 426 | TextPageData<User> pageData = null; |
398 | 427 | do { |
399 | - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
400 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
428 | + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
429 | + new TypeReference<TextPageData<User>>() { | |
430 | + }, pageLink); | |
401 | 431 | loadedTenantAdminsEmail1.addAll(pageData.getData()); |
402 | 432 | if (pageData.hasNext()) { |
403 | 433 | pageLink = pageData.getNextPageLink(); |
404 | 434 | } |
405 | 435 | } while (pageData.hasNext()); |
406 | - | |
436 | + | |
407 | 437 | Collections.sort(tenantAdminsEmail1, idComparator); |
408 | 438 | Collections.sort(loadedTenantAdminsEmail1, idComparator); |
409 | - | |
439 | + | |
410 | 440 | Assert.assertEquals(tenantAdminsEmail1, loadedTenantAdminsEmail1); |
411 | - | |
441 | + | |
412 | 442 | List<User> loadedTenantAdminsEmail2 = new ArrayList<>(); |
413 | 443 | pageLink = new TextPageLink(16, email2); |
414 | 444 | do { |
415 | - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
416 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
445 | + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
446 | + new TypeReference<TextPageData<User>>() { | |
447 | + }, pageLink); | |
417 | 448 | loadedTenantAdminsEmail2.addAll(pageData.getData()); |
418 | 449 | if (pageData.hasNext()) { |
419 | 450 | pageLink = pageData.getNextPageLink(); |
420 | 451 | } |
421 | 452 | } while (pageData.hasNext()); |
422 | - | |
453 | + | |
423 | 454 | Collections.sort(tenantAdminsEmail2, idComparator); |
424 | 455 | Collections.sort(loadedTenantAdminsEmail2, idComparator); |
425 | - | |
456 | + | |
426 | 457 | Assert.assertEquals(tenantAdminsEmail2, loadedTenantAdminsEmail2); |
427 | - | |
458 | + | |
428 | 459 | for (User user : loadedTenantAdminsEmail1) { |
429 | - doDelete("/api/user/"+user.getId().getId().toString()) | |
430 | - .andExpect(status().isOk()); | |
460 | + doDelete("/api/user/" + user.getId().getId().toString()) | |
461 | + .andExpect(status().isOk()); | |
431 | 462 | } |
432 | - | |
463 | + | |
433 | 464 | pageLink = new TextPageLink(4, email1); |
434 | - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
435 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
465 | + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
466 | + new TypeReference<TextPageData<User>>() { | |
467 | + }, pageLink); | |
436 | 468 | Assert.assertFalse(pageData.hasNext()); |
437 | 469 | Assert.assertEquals(0, pageData.getData().size()); |
438 | - | |
470 | + | |
439 | 471 | for (User user : loadedTenantAdminsEmail2) { |
440 | - doDelete("/api/user/"+user.getId().getId().toString()) | |
441 | - .andExpect(status().isOk()); | |
472 | + doDelete("/api/user/" + user.getId().getId().toString()) | |
473 | + .andExpect(status().isOk()); | |
442 | 474 | } |
443 | - | |
475 | + | |
444 | 476 | pageLink = new TextPageLink(4, email2); |
445 | - pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
446 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
477 | + pageData = doGetTypedWithPageLink("/api/tenant/" + tenantId.getId().toString() + "/users?", | |
478 | + new TypeReference<TextPageData<User>>() { | |
479 | + }, pageLink); | |
447 | 480 | Assert.assertFalse(pageData.hasNext()); |
448 | 481 | Assert.assertEquals(0, pageData.getData().size()); |
449 | - | |
450 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
451 | - .andExpect(status().isOk()); | |
482 | + | |
483 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
484 | + .andExpect(status().isOk()); | |
452 | 485 | } |
453 | - | |
486 | + | |
454 | 487 | @Test |
455 | 488 | public void testFindCustomerUsers() throws Exception { |
456 | - | |
489 | + | |
457 | 490 | loginSysAdmin(); |
458 | 491 | Tenant tenant = new Tenant(); |
459 | 492 | tenant.setTitle("My tenant"); |
460 | 493 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
461 | 494 | Assert.assertNotNull(savedTenant); |
462 | - | |
495 | + | |
463 | 496 | TenantId tenantId = savedTenant.getId(); |
464 | 497 | User tenantAdmin = new User(); |
465 | 498 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -467,59 +500,60 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
467 | 500 | tenantAdmin.setEmail("tenant2@thingsboard.org"); |
468 | 501 | tenantAdmin.setFirstName("Joe"); |
469 | 502 | tenantAdmin.setLastName("Downs"); |
470 | - | |
503 | + | |
471 | 504 | tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
472 | - | |
505 | + | |
473 | 506 | Customer customer = new Customer(); |
474 | 507 | customer.setTitle("My customer"); |
475 | 508 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
476 | 509 | |
477 | 510 | CustomerId customerId = savedCustomer.getId(); |
478 | - | |
511 | + | |
479 | 512 | List<User> customerUsers = new ArrayList<>(); |
480 | - for (int i=0;i<56;i++) { | |
513 | + for (int i = 0; i < 56; i++) { | |
481 | 514 | User user = new User(); |
482 | 515 | user.setAuthority(Authority.CUSTOMER_USER); |
483 | 516 | user.setCustomerId(customerId); |
484 | 517 | user.setEmail("testCustomer" + i + "@thingsboard.org"); |
485 | 518 | customerUsers.add(doPost("/api/user", user, User.class)); |
486 | 519 | } |
487 | - | |
520 | + | |
488 | 521 | List<User> loadedCustomerUsers = new ArrayList<>(); |
489 | 522 | TextPageLink pageLink = new TextPageLink(33); |
490 | 523 | TextPageData<User> pageData = null; |
491 | 524 | do { |
492 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
493 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
525 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
526 | + new TypeReference<TextPageData<User>>() { | |
527 | + }, pageLink); | |
494 | 528 | loadedCustomerUsers.addAll(pageData.getData()); |
495 | 529 | if (pageData.hasNext()) { |
496 | 530 | pageLink = pageData.getNextPageLink(); |
497 | 531 | } |
498 | 532 | } while (pageData.hasNext()); |
499 | - | |
533 | + | |
500 | 534 | Collections.sort(customerUsers, idComparator); |
501 | 535 | Collections.sort(loadedCustomerUsers, idComparator); |
502 | - | |
536 | + | |
503 | 537 | Assert.assertEquals(customerUsers, loadedCustomerUsers); |
504 | - | |
505 | - doDelete("/api/customer/"+customerId.getId().toString()) | |
506 | - .andExpect(status().isOk()); | |
507 | - | |
538 | + | |
539 | + doDelete("/api/customer/" + customerId.getId().toString()) | |
540 | + .andExpect(status().isOk()); | |
541 | + | |
508 | 542 | loginSysAdmin(); |
509 | - | |
510 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
511 | - .andExpect(status().isOk()); | |
543 | + | |
544 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
545 | + .andExpect(status().isOk()); | |
512 | 546 | } |
513 | - | |
547 | + | |
514 | 548 | @Test |
515 | 549 | public void testFindCustomerUsersByEmail() throws Exception { |
516 | - | |
550 | + | |
517 | 551 | loginSysAdmin(); |
518 | 552 | Tenant tenant = new Tenant(); |
519 | 553 | tenant.setTitle("My tenant"); |
520 | 554 | Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
521 | 555 | Assert.assertNotNull(savedTenant); |
522 | - | |
556 | + | |
523 | 557 | TenantId tenantId = savedTenant.getId(); |
524 | 558 | User tenantAdmin = new User(); |
525 | 559 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
... | ... | @@ -527,105 +561,109 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { |
527 | 561 | tenantAdmin.setEmail("tenant2@thingsboard.org"); |
528 | 562 | tenantAdmin.setFirstName("Joe"); |
529 | 563 | tenantAdmin.setLastName("Downs"); |
530 | - | |
564 | + | |
531 | 565 | tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
532 | - | |
566 | + | |
533 | 567 | Customer customer = new Customer(); |
534 | 568 | customer.setTitle("My customer"); |
535 | 569 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
536 | 570 | |
537 | 571 | CustomerId customerId = savedCustomer.getId(); |
538 | - | |
539 | - String email1 = "testEmail1"; | |
572 | + | |
573 | + String email1 = "testEmail1"; | |
540 | 574 | List<User> customerUsersEmail1 = new ArrayList<>(); |
541 | - | |
542 | - for (int i=0;i<74;i++) { | |
575 | + | |
576 | + for (int i = 0; i < 74; i++) { | |
543 | 577 | User user = new User(); |
544 | 578 | user.setAuthority(Authority.CUSTOMER_USER); |
545 | 579 | user.setCustomerId(customerId); |
546 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); | |
547 | - String email = email1+suffix+ "@thingsboard.org"; | |
580 | + String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)); | |
581 | + String email = email1 + suffix + "@thingsboard.org"; | |
548 | 582 | email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); |
549 | 583 | user.setEmail(email); |
550 | 584 | customerUsersEmail1.add(doPost("/api/user", user, User.class)); |
551 | 585 | } |
552 | - | |
553 | - String email2 = "testEmail2"; | |
586 | + | |
587 | + String email2 = "testEmail2"; | |
554 | 588 | List<User> customerUsersEmail2 = new ArrayList<>(); |
555 | - | |
556 | - for (int i=0;i<92;i++) { | |
589 | + | |
590 | + for (int i = 0; i < 92; i++) { | |
557 | 591 | User user = new User(); |
558 | 592 | user.setAuthority(Authority.CUSTOMER_USER); |
559 | 593 | user.setCustomerId(customerId); |
560 | - String suffix = RandomStringUtils.randomAlphanumeric((int)(5 + Math.random()*10)); | |
561 | - String email = email2+suffix+ "@thingsboard.org"; | |
594 | + String suffix = RandomStringUtils.randomAlphanumeric((int) (5 + Math.random() * 10)); | |
595 | + String email = email2 + suffix + "@thingsboard.org"; | |
562 | 596 | email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); |
563 | 597 | user.setEmail(email); |
564 | 598 | customerUsersEmail2.add(doPost("/api/user", user, User.class)); |
565 | 599 | } |
566 | - | |
600 | + | |
567 | 601 | List<User> loadedCustomerUsersEmail1 = new ArrayList<>(); |
568 | 602 | TextPageLink pageLink = new TextPageLink(33, email1); |
569 | 603 | TextPageData<User> pageData = null; |
570 | 604 | do { |
571 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
572 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
605 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
606 | + new TypeReference<TextPageData<User>>() { | |
607 | + }, pageLink); | |
573 | 608 | loadedCustomerUsersEmail1.addAll(pageData.getData()); |
574 | 609 | if (pageData.hasNext()) { |
575 | 610 | pageLink = pageData.getNextPageLink(); |
576 | 611 | } |
577 | 612 | } while (pageData.hasNext()); |
578 | - | |
613 | + | |
579 | 614 | Collections.sort(customerUsersEmail1, idComparator); |
580 | 615 | Collections.sort(loadedCustomerUsersEmail1, idComparator); |
581 | - | |
616 | + | |
582 | 617 | Assert.assertEquals(customerUsersEmail1, loadedCustomerUsersEmail1); |
583 | - | |
618 | + | |
584 | 619 | List<User> loadedCustomerUsersEmail2 = new ArrayList<>(); |
585 | 620 | pageLink = new TextPageLink(16, email2); |
586 | 621 | do { |
587 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
588 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
622 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
623 | + new TypeReference<TextPageData<User>>() { | |
624 | + }, pageLink); | |
589 | 625 | loadedCustomerUsersEmail2.addAll(pageData.getData()); |
590 | 626 | if (pageData.hasNext()) { |
591 | 627 | pageLink = pageData.getNextPageLink(); |
592 | 628 | } |
593 | 629 | } while (pageData.hasNext()); |
594 | - | |
630 | + | |
595 | 631 | Collections.sort(customerUsersEmail2, idComparator); |
596 | 632 | Collections.sort(loadedCustomerUsersEmail2, idComparator); |
597 | - | |
633 | + | |
598 | 634 | Assert.assertEquals(customerUsersEmail2, loadedCustomerUsersEmail2); |
599 | - | |
635 | + | |
600 | 636 | for (User user : loadedCustomerUsersEmail1) { |
601 | - doDelete("/api/user/"+user.getId().getId().toString()) | |
602 | - .andExpect(status().isOk()); | |
637 | + doDelete("/api/user/" + user.getId().getId().toString()) | |
638 | + .andExpect(status().isOk()); | |
603 | 639 | } |
604 | - | |
640 | + | |
605 | 641 | pageLink = new TextPageLink(4, email1); |
606 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
607 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
642 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
643 | + new TypeReference<TextPageData<User>>() { | |
644 | + }, pageLink); | |
608 | 645 | Assert.assertFalse(pageData.hasNext()); |
609 | 646 | Assert.assertEquals(0, pageData.getData().size()); |
610 | - | |
647 | + | |
611 | 648 | for (User user : loadedCustomerUsersEmail2) { |
612 | - doDelete("/api/user/"+user.getId().getId().toString()) | |
613 | - .andExpect(status().isOk()); | |
649 | + doDelete("/api/user/" + user.getId().getId().toString()) | |
650 | + .andExpect(status().isOk()); | |
614 | 651 | } |
615 | - | |
652 | + | |
616 | 653 | pageLink = new TextPageLink(4, email2); |
617 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
618 | - new TypeReference<TextPageData<User>>(){}, pageLink); | |
654 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/users?", | |
655 | + new TypeReference<TextPageData<User>>() { | |
656 | + }, pageLink); | |
619 | 657 | Assert.assertFalse(pageData.hasNext()); |
620 | 658 | Assert.assertEquals(0, pageData.getData().size()); |
621 | - | |
622 | - doDelete("/api/customer/"+customerId.getId().toString()) | |
623 | - .andExpect(status().isOk()); | |
624 | - | |
659 | + | |
660 | + doDelete("/api/customer/" + customerId.getId().toString()) | |
661 | + .andExpect(status().isOk()); | |
662 | + | |
625 | 663 | loginSysAdmin(); |
626 | - | |
627 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | |
628 | - .andExpect(status().isOk()); | |
664 | + | |
665 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | |
666 | + .andExpect(status().isOk()); | |
629 | 667 | } |
630 | - | |
668 | + | |
631 | 669 | } | ... | ... |
... | ... | @@ -64,7 +64,6 @@ public abstract class BaseWidgetTypeControllerTest extends AbstractControllerTes |
64 | 64 | WidgetsBundle widgetsBundle = new WidgetsBundle(); |
65 | 65 | widgetsBundle.setTitle("My widgets bundle"); |
66 | 66 | savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class); |
67 | - | |
68 | 67 | } |
69 | 68 | |
70 | 69 | @After |
... | ... | @@ -101,6 +100,19 @@ public abstract class BaseWidgetTypeControllerTest extends AbstractControllerTes |
101 | 100 | } |
102 | 101 | |
103 | 102 | @Test |
103 | + public void testUpdateWidgetTypeFromDifferentTenant() throws Exception { | |
104 | + WidgetType widgetType = new WidgetType(); | |
105 | + widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); | |
106 | + widgetType.setName("Widget Type"); | |
107 | + widgetType.setDescriptor(new ObjectMapper().readValue("{ \"someKey\": \"someValue\" }", JsonNode.class)); | |
108 | + WidgetType savedWidgetType = doPost("/api/widgetType", widgetType, WidgetType.class); | |
109 | + | |
110 | + loginDifferentTenant(); | |
111 | + doPost("/api/widgetType", savedWidgetType, WidgetType.class, status().isForbidden()); | |
112 | + deleteDifferentTenant(); | |
113 | + } | |
114 | + | |
115 | + @Test | |
104 | 116 | public void testFindWidgetTypeById() throws Exception { |
105 | 117 | WidgetType widgetType = new WidgetType(); |
106 | 118 | widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); | ... | ... |
... | ... | @@ -89,6 +89,17 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController |
89 | 89 | } |
90 | 90 | |
91 | 91 | @Test |
92 | + public void testUpdateWidgetsBundleFromDifferentTenant() throws Exception { | |
93 | + WidgetsBundle widgetsBundle = new WidgetsBundle(); | |
94 | + widgetsBundle.setTitle("My widgets bundle"); | |
95 | + WidgetsBundle savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class); | |
96 | + | |
97 | + loginDifferentTenant(); | |
98 | + doPost("/api/widgetsBundle", savedWidgetsBundle, WidgetsBundle.class, status().isForbidden()); | |
99 | + deleteDifferentTenant(); | |
100 | + } | |
101 | + | |
102 | + @Test | |
92 | 103 | public void testFindWidgetsBundleById() throws Exception { |
93 | 104 | WidgetsBundle widgetsBundle = new WidgetsBundle(); |
94 | 105 | widgetsBundle.setTitle("My widgets bundle"); | ... | ... |
application/src/test/java/org/thingsboard/server/rules/RuleEngineNoSqlTestSuite.java
deleted
100644 → 0
1 | -/** | |
2 | - * Copyright © 2016-2020 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.rules; | |
17 | - | |
18 | -import org.cassandraunit.dataset.cql.ClassPathCQLDataSet; | |
19 | -import org.junit.BeforeClass; | |
20 | -import org.junit.ClassRule; | |
21 | -import org.junit.extensions.cpsuite.ClasspathSuite; | |
22 | -import org.junit.runner.RunWith; | |
23 | -import org.thingsboard.server.dao.CustomCassandraCQLUnit; | |
24 | -import org.thingsboard.server.dao.CustomSqlUnit; | |
25 | -import org.thingsboard.server.queue.memory.InMemoryStorage; | |
26 | - | |
27 | -import java.util.Arrays; | |
28 | - | |
29 | -@RunWith(ClasspathSuite.class) | |
30 | -@ClasspathSuite.ClassnameFilters({ | |
31 | - "org.thingsboard.server.rules.flow.nosql.*Test", | |
32 | - "org.thingsboard.server.rules.lifecycle.nosql.*Test" | |
33 | -}) | |
34 | -public class RuleEngineNoSqlTestSuite { | |
35 | - | |
36 | - @ClassRule | |
37 | - public static CustomCassandraCQLUnit cassandraUnit = | |
38 | - new CustomCassandraCQLUnit( | |
39 | - Arrays.asList( | |
40 | - new ClassPathCQLDataSet("cassandra/schema-ts.cql", false, false), | |
41 | - new ClassPathCQLDataSet("cassandra/schema-entities.cql", false, false), | |
42 | - new ClassPathCQLDataSet("cassandra/system-data.cql", false, false)), | |
43 | - "cassandra-test.yaml", 30000l); | |
44 | - | |
45 | - @BeforeClass | |
46 | - public static void cleanupInMemStorage(){ | |
47 | - InMemoryStorage.getInstance().cleanup(); | |
48 | - } | |
49 | - | |
50 | -} |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -40,6 +40,7 @@ import java.util.UUID; |
40 | 40 | public final class TbMsg implements Serializable { |
41 | 41 | |
42 | 42 | private final UUID id; |
43 | + private final long ts; | |
43 | 44 | private final String type; |
44 | 45 | private final EntityId originator; |
45 | 46 | private final TbMsgMetaData metaData; |
... | ... | @@ -51,38 +52,43 @@ public final class TbMsg implements Serializable { |
51 | 52 | transient private final TbMsgCallback callback; |
52 | 53 | |
53 | 54 | public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { |
54 | - return new TbMsg(UUID.randomUUID(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, TbMsgCallback.EMPTY); | |
55 | + return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, TbMsgCallback.EMPTY); | |
55 | 56 | } |
56 | 57 | |
57 | 58 | public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { |
58 | - return new TbMsg(UUID.randomUUID(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); | |
59 | + return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); | |
59 | 60 | } |
60 | 61 | |
61 | 62 | public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { |
62 | - return new TbMsg(UUID.randomUUID(), type, originator, metaData.copy(), dataType, data, null, null, TbMsgCallback.EMPTY); | |
63 | + return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, null, null, TbMsgCallback.EMPTY); | |
63 | 64 | } |
64 | 65 | |
65 | 66 | public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { |
66 | - return new TbMsg(UUID.randomUUID(), type, originator, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); | |
67 | + return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), dataType, data, ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); | |
67 | 68 | } |
68 | 69 | |
69 | 70 | public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { |
70 | - return new TbMsg(UUID.randomUUID(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, callback); | |
71 | + return new TbMsg(UUID.randomUUID(), System.currentTimeMillis(), type, originator, metaData.copy(), TbMsgDataType.JSON, data, null, null, callback); | |
71 | 72 | } |
72 | 73 | |
73 | 74 | public static TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { |
74 | - return new TbMsg(origMsg.getId(), type, originator, metaData.copy(), origMsg.getDataType(), | |
75 | + return new TbMsg(origMsg.getId(), origMsg.getTs(), type, originator, metaData.copy(), origMsg.getDataType(), | |
75 | 76 | data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), origMsg.getCallback()); |
76 | 77 | } |
77 | 78 | |
78 | 79 | public static TbMsg newMsg(TbMsg tbMsg, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { |
79 | - return new TbMsg(UUID.randomUUID(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(), | |
80 | + return new TbMsg(UUID.randomUUID(), tbMsg.getTs(), tbMsg.getType(), tbMsg.getOriginator(), tbMsg.getMetaData().copy(), | |
80 | 81 | tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); |
81 | 82 | } |
82 | 83 | |
83 | - private TbMsg(UUID id, String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, | |
84 | + private TbMsg(UUID id, long ts, String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, | |
84 | 85 | RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgCallback callback) { |
85 | 86 | this.id = id; |
87 | + if (ts > 0) { | |
88 | + this.ts = ts; | |
89 | + } else { | |
90 | + this.ts = System.currentTimeMillis(); | |
91 | + } | |
86 | 92 | this.type = type; |
87 | 93 | this.originator = originator; |
88 | 94 | this.metaData = metaData; |
... | ... | @@ -105,6 +111,7 @@ public final class TbMsg implements Serializable { |
105 | 111 | public static byte[] toByteArray(TbMsg msg) { |
106 | 112 | MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); |
107 | 113 | builder.setId(msg.getId().toString()); |
114 | + builder.setTs(msg.getTs()); | |
108 | 115 | builder.setType(msg.getType()); |
109 | 116 | builder.setEntityType(msg.getOriginator().getEntityType().name()); |
110 | 117 | builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits()); |
... | ... | @@ -124,7 +131,6 @@ public final class TbMsg implements Serializable { |
124 | 131 | builder.setMetaData(MsgProtos.TbMsgMetaDataProto.newBuilder().putAllData(msg.getMetaData().getData()).build()); |
125 | 132 | } |
126 | 133 | |
127 | - | |
128 | 134 | builder.setDataType(msg.getDataType().ordinal()); |
129 | 135 | builder.setData(msg.getData()); |
130 | 136 | return builder.build().toByteArray(); |
... | ... | @@ -144,18 +150,18 @@ public final class TbMsg implements Serializable { |
144 | 150 | ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); |
145 | 151 | } |
146 | 152 | TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; |
147 | - return new TbMsg(UUID.fromString(proto.getId()), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, callback); | |
153 | + return new TbMsg(UUID.fromString(proto.getId()), proto.getTs(), proto.getType(), entityId, metaData, dataType, proto.getData(), ruleChainId, ruleNodeId, callback); | |
148 | 154 | } catch (InvalidProtocolBufferException e) { |
149 | 155 | throw new IllegalStateException("Could not parse protobuf for TbMsg", e); |
150 | 156 | } |
151 | 157 | } |
152 | 158 | |
153 | 159 | public TbMsg copyWithRuleChainId(RuleChainId ruleChainId) { |
154 | - return new TbMsg(this.id, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, callback); | |
160 | + return new TbMsg(this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, null, callback); | |
155 | 161 | } |
156 | 162 | |
157 | 163 | public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { |
158 | - return new TbMsg(this.id, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, callback); | |
164 | + return new TbMsg(this.id, this.ts, this.type, this.originator, this.metaData, this.dataType, this.data, ruleChainId, ruleNodeId, callback); | |
159 | 165 | } |
160 | 166 | |
161 | 167 | public TbMsgCallback getCallback() { | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>common</artifactId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -101,7 +101,7 @@ public class TbServiceBusConsumerTemplate<T extends TbQueueMsg> extends Abstract |
101 | 101 | @Override |
102 | 102 | protected void doSubscribe(List<String> topicNames) { |
103 | 103 | createReceivers(); |
104 | - messagesPerQueue = receivers.size() / partitions.size(); | |
104 | + messagesPerQueue = receivers.size() / Math.max(partitions.size(), 1); | |
105 | 105 | } |
106 | 106 | |
107 | 107 | @Override | ... | ... |
... | ... | @@ -85,7 +85,12 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i |
85 | 85 | subscribed = true; |
86 | 86 | } |
87 | 87 | |
88 | - List<R> records = doPoll(durationInMillis); | |
88 | + List<R> records; | |
89 | + if (partitions.isEmpty()) { | |
90 | + records = Collections.emptyList(); | |
91 | + } else { | |
92 | + records = doPoll(durationInMillis); | |
93 | + } | |
89 | 94 | if (!records.isEmpty()) { |
90 | 95 | List<T> result = new ArrayList<>(records.size()); |
91 | 96 | records.forEach(record -> { | ... | ... |
... | ... | @@ -36,6 +36,7 @@ import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
36 | 36 | import javax.annotation.PostConstruct; |
37 | 37 | import java.nio.charset.StandardCharsets; |
38 | 38 | import java.util.ArrayList; |
39 | +import java.util.Collections; | |
39 | 40 | import java.util.Comparator; |
40 | 41 | import java.util.HashMap; |
41 | 42 | import java.util.HashSet; |
... | ... | @@ -148,6 +149,14 @@ public class HashPartitionService implements PartitionService { |
148 | 149 | } |
149 | 150 | } |
150 | 151 | }); |
152 | + | |
153 | + oldPartitions.forEach((serviceQueueKey, partitions) -> { | |
154 | + if (!myPartitions.containsKey(serviceQueueKey)) { | |
155 | + log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", serviceQueueKey); | |
156 | + applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceQueueKey, Collections.emptySet())); | |
157 | + } | |
158 | + }); | |
159 | + | |
151 | 160 | myPartitions.forEach((serviceQueueKey, partitions) -> { |
152 | 161 | if (!partitions.equals(oldPartitions.get(serviceQueueKey))) { |
153 | 162 | log.info("[{}] NEW PARTITIONS: {}", serviceQueueKey, partitions); | ... | ... |
... | ... | @@ -71,8 +71,12 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue |
71 | 71 | |
72 | 72 | @Override |
73 | 73 | protected void doSubscribe(List<String> topicNames) { |
74 | - topicNames.forEach(admin::createTopicIfNotExists); | |
75 | - consumer.subscribe(topicNames); | |
74 | + if (!topicNames.isEmpty()) { | |
75 | + topicNames.forEach(admin::createTopicIfNotExists); | |
76 | + consumer.subscribe(topicNames); | |
77 | + } else { | |
78 | + consumer.unsubscribe(); | |
79 | + } | |
76 | 80 | } |
77 | 81 | |
78 | 82 | @Override | ... | ... |
... | ... | @@ -200,7 +200,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi |
200 | 200 | consumerBuilder.settings(kafkaSettings); |
201 | 201 | consumerBuilder.topic(transportApiSettings.getRequestsTopic()); |
202 | 202 | consumerBuilder.clientId("monolith-transport-api-consumer-" + serviceInfoProvider.getServiceId()); |
203 | - consumerBuilder.groupId("monolith-transport-api-consumer-" + serviceInfoProvider.getServiceId()); | |
203 | + consumerBuilder.groupId("monolith-transport-api-consumer"); | |
204 | 204 | consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
205 | 205 | consumerBuilder.admin(transportApiAdmin); |
206 | 206 | return consumerBuilder.build(); | ... | ... |
... | ... | @@ -170,7 +170,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { |
170 | 170 | consumerBuilder.settings(kafkaSettings); |
171 | 171 | consumerBuilder.topic(transportApiSettings.getRequestsTopic()); |
172 | 172 | consumerBuilder.clientId("tb-core-transport-api-consumer-" + serviceInfoProvider.getServiceId()); |
173 | - consumerBuilder.groupId("tb-core-transport-api-consumer-" + serviceInfoProvider.getServiceId()); | |
173 | + consumerBuilder.groupId("tb-core-transport-api-consumer"); | |
174 | 174 | consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); |
175 | 175 | consumerBuilder.admin(transportApiAdmin); |
176 | 176 | return consumerBuilder.build(); | ... | ... |
... | ... | @@ -106,7 +106,7 @@ public class TbPubSubConsumerTemplate<T extends TbQueueMsg> extends AbstractPara |
106 | 106 | subscriptionNames = new LinkedHashSet<>(topicNames); |
107 | 107 | subscriptionNames.forEach(admin::createTopicIfNotExists); |
108 | 108 | initNewExecutor(subscriptionNames.size() + 1); |
109 | - messagesPerTopic = pubSubSettings.getMaxMessages() / subscriptionNames.size(); | |
109 | + messagesPerTopic = pubSubSettings.getMaxMessages() / Math.max(subscriptionNames.size(), 1); | |
110 | 110 | } |
111 | 111 | |
112 | 112 | @Override | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> | ... | ... |
... | ... | @@ -294,7 +294,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement |
294 | 294 | break; |
295 | 295 | } |
296 | 296 | } catch (Exception e) { |
297 | - log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS); | |
297 | + log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS, e); | |
298 | 298 | grantedQoSList.add(FAILURE.value()); |
299 | 299 | } |
300 | 300 | } | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>transport</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common.transport</groupId> |
... | ... | @@ -53,10 +53,6 @@ |
53 | 53 | <artifactId>util</artifactId> |
54 | 54 | </dependency> |
55 | 55 | <dependency> |
56 | - <groupId>org.thingsboard.common</groupId> | |
57 | - <artifactId>queue</artifactId> | |
58 | - </dependency> | |
59 | - <dependency> | |
60 | 56 | <groupId>com.google.code.gson</groupId> |
61 | 57 | <artifactId>gson</artifactId> |
62 | 58 | </dependency> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>common</artifactId> |
25 | 25 | </parent> |
26 | 26 | <groupId>org.thingsboard.common</groupId> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <modelVersion>4.0.0</modelVersion> |
21 | 21 | <parent> |
22 | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.0-SNAPSHOT</version> | |
23 | + <version>2.5.1-SNAPSHOT</version> | |
24 | 24 | <artifactId>thingsboard</artifactId> |
25 | 25 | </parent> |
26 | 26 | <artifactId>dao</artifactId> | ... | ... |
... | ... | @@ -112,7 +112,7 @@ public class EventEntity extends BaseSqlEntity<Event> implements BaseEntity<Eve |
112 | 112 | return event; |
113 | 113 | } |
114 | 114 | |
115 | - private long getTs(UUID uuid) { | |
115 | + private static long getTs(UUID uuid) { | |
116 | 116 | return (uuid.timestamp() - EPOCH_DIFF) / 10000; |
117 | 117 | } |
118 | 118 | } | ... | ... |
... | ... | @@ -34,6 +34,8 @@ public class OAuth2ClientMapperConfig { |
34 | 34 | private String tenantNameStrategy; |
35 | 35 | private String tenantNamePattern; |
36 | 36 | private String customerNamePattern; |
37 | + private boolean alwaysFullScreen; | |
38 | + private String defaultDashboardName; | |
37 | 39 | } |
38 | 40 | |
39 | 41 | @Data | ... | ... |
... | ... | @@ -90,7 +90,7 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa |
90 | 90 | } |
91 | 91 | |
92 | 92 | private void savePartitionIfNotExist(long ts) { |
93 | - if (!tsFormat.equals(SqlTsPartitionDate.INDEFINITE)) { | |
93 | + if (!tsFormat.equals(SqlTsPartitionDate.INDEFINITE) && ts >= 0) { | |
94 | 94 | LocalDateTime time = LocalDateTime.ofInstant(Instant.ofEpochMilli(ts), ZoneOffset.UTC); |
95 | 95 | LocalDateTime localDateTimeStart = tsFormat.trancateTo(time); |
96 | 96 | long partitionStartTs = toMills(localDateTimeStart); | ... | ... |
... | ... | @@ -52,7 +52,7 @@ CREATE TABLE IF NOT EXISTS tb_schema_settings |
52 | 52 | CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) |
53 | 53 | ); |
54 | 54 | |
55 | -INSERT INTO tb_schema_settings (schema_version) VALUES (2005000) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 2005000; | |
55 | +INSERT INTO tb_schema_settings (schema_version) VALUES (2005001) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 2005001; | |
56 | 56 | |
57 | 57 | CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS |
58 | 58 | $$ | ... | ... |
... | ... | @@ -53,7 +53,7 @@ CREATE TABLE IF NOT EXISTS tb_schema_settings |
53 | 53 | CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) |
54 | 54 | ); |
55 | 55 | |
56 | -INSERT INTO tb_schema_settings (schema_version) VALUES (2005000) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 2005000; | |
56 | +INSERT INTO tb_schema_settings (schema_version) VALUES (2005001) ON CONFLICT (schema_version) DO UPDATE SET schema_version = 2005001; | |
57 | 57 | |
58 | 58 | CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint) |
59 | 59 | LANGUAGE plpgsql AS | ... | ... |
... | ... | @@ -32,6 +32,32 @@ function additionalComposeArgs() { |
32 | 32 | echo $ADDITIONAL_COMPOSE_ARGS |
33 | 33 | } |
34 | 34 | |
35 | +function additionalComposeQueueArgs() { | |
36 | + source .env | |
37 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="" | |
38 | + case $TB_QUEUE_TYPE in | |
39 | + kafka) | |
40 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.kafka.yml" | |
41 | + ;; | |
42 | + aws-sqs) | |
43 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.aws-sqs.yml" | |
44 | + ;; | |
45 | + pubsub) | |
46 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.pubsub.yml" | |
47 | + ;; | |
48 | + rabbitmq) | |
49 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.rabbitmq.yml" | |
50 | + ;; | |
51 | + service-bus) | |
52 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.service-bus.yml" | |
53 | + ;; | |
54 | + *) | |
55 | + echo "Unknown Queue service value specified: '${TB_QUEUE_TYPE}'. Should be either kafka or aws-sqs or pubsub or rabbitmq or service-bus." >&2 | |
56 | + exit 1 | |
57 | + esac | |
58 | + echo $ADDITIONAL_COMPOSE_QUEUE_ARGS | |
59 | +} | |
60 | + | |
35 | 61 | function additionalStartupServices() { |
36 | 62 | source .env |
37 | 63 | ADDITIONAL_STARTUP_SERVICES="" | ... | ... |
docker/docker-compose.aws-sqs.yml
0 → 100644
1 | +# | |
2 | +# Copyright © 2016-2020 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 | + | |
17 | +version: '2.2' | |
18 | + | |
19 | +services: | |
20 | + tb-js-executor: | |
21 | + env_file: | |
22 | + - queue-aws-sqs.env | |
23 | + tb-core1: | |
24 | + env_file: | |
25 | + - queue-aws-sqs.env | |
26 | + depends_on: | |
27 | + - zookeeper | |
28 | + - redis | |
29 | + tb-core2: | |
30 | + env_file: | |
31 | + - queue-aws-sqs.env | |
32 | + depends_on: | |
33 | + - zookeeper | |
34 | + - redis | |
35 | + tb-rule-engine1: | |
36 | + env_file: | |
37 | + - queue-aws-sqs.env | |
38 | + depends_on: | |
39 | + - zookeeper | |
40 | + - redis | |
41 | + tb-rule-engine2: | |
42 | + env_file: | |
43 | + - queue-aws-sqs.env | |
44 | + depends_on: | |
45 | + - zookeeper | |
46 | + - redis | |
47 | + tb-mqtt-transport1: | |
48 | + env_file: | |
49 | + - queue-aws-sqs.env | |
50 | + depends_on: | |
51 | + - zookeeper | |
52 | + tb-mqtt-transport2: | |
53 | + env_file: | |
54 | + - queue-aws-sqs.env | |
55 | + depends_on: | |
56 | + - zookeeper | |
57 | + tb-http-transport1: | |
58 | + env_file: | |
59 | + - queue-aws-sqs.env | |
60 | + depends_on: | |
61 | + - zookeeper | |
62 | + tb-http-transport2: | |
63 | + env_file: | |
64 | + - queue-aws-sqs.env | |
65 | + depends_on: | |
66 | + - zookeeper | |
67 | + tb-coap-transport: | |
68 | + env_file: | |
69 | + - queue-aws-sqs.env | |
70 | + depends_on: | |
71 | + - zookeeper | |
\ No newline at end of file | ... | ... |
... | ... | @@ -28,27 +28,27 @@ services: |
28 | 28 | env_file: |
29 | 29 | - tb-node.cassandra.env |
30 | 30 | depends_on: |
31 | - - kafka | |
31 | + - zookeeper | |
32 | 32 | - redis |
33 | 33 | - cassandra |
34 | 34 | tb-core2: |
35 | 35 | env_file: |
36 | 36 | - tb-node.cassandra.env |
37 | 37 | depends_on: |
38 | - - kafka | |
38 | + - zookeeper | |
39 | 39 | - redis |
40 | 40 | - cassandra |
41 | 41 | tb-rule-engine1: |
42 | 42 | env_file: |
43 | 43 | - tb-node.cassandra.env |
44 | 44 | depends_on: |
45 | - - kafka | |
45 | + - zookeeper | |
46 | 46 | - redis |
47 | 47 | - cassandra |
48 | 48 | tb-rule-engine2: |
49 | 49 | env_file: |
50 | 50 | - tb-node.cassandra.env |
51 | 51 | depends_on: |
52 | - - kafka | |
52 | + - zookeeper | |
53 | 53 | - redis |
54 | 54 | - cassandra | ... | ... |
docker/docker-compose.kafka.yml
0 → 100644
1 | +# | |
2 | +# Copyright © 2016-2020 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 | + | |
17 | +version: '2.2' | |
18 | + | |
19 | +services: | |
20 | + kafka: | |
21 | + restart: always | |
22 | + image: "wurstmeister/kafka:2.12-2.3.0" | |
23 | + ports: | |
24 | + - "9092:9092" | |
25 | + env_file: | |
26 | + - kafka.env | |
27 | + depends_on: | |
28 | + - zookeeper | |
29 | + tb-js-executor: | |
30 | + env_file: | |
31 | + - queue-kafka.env | |
32 | + depends_on: | |
33 | + - kafka | |
34 | + tb-core1: | |
35 | + env_file: | |
36 | + - queue-kafka.env | |
37 | + depends_on: | |
38 | + - kafka | |
39 | + - redis | |
40 | + tb-core2: | |
41 | + env_file: | |
42 | + - queue-kafka.env | |
43 | + depends_on: | |
44 | + - kafka | |
45 | + - redis | |
46 | + tb-rule-engine1: | |
47 | + env_file: | |
48 | + - queue-kafka.env | |
49 | + depends_on: | |
50 | + - kafka | |
51 | + - redis | |
52 | + tb-rule-engine2: | |
53 | + env_file: | |
54 | + - queue-kafka.env | |
55 | + depends_on: | |
56 | + - kafka | |
57 | + - redis | |
58 | + tb-mqtt-transport1: | |
59 | + env_file: | |
60 | + - queue-kafka.env | |
61 | + depends_on: | |
62 | + - kafka | |
63 | + tb-mqtt-transport2: | |
64 | + env_file: | |
65 | + - queue-kafka.env | |
66 | + depends_on: | |
67 | + - kafka | |
68 | + tb-http-transport1: | |
69 | + env_file: | |
70 | + - queue-kafka.env | |
71 | + depends_on: | |
72 | + - kafka | |
73 | + tb-http-transport2: | |
74 | + env_file: | |
75 | + - queue-kafka.env | |
76 | + depends_on: | |
77 | + - kafka | |
78 | + tb-coap-transport: | |
79 | + env_file: | |
80 | + - queue-kafka.env | |
81 | + depends_on: | |
82 | + - kafka | ... | ... |
... | ... | @@ -31,27 +31,27 @@ services: |
31 | 31 | env_file: |
32 | 32 | - tb-node.postgres.env |
33 | 33 | depends_on: |
34 | - - kafka | |
34 | + - zookeeper | |
35 | 35 | - redis |
36 | 36 | - postgres |
37 | 37 | tb-core2: |
38 | 38 | env_file: |
39 | 39 | - tb-node.postgres.env |
40 | 40 | depends_on: |
41 | - - kafka | |
41 | + - zookeeper | |
42 | 42 | - redis |
43 | 43 | - postgres |
44 | 44 | tb-rule-engine1: |
45 | 45 | env_file: |
46 | 46 | - tb-node.postgres.env |
47 | 47 | depends_on: |
48 | - - kafka | |
48 | + - zookeeper | |
49 | 49 | - redis |
50 | 50 | - postgres |
51 | 51 | tb-rule-engine2: |
52 | 52 | env_file: |
53 | 53 | - tb-node.postgres.env |
54 | 54 | depends_on: |
55 | - - kafka | |
55 | + - zookeeper | |
56 | 56 | - redis |
57 | 57 | - postgres | ... | ... |
docker/docker-compose.pubsub.yml
0 → 100644
1 | +# | |
2 | +# Copyright © 2016-2020 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 | + | |
17 | +version: '2.2' | |
18 | + | |
19 | +services: | |
20 | + tb-js-executor: | |
21 | + env_file: | |
22 | + - queue-pubsub.env | |
23 | + tb-core1: | |
24 | + env_file: | |
25 | + - queue-pubsub.env | |
26 | + depends_on: | |
27 | + - zookeeper | |
28 | + - redis | |
29 | + tb-core2: | |
30 | + env_file: | |
31 | + - queue-pubsub.env | |
32 | + depends_on: | |
33 | + - zookeeper | |
34 | + - redis | |
35 | + tb-rule-engine1: | |
36 | + env_file: | |
37 | + - queue-pubsub.env | |
38 | + depends_on: | |
39 | + - zookeeper | |
40 | + - redis | |
41 | + tb-rule-engine2: | |
42 | + env_file: | |
43 | + - queue-pubsub.env | |
44 | + depends_on: | |
45 | + - zookeeper | |
46 | + - redis | |
47 | + tb-mqtt-transport1: | |
48 | + env_file: | |
49 | + - queue-pubsub.env | |
50 | + depends_on: | |
51 | + - zookeeper | |
52 | + tb-mqtt-transport2: | |
53 | + env_file: | |
54 | + - queue-pubsub.env | |
55 | + depends_on: | |
56 | + - zookeeper | |
57 | + tb-http-transport1: | |
58 | + env_file: | |
59 | + - queue-pubsub.env | |
60 | + depends_on: | |
61 | + - zookeeper | |
62 | + tb-http-transport2: | |
63 | + env_file: | |
64 | + - queue-pubsub.env | |
65 | + depends_on: | |
66 | + - zookeeper | |
67 | + tb-coap-transport: | |
68 | + env_file: | |
69 | + - queue-pubsub.env | |
70 | + depends_on: | |
71 | + - zookeeper | ... | ... |
docker/docker-compose.rabbitmq.yml
0 → 100644
1 | +# | |
2 | +# Copyright © 2016-2020 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 | + | |
17 | +version: '2.2' | |
18 | + | |
19 | +services: | |
20 | + tb-js-executor: | |
21 | + env_file: | |
22 | + - queue-rabbitmq.env | |
23 | + tb-core1: | |
24 | + env_file: | |
25 | + - queue-rabbitmq.env | |
26 | + depends_on: | |
27 | + - zookeeper | |
28 | + - redis | |
29 | + tb-core2: | |
30 | + env_file: | |
31 | + - queue-rabbitmq.env | |
32 | + depends_on: | |
33 | + - zookeeper | |
34 | + - redis | |
35 | + tb-rule-engine1: | |
36 | + env_file: | |
37 | + - queue-rabbitmq.env | |
38 | + depends_on: | |
39 | + - zookeeper | |
40 | + - redis | |
41 | + tb-rule-engine2: | |
42 | + env_file: | |
43 | + - queue-rabbitmq.env | |
44 | + depends_on: | |
45 | + - zookeeper | |
46 | + - redis | |
47 | + tb-mqtt-transport1: | |
48 | + env_file: | |
49 | + - queue-rabbitmq.env | |
50 | + depends_on: | |
51 | + - zookeeper | |
52 | + tb-mqtt-transport2: | |
53 | + env_file: | |
54 | + - queue-rabbitmq.env | |
55 | + depends_on: | |
56 | + - zookeeper | |
57 | + tb-http-transport1: | |
58 | + env_file: | |
59 | + - queue-rabbitmq.env | |
60 | + depends_on: | |
61 | + - zookeeper | |
62 | + tb-http-transport2: | |
63 | + env_file: | |
64 | + - queue-rabbitmq.env | |
65 | + depends_on: | |
66 | + - zookeeper | |
67 | + tb-coap-transport: | |
68 | + env_file: | |
69 | + - queue-rabbitmq.env | |
70 | + depends_on: | |
71 | + - zookeeper | |
\ No newline at end of file | ... | ... |
docker/docker-compose.service-bus.yml
0 → 100644
1 | +# | |
2 | +# Copyright © 2016-2020 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 | + | |
17 | +version: '2.2' | |
18 | + | |
19 | +services: | |
20 | + tb-js-executor: | |
21 | + env_file: | |
22 | + - queue-service-bus.env | |
23 | + tb-core1: | |
24 | + env_file: | |
25 | + - queue-service-bus.env | |
26 | + depends_on: | |
27 | + - zookeeper | |
28 | + - redis | |
29 | + tb-core2: | |
30 | + env_file: | |
31 | + - queue-service-bus.env | |
32 | + depends_on: | |
33 | + - zookeeper | |
34 | + - redis | |
35 | + tb-rule-engine1: | |
36 | + env_file: | |
37 | + - queue-service-bus.env | |
38 | + depends_on: | |
39 | + - zookeeper | |
40 | + - redis | |
41 | + tb-rule-engine2: | |
42 | + env_file: | |
43 | + - queue-service-bus.env | |
44 | + depends_on: | |
45 | + - zookeeper | |
46 | + - redis | |
47 | + tb-mqtt-transport1: | |
48 | + env_file: | |
49 | + - queue-service-bus.env | |
50 | + depends_on: | |
51 | + - zookeeper | |
52 | + tb-mqtt-transport2: | |
53 | + env_file: | |
54 | + - queue-service-bus.env | |
55 | + depends_on: | |
56 | + - zookeeper | |
57 | + tb-http-transport1: | |
58 | + env_file: | |
59 | + - queue-service-bus.env | |
60 | + depends_on: | |
61 | + - zookeeper | |
62 | + tb-http-transport2: | |
63 | + env_file: | |
64 | + - queue-service-bus.env | |
65 | + depends_on: | |
66 | + - zookeeper | |
67 | + tb-coap-transport: | |
68 | + env_file: | |
69 | + - queue-service-bus.env | |
70 | + depends_on: | |
71 | + - zookeeper | |
\ No newline at end of file | ... | ... |
... | ... | @@ -26,15 +26,6 @@ services: |
26 | 26 | environment: |
27 | 27 | ZOO_MY_ID: 1 |
28 | 28 | ZOO_SERVERS: server.1=zookeeper:2888:3888;zookeeper:2181 |
29 | - kafka: | |
30 | - restart: always | |
31 | - image: "wurstmeister/kafka:2.12-2.3.0" | |
32 | - ports: | |
33 | - - "9092:9092" | |
34 | - env_file: | |
35 | - - kafka.env | |
36 | - depends_on: | |
37 | - - zookeeper | |
38 | 29 | redis: |
39 | 30 | restart: always |
40 | 31 | image: redis:4.0 |
... | ... | @@ -46,8 +37,6 @@ services: |
46 | 37 | scale: 20 |
47 | 38 | env_file: |
48 | 39 | - tb-js-executor.env |
49 | - depends_on: | |
50 | - - kafka | |
51 | 40 | tb-core1: |
52 | 41 | restart: always |
53 | 42 | image: "${DOCKER_REPO}/${TB_NODE_DOCKER_NAME}:${TB_VERSION}" |
... | ... | @@ -67,7 +56,7 @@ services: |
67 | 56 | - ./tb-node/conf:/config |
68 | 57 | - ./tb-node/log:/var/log/thingsboard |
69 | 58 | depends_on: |
70 | - - kafka | |
59 | + - zookeeper | |
71 | 60 | - redis |
72 | 61 | - tb-js-executor |
73 | 62 | - tb-rule-engine1 |
... | ... | @@ -91,7 +80,7 @@ services: |
91 | 80 | - ./tb-node/conf:/config |
92 | 81 | - ./tb-node/log:/var/log/thingsboard |
93 | 82 | depends_on: |
94 | - - kafka | |
83 | + - zookeeper | |
95 | 84 | - redis |
96 | 85 | - tb-js-executor |
97 | 86 | - tb-rule-engine1 |
... | ... | @@ -115,7 +104,7 @@ services: |
115 | 104 | - ./tb-node/conf:/config |
116 | 105 | - ./tb-node/log:/var/log/thingsboard |
117 | 106 | depends_on: |
118 | - - kafka | |
107 | + - zookeeper | |
119 | 108 | - redis |
120 | 109 | - tb-js-executor |
121 | 110 | tb-rule-engine2: |
... | ... | @@ -137,7 +126,7 @@ services: |
137 | 126 | - ./tb-node/conf:/config |
138 | 127 | - ./tb-node/log:/var/log/thingsboard |
139 | 128 | depends_on: |
140 | - - kafka | |
129 | + - zookeeper | |
141 | 130 | - redis |
142 | 131 | - tb-js-executor |
143 | 132 | tb-mqtt-transport1: |
... | ... | @@ -153,7 +142,7 @@ services: |
153 | 142 | - ./tb-transports/mqtt/conf:/config |
154 | 143 | - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport |
155 | 144 | depends_on: |
156 | - - kafka | |
145 | + - zookeeper | |
157 | 146 | tb-mqtt-transport2: |
158 | 147 | restart: always |
159 | 148 | image: "${DOCKER_REPO}/${MQTT_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" |
... | ... | @@ -167,7 +156,7 @@ services: |
167 | 156 | - ./tb-transports/mqtt/conf:/config |
168 | 157 | - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport |
169 | 158 | depends_on: |
170 | - - kafka | |
159 | + - zookeeper | |
171 | 160 | tb-http-transport1: |
172 | 161 | restart: always |
173 | 162 | image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" |
... | ... | @@ -181,7 +170,7 @@ services: |
181 | 170 | - ./tb-transports/http/conf:/config |
182 | 171 | - ./tb-transports/http/log:/var/log/tb-http-transport |
183 | 172 | depends_on: |
184 | - - kafka | |
173 | + - zookeeper | |
185 | 174 | tb-http-transport2: |
186 | 175 | restart: always |
187 | 176 | image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" |
... | ... | @@ -195,7 +184,7 @@ services: |
195 | 184 | - ./tb-transports/http/conf:/config |
196 | 185 | - ./tb-transports/http/log:/var/log/tb-http-transport |
197 | 186 | depends_on: |
198 | - - kafka | |
187 | + - zookeeper | |
199 | 188 | tb-coap-transport: |
200 | 189 | restart: always |
201 | 190 | image: "${DOCKER_REPO}/${COAP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" |
... | ... | @@ -209,7 +198,7 @@ services: |
209 | 198 | - ./tb-transports/coap/conf:/config |
210 | 199 | - ./tb-transports/coap/log:/var/log/tb-coap-transport |
211 | 200 | depends_on: |
212 | - - kafka | |
201 | + - zookeeper | |
213 | 202 | tb-web-ui1: |
214 | 203 | restart: always |
215 | 204 | image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}" | ... | ... |
... | ... | @@ -41,14 +41,16 @@ set -e |
41 | 41 | |
42 | 42 | source compose-utils.sh |
43 | 43 | |
44 | +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $? | |
45 | + | |
44 | 46 | ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? |
45 | 47 | |
46 | 48 | ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? |
47 | 49 | |
48 | 50 | if [ ! -z "${ADDITIONAL_STARTUP_SERVICES// }" ]; then |
49 | - docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS up -d redis $ADDITIONAL_STARTUP_SERVICES | |
51 | + docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS up -d redis $ADDITIONAL_STARTUP_SERVICES | |
50 | 52 | fi |
51 | 53 | |
52 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS run --no-deps --rm -e INSTALL_TB=true -e LOAD_DEMO=${loadDemo} tb-core1 | |
54 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS run --no-deps --rm -e INSTALL_TB=true -e LOAD_DEMO=${loadDemo} tb-core1 | |
53 | 55 | |
54 | 56 | ... | ... |
... | ... | @@ -19,6 +19,8 @@ set -e |
19 | 19 | |
20 | 20 | source compose-utils.sh |
21 | 21 | |
22 | +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $? | |
23 | + | |
22 | 24 | ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? |
23 | 25 | |
24 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS down -v | |
26 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS down -v | ... | ... |
... | ... | @@ -19,6 +19,8 @@ set -e |
19 | 19 | |
20 | 20 | source compose-utils.sh |
21 | 21 | |
22 | +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $? | |
23 | + | |
22 | 24 | ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? |
23 | 25 | |
24 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS up -d | |
26 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS up -d | ... | ... |
... | ... | @@ -19,6 +19,8 @@ set -e |
19 | 19 | |
20 | 20 | source compose-utils.sh |
21 | 21 | |
22 | +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $? | |
23 | + | |
22 | 24 | ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? |
23 | 25 | |
24 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS stop | |
26 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS stop | ... | ... |
... | ... | @@ -19,7 +19,9 @@ set -e |
19 | 19 | |
20 | 20 | source compose-utils.sh |
21 | 21 | |
22 | +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $? | |
23 | + | |
22 | 24 | ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? |
23 | 25 | |
24 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS pull $@ | |
25 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS up -d --no-deps --build $@ | |
26 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS pull $@ | |
27 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS up -d --no-deps --build $@ | ... | ... |
... | ... | @@ -40,12 +40,14 @@ set -e |
40 | 40 | |
41 | 41 | source compose-utils.sh |
42 | 42 | |
43 | +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $? | |
44 | + | |
43 | 45 | ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? |
44 | 46 | |
45 | 47 | ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? |
46 | 48 | |
47 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS pull tb-core1 | |
49 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS pull tb-core1 | |
48 | 50 | |
49 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS up -d redis $ADDITIONAL_STARTUP_SERVICES | |
51 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS up -d redis $ADDITIONAL_STARTUP_SERVICES | |
50 | 52 | |
51 | -docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS run --no-deps --rm -e UPGRADE_TB=true -e FROM_VERSION=${fromVersion} tb-core1 | |
53 | +docker-compose -f docker-compose.yml $ADDITIONAL_COMPOSE_ARGS $ADDITIONAL_COMPOSE_QUEUE_ARGS run --no-deps --rm -e UPGRADE_TB=true -e FROM_VERSION=${fromVersion} tb-core1 | ... | ... |
docker/queue-aws-sqs.env
0 → 100644
docker/queue-kafka.env
0 → 100644
docker/queue-pubsub.env
0 → 100644
docker/queue-rabbitmq.env
0 → 100644
docker/queue-service-bus.env
0 → 100644