Commit 3d3dd8871044a0733a7016eafc4a2e09f28a26c1

Authored by Volodymyr Babak
2 parents 2748a755 4df37fc0

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,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>application</artifactId> 26 <artifactId>application</artifactId>
@@ -34,10 +34,15 @@ @@ -34,10 +34,15 @@
34 <properties> 34 <properties>
35 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 35 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
36 <main.dir>${basedir}/..</main.dir> 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 <pkg.name>thingsboard</pkg.name> 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 <pkg.win.dist>${project.build.directory}/windows</pkg.win.dist> 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 </properties> 46 </properties>
42 47
43 <dependencies> 48 <dependencies>
@@ -313,6 +318,10 @@ @@ -313,6 +318,10 @@
313 <plugins> 318 <plugins>
314 <plugin> 319 <plugin>
315 <groupId>org.apache.maven.plugins</groupId> 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 <artifactId>maven-surefire-plugin</artifactId> 325 <artifactId>maven-surefire-plugin</artifactId>
317 <version>${surfire.version}</version> 326 <version>${surfire.version}</version>
318 <configuration> 327 <configuration>
@@ -327,313 +336,30 @@ @@ -327,313 +336,30 @@
327 <plugin> 336 <plugin>
328 <groupId>org.apache.maven.plugins</groupId> 337 <groupId>org.apache.maven.plugins</groupId>
329 <artifactId>maven-resources-plugin</artifactId> 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 </plugin> 339 </plugin>
506 <plugin> 340 <plugin>
507 <groupId>org.apache.maven.plugins</groupId> 341 <groupId>org.apache.maven.plugins</groupId>
508 <artifactId>maven-dependency-plugin</artifactId> 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 </plugin> 343 </plugin>
531 <plugin> 344 <plugin>
532 <groupId>org.apache.maven.plugins</groupId> 345 <groupId>org.apache.maven.plugins</groupId>
533 <artifactId>maven-jar-plugin</artifactId> 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 </plugin> 347 </plugin>
546 <plugin> 348 <plugin>
547 <groupId>org.springframework.boot</groupId> 349 <groupId>org.springframework.boot</groupId>
548 <artifactId>spring-boot-maven-plugin</artifactId> 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 </plugin> 351 </plugin>
570 <plugin> 352 <plugin>
571 <groupId>org.thingsboard</groupId> 353 <groupId>org.thingsboard</groupId>
572 <artifactId>gradle-maven-plugin</artifactId> 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 </plugin> 355 </plugin>
598 <plugin> 356 <plugin>
599 <groupId>org.apache.maven.plugins</groupId> 357 <groupId>org.apache.maven.plugins</groupId>
600 <artifactId>maven-assembly-plugin</artifactId> 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 </plugin> 359 </plugin>
617 <plugin> 360 <plugin>
618 <groupId>org.apache.maven.plugins</groupId> 361 <groupId>org.apache.maven.plugins</groupId>
619 <artifactId>maven-install-plugin</artifactId> 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 </plugin> 363 </plugin>
638 <plugin> 364 <plugin>
639 <groupId>org.xolstice.maven.plugins</groupId> 365 <groupId>org.xolstice.maven.plugins</groupId>
@@ -16,50 +16,85 @@ @@ -16,50 +16,85 @@
16 16
17 -- call create_partition_ts_kv_table(); 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 BEGIN 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 END; 48 END;
40 $$; 49 $$;
41 50
42 -- call create_new_ts_kv_latest_table(); 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 BEGIN 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 END; 98 END;
64 $$; 99 $$;
65 100
@@ -93,8 +128,9 @@ BEGIN @@ -93,8 +128,9 @@ BEGIN
93 RETURN QUERY SELECT SUBSTRING(year_date.year, 1, 4) AS partition_date, 128 RETURN QUERY SELECT SUBSTRING(year_date.year, 1, 4) AS partition_date,
94 (extract(epoch from (year_date.year)::timestamp) * 1000)::bigint AS from_ts, 129 (extract(epoch from (year_date.year)::timestamp) * 1000)::bigint AS from_ts,
95 (extract(epoch from (year_date.year::date + INTERVAL '1 YEAR')::timestamp) * 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 ELSE 134 ELSE
99 RAISE EXCEPTION 'Failed to parse partitioning property: % !', partition_type; 135 RAISE EXCEPTION 'Failed to parse partitioning property: % !', partition_type;
100 END CASE; 136 END CASE;
@@ -103,13 +139,16 @@ $$ LANGUAGE plpgsql; @@ -103,13 +139,16 @@ $$ LANGUAGE plpgsql;
103 139
104 -- call create_partitions(); 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 DECLARE 146 DECLARE
109 partition_date varchar; 147 partition_date varchar;
110 from_ts bigint; 148 from_ts bigint;
111 to_ts bigint; 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 BEGIN 152 BEGIN
114 OPEN partitions_cursor; 153 OPEN partitions_cursor;
115 LOOP 154 LOOP
@@ -127,21 +166,25 @@ $$; @@ -127,21 +166,25 @@ $$;
127 166
128 -- call create_ts_kv_dictionary_table(); 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 BEGIN 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 END; 180 END;
140 $$; 181 $$;
141 182
142 -- call insert_into_dictionary(); 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 DECLARE 189 DECLARE
147 insert_record RECORD; 190 insert_record RECORD;
@@ -164,31 +207,89 @@ BEGIN @@ -164,31 +207,89 @@ BEGIN
164 END; 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 ts_kv_records.key AS key, 223 ts_kv_records.key AS key,
176 ts_kv_records.ts AS ts, 224 ts_kv_records.ts AS ts,
177 ts_kv_records.bool_v AS bool_v, 225 ts_kv_records.bool_v AS bool_v,
178 ts_kv_records.str_v AS str_v, 226 ts_kv_records.str_v AS str_v,
179 ts_kv_records.long_v AS long_v, 227 ts_kv_records.long_v AS long_v,
180 ts_kv_records.dbl_v AS dbl_v 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 key_id AS key, 257 key_id AS key,
187 ts, 258 ts,
188 bool_v, 259 bool_v,
189 str_v, 260 str_v,
190 long_v, 261 long_v,
191 dbl_v 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 FROM ts_kv_old 293 FROM ts_kv_old
193 INNER JOIN ts_kv_dictionary ON (ts_kv_old.key = ts_kv_dictionary.key)) AS ts_kv_records; 294 INNER JOIN ts_kv_dictionary ON (ts_kv_old.key = ts_kv_dictionary.key)) AS ts_kv_records;
194 BEGIN 295 BEGIN
@@ -211,26 +312,24 @@ BEGIN @@ -211,26 +312,24 @@ BEGIN
211 END; 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 DECLARE 320 DECLARE
218 insert_size CONSTANT integer := 10000; 321 insert_size CONSTANT integer := 10000;
219 insert_counter integer DEFAULT 0; 322 insert_counter integer DEFAULT 0;
220 insert_record RECORD; 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 ts, 333 ts,
235 bool_v, 334 bool_v,
236 str_v, 335 str_v,
@@ -258,4 +357,3 @@ BEGIN @@ -258,4 +357,3 @@ BEGIN
258 END; 357 END;
259 $$; 358 $$;
260 359
261 -  
@@ -96,51 +96,36 @@ BEGIN @@ -96,51 +96,36 @@ BEGIN
96 END; 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 BEGIN 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 END; 129 END;
145 $$; 130 $$;
146 131
@@ -177,3 +162,47 @@ BEGIN @@ -177,3 +162,47 @@ BEGIN
177 CLOSE insert_cursor; 162 CLOSE insert_cursor;
178 END; 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 +$$;
@@ -56,6 +56,7 @@ import org.thingsboard.server.dao.audit.AuditLogService; @@ -56,6 +56,7 @@ import org.thingsboard.server.dao.audit.AuditLogService;
56 import org.thingsboard.server.dao.cassandra.CassandraCluster; 56 import org.thingsboard.server.dao.cassandra.CassandraCluster;
57 import org.thingsboard.server.dao.customer.CustomerService; 57 import org.thingsboard.server.dao.customer.CustomerService;
58 import org.thingsboard.server.dao.dashboard.DashboardService; 58 import org.thingsboard.server.dao.dashboard.DashboardService;
  59 +import org.thingsboard.server.dao.device.ClaimDevicesService;
59 import org.thingsboard.server.dao.device.DeviceService; 60 import org.thingsboard.server.dao.device.DeviceService;
60 import org.thingsboard.server.dao.edge.EdgeService; 61 import org.thingsboard.server.dao.edge.EdgeService;
61 import org.thingsboard.server.dao.entityview.EntityViewService; 62 import org.thingsboard.server.dao.entityview.EntityViewService;
@@ -219,6 +220,10 @@ public class ActorSystemContext { @@ -219,6 +220,10 @@ public class ActorSystemContext {
219 @Getter 220 @Getter
220 private MailService mailService; 221 private MailService mailService;
221 222
  223 + @Autowired
  224 + @Getter
  225 + private ClaimDevicesService claimDevicesService;
  226 +
222 //TODO: separate context for TbCore and TbRuleEngine 227 //TODO: separate context for TbCore and TbRuleEngine
223 @Autowired(required = false) 228 @Autowired(required = false)
224 @Getter 229 @Getter
@@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData; @@ -39,6 +39,7 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
39 import org.thingsboard.server.common.msg.queue.TbCallback; 39 import org.thingsboard.server.common.msg.queue.TbCallback;
40 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; 40 import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest;
41 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg; 41 import org.thingsboard.server.common.msg.timeout.DeviceActorServerSideRpcTimeoutMsg;
  42 +import org.thingsboard.server.gen.transport.TransportProtos;
42 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; 43 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
43 import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry; 44 import org.thingsboard.server.gen.transport.TransportProtos.DeviceSessionsCacheEntry;
44 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; 45 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
@@ -232,9 +233,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { @@ -232,9 +233,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
232 if (msg.hasSubscriptionInfo()) { 233 if (msg.hasSubscriptionInfo()) {
233 handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo()); 234 handleSessionActivity(context, msg.getSessionInfo(), msg.getSubscriptionInfo());
234 } 235 }
  236 + if (msg.hasClaimDevice()) {
  237 + handleClaimDeviceMsg(context, msg.getSessionInfo(), msg.getClaimDevice());
  238 + }
235 callback.onSuccess(); 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 private void reportSessionOpen() { 247 private void reportSessionOpen() {
239 systemContext.getDeviceStateService().onDeviceConnect(deviceId); 248 systemContext.getDeviceStateService().onDeviceConnect(deviceId);
240 } 249 }
@@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; @@ -28,7 +28,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
28 import org.springframework.web.bind.annotation.RestController; 28 import org.springframework.web.bind.annotation.RestController;
29 import org.thingsboard.server.common.data.EntityType; 29 import org.thingsboard.server.common.data.EntityType;
30 import org.thingsboard.server.common.data.alarm.Alarm; 30 import org.thingsboard.server.common.data.alarm.Alarm;
31 -import org.thingsboard.server.common.data.id.AlarmId;  
32 import org.thingsboard.server.common.data.alarm.AlarmInfo; 31 import org.thingsboard.server.common.data.alarm.AlarmInfo;
33 import org.thingsboard.server.common.data.alarm.AlarmQuery; 32 import org.thingsboard.server.common.data.alarm.AlarmQuery;
34 import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; 33 import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
@@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; @@ -37,6 +36,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus;
37 import org.thingsboard.server.common.data.audit.ActionType; 36 import org.thingsboard.server.common.data.audit.ActionType;
38 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; 37 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
39 import org.thingsboard.server.common.data.exception.ThingsboardException; 38 import org.thingsboard.server.common.data.exception.ThingsboardException;
  39 +import org.thingsboard.server.common.data.id.AlarmId;
40 import org.thingsboard.server.common.data.id.EntityId; 40 import org.thingsboard.server.common.data.id.EntityId;
41 import org.thingsboard.server.common.data.id.EntityIdFactory; 41 import org.thingsboard.server.common.data.id.EntityIdFactory;
42 import org.thingsboard.server.common.data.page.TimePageData; 42 import org.thingsboard.server.common.data.page.TimePageData;
@@ -84,8 +84,9 @@ public class AlarmController extends BaseController { @@ -84,8 +84,9 @@ public class AlarmController extends BaseController {
84 public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException { 84 public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException {
85 try { 85 try {
86 alarm.setTenantId(getCurrentUser().getTenantId()); 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 Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm)); 90 Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm));
90 logEntityAction(savedAlarm.getId(), savedAlarm, 91 logEntityAction(savedAlarm.getId(), savedAlarm,
91 getCurrentUser().getCustomerId(), 92 getCurrentUser().getCustomerId(),
@@ -82,18 +82,15 @@ public class AssetController extends BaseController { @@ -82,18 +82,15 @@ public class AssetController extends BaseController {
82 try { 82 try {
83 asset.setTenantId(getCurrentUser().getTenantId()); 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 logEntityAction(savedAsset.getId(), savedAsset, 89 logEntityAction(savedAsset.getId(), savedAsset,
93 savedAsset.getCustomerId(), 90 savedAsset.getCustomerId(),
94 asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); 91 asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
95 92
96 - return savedAsset; 93 + return savedAsset;
97 } catch (Exception e) { 94 } catch (Exception e) {
98 logEntityAction(emptyId(EntityType.ASSET), asset, 95 logEntityAction(emptyId(EntityType.ASSET), asset,
99 null, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); 96 null, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
@@ -144,7 +141,7 @@ public class AssetController extends BaseController { @@ -144,7 +141,7 @@ public class AssetController extends BaseController {
144 savedAsset.getCustomerId(), 141 savedAsset.getCustomerId(),
145 ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName()); 142 ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName());
146 143
147 - return savedAsset; 144 + return savedAsset;
148 } catch (Exception e) { 145 } catch (Exception e) {
149 146
150 logEntityAction(emptyId(EntityType.ASSET), null, 147 logEntityAction(emptyId(EntityType.ASSET), null,
@@ -224,7 +221,7 @@ public class AssetController extends BaseController { @@ -224,7 +221,7 @@ public class AssetController extends BaseController {
224 try { 221 try {
225 TenantId tenantId = getCurrentUser().getTenantId(); 222 TenantId tenantId = getCurrentUser().getTenantId();
226 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 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 return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink)); 225 return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
229 } else { 226 } else {
230 return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink)); 227 return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
@@ -263,7 +260,7 @@ public class AssetController extends BaseController { @@ -263,7 +260,7 @@ public class AssetController extends BaseController {
263 CustomerId customerId = new CustomerId(toUUID(strCustomerId)); 260 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
264 checkCustomerId(customerId, Operation.READ); 261 checkCustomerId(customerId, Operation.READ);
265 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 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 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); 264 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
268 } else { 265 } else {
269 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); 266 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value; @@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Value;
26 import org.springframework.security.core.Authentication; 26 import org.springframework.security.core.Authentication;
27 import org.springframework.security.core.context.SecurityContextHolder; 27 import org.springframework.security.core.context.SecurityContextHolder;
28 import org.springframework.web.bind.annotation.ExceptionHandler; 28 import org.springframework.web.bind.annotation.ExceptionHandler;
  29 +import org.thingsboard.server.common.data.BaseData;
29 import org.thingsboard.server.common.data.Customer; 30 import org.thingsboard.server.common.data.Customer;
30 import org.thingsboard.server.common.data.Dashboard; 31 import org.thingsboard.server.common.data.Dashboard;
31 import org.thingsboard.server.common.data.DashboardInfo; 32 import org.thingsboard.server.common.data.DashboardInfo;
@@ -107,7 +108,6 @@ import org.thingsboard.server.service.state.DeviceStateService; @@ -107,7 +108,6 @@ import org.thingsboard.server.service.state.DeviceStateService;
107 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; 108 import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
108 109
109 import javax.mail.MessagingException; 110 import javax.mail.MessagingException;
110 -import javax.servlet.http.HttpServletRequest;  
111 import javax.servlet.http.HttpServletResponse; 111 import javax.servlet.http.HttpServletResponse;
112 import java.util.List; 112 import java.util.List;
113 import java.util.Optional; 113 import java.util.Optional;
@@ -337,11 +337,23 @@ public abstract class BaseController { @@ -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 protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException { 349 protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException {
341 try { 350 try {
342 checkNotNull(entityId); 351 checkNotNull(entityId);
343 validateId(entityId.getId(), "Incorrect entityId " + entityId); 352 validateId(entityId.getId(), "Incorrect entityId " + entityId);
344 switch (entityId.getEntityType()) { 353 switch (entityId.getEntityType()) {
  354 + case ALARM:
  355 + checkAlarmId(new AlarmId(entityId.getId()), operation);
  356 + return;
345 case DEVICE: 357 case DEVICE:
346 checkDeviceId(new DeviceId(entityId.getId()), operation); 358 checkDeviceId(new DeviceId(entityId.getId()), operation);
347 return; 359 return;
@@ -372,6 +384,12 @@ public abstract class BaseController { @@ -372,6 +384,12 @@ public abstract class BaseController {
372 case EDGE: 384 case EDGE:
373 checkEdgeId(new EdgeId(entityId.getId()), operation); 385 checkEdgeId(new EdgeId(entityId.getId()), operation);
374 return; 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 default: 393 default:
376 throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType()); 394 throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
377 } 395 }
@@ -100,8 +100,7 @@ public class CustomerController extends BaseController { @@ -100,8 +100,7 @@ public class CustomerController extends BaseController {
100 try { 100 try {
101 customer.setTenantId(getCurrentUser().getTenantId()); 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 Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer)); 105 Customer savedCustomer = checkNotNull(customerService.saveCustomer(customer));
107 106
@@ -103,15 +103,12 @@ public class DashboardController extends BaseController { @@ -103,15 +103,12 @@ public class DashboardController extends BaseController {
103 103
104 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 104 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
105 @RequestMapping(value = "/dashboard", method = RequestMethod.POST) 105 @RequestMapping(value = "/dashboard", method = RequestMethod.POST)
106 - @ResponseBody 106 + @ResponseBody
107 public Dashboard saveDashboard(@RequestBody Dashboard dashboard) throws ThingsboardException { 107 public Dashboard saveDashboard(@RequestBody Dashboard dashboard) throws ThingsboardException {
108 try { 108 try {
109 dashboard.setTenantId(getCurrentUser().getTenantId()); 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 Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard)); 113 Dashboard savedDashboard = checkNotNull(dashboardService.saveDashboard(dashboard));
117 114
@@ -155,9 +152,9 @@ public class DashboardController extends BaseController { @@ -155,9 +152,9 @@ public class DashboardController extends BaseController {
155 152
156 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 153 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
157 @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST) 154 @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.POST)
158 - @ResponseBody 155 + @ResponseBody
159 public Dashboard assignDashboardToCustomer(@PathVariable("customerId") String strCustomerId, 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 checkParameter("customerId", strCustomerId); 158 checkParameter("customerId", strCustomerId);
162 checkParameter(DASHBOARD_ID, strDashboardId); 159 checkParameter(DASHBOARD_ID, strDashboardId);
163 try { 160 try {
@@ -166,7 +163,7 @@ public class DashboardController extends BaseController { @@ -166,7 +163,7 @@ public class DashboardController extends BaseController {
166 163
167 DashboardId dashboardId = new DashboardId(toUUID(strDashboardId)); 164 DashboardId dashboardId = new DashboardId(toUUID(strDashboardId));
168 checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER); 165 checkDashboardId(dashboardId, Operation.ASSIGN_TO_CUSTOMER);
169 - 166 +
170 Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId)); 167 Dashboard savedDashboard = checkNotNull(dashboardService.assignDashboardToCustomer(getCurrentUser().getTenantId(), dashboardId, customerId));
171 168
172 logEntityAction(dashboardId, savedDashboard, 169 logEntityAction(dashboardId, savedDashboard,
@@ -187,7 +184,7 @@ public class DashboardController extends BaseController { @@ -187,7 +184,7 @@ public class DashboardController extends BaseController {
187 184
188 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 185 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
189 @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE) 186 @RequestMapping(value = "/customer/{customerId}/dashboard/{dashboardId}", method = RequestMethod.DELETE)
190 - @ResponseBody 187 + @ResponseBody
191 public Dashboard unassignDashboardFromCustomer(@PathVariable("customerId") String strCustomerId, 188 public Dashboard unassignDashboardFromCustomer(@PathVariable("customerId") String strCustomerId,
192 @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException { 189 @PathVariable(DASHBOARD_ID) String strDashboardId) throws ThingsboardException {
193 checkParameter("customerId", strCustomerId); 190 checkParameter("customerId", strCustomerId);
@@ -421,7 +418,7 @@ public class DashboardController extends BaseController { @@ -421,7 +418,7 @@ public class DashboardController extends BaseController {
421 } 418 }
422 419
423 @PreAuthorize("hasAuthority('SYS_ADMIN')") 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 @ResponseBody 422 @ResponseBody
426 public TextPageData<DashboardInfo> getTenantDashboards( 423 public TextPageData<DashboardInfo> getTenantDashboards(
427 @PathVariable("tenantId") String strTenantId, 424 @PathVariable("tenantId") String strTenantId,
@@ -440,7 +437,7 @@ public class DashboardController extends BaseController { @@ -440,7 +437,7 @@ public class DashboardController extends BaseController {
440 } 437 }
441 438
442 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 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 @ResponseBody 441 @ResponseBody
445 public TextPageData<DashboardInfo> getTenantDashboards( 442 public TextPageData<DashboardInfo> getTenantDashboards(
446 @RequestParam int limit, 443 @RequestParam int limit,
@@ -457,7 +454,7 @@ public class DashboardController extends BaseController { @@ -457,7 +454,7 @@ public class DashboardController extends BaseController {
457 } 454 }
458 455
459 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") 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 @ResponseBody 458 @ResponseBody
462 public TimePageData<DashboardInfo> getCustomerDashboards( 459 public TimePageData<DashboardInfo> getCustomerDashboards(
463 @PathVariable("customerId") String strCustomerId, 460 @PathVariable("customerId") String strCustomerId,
@@ -99,10 +99,7 @@ public class DeviceController extends BaseController { @@ -99,10 +99,7 @@ public class DeviceController extends BaseController {
99 try { 99 try {
100 device.setTenantId(getCurrentUser().getTenantId()); 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 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); 104 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
108 105
@@ -97,10 +97,7 @@ public class EntityViewController extends BaseController { @@ -97,10 +97,7 @@ public class EntityViewController extends BaseController {
97 try { 97 try {
98 entityView.setTenantId(getCurrentUser().getTenantId()); 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 EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); 102 EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
106 List<ListenableFuture<List<Void>>> futures = new ArrayList<>(); 103 List<ListenableFuture<List<Void>>> futures = new ArrayList<>();
@@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.google.common.util.concurrent.FutureCallback; 20 import com.google.common.util.concurrent.FutureCallback;
21 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
22 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.beans.factory.annotation.Value;
23 import org.springframework.http.HttpStatus; 24 import org.springframework.http.HttpStatus;
24 import org.springframework.http.ResponseEntity; 25 import org.springframework.http.ResponseEntity;
25 import org.springframework.security.access.prepost.PreAuthorize; 26 import org.springframework.security.access.prepost.PreAuthorize;
@@ -65,7 +66,6 @@ import java.util.UUID; @@ -65,7 +66,6 @@ import java.util.UUID;
65 @Slf4j 66 @Slf4j
66 public class RpcController extends BaseController { 67 public class RpcController extends BaseController {
67 68
68 - public static final int DEFAULT_TIMEOUT = 10000;  
69 protected final ObjectMapper jsonMapper = new ObjectMapper(); 69 protected final ObjectMapper jsonMapper = new ObjectMapper();
70 70
71 @Autowired 71 @Autowired
@@ -74,6 +74,12 @@ public class RpcController extends BaseController { @@ -74,6 +74,12 @@ public class RpcController extends BaseController {
74 @Autowired 74 @Autowired
75 private AccessValidator accessValidator; 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 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 83 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
78 @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST) 84 @RequestMapping(value = "/oneway/{deviceId}", method = RequestMethod.POST)
79 @ResponseBody 85 @ResponseBody
@@ -100,7 +106,8 @@ public class RpcController extends BaseController { @@ -100,7 +106,8 @@ public class RpcController extends BaseController {
100 SecurityUser currentUser = getCurrentUser(); 106 SecurityUser currentUser = getCurrentUser();
101 TenantId tenantId = currentUser.getTenantId(); 107 TenantId tenantId = currentUser.getTenantId();
102 final DeferredResult<ResponseEntity> response = new DeferredResult<>(); 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 ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(cmd.getMethodName(), cmd.getRequestData()); 111 ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(cmd.getMethodName(), cmd.getRequestData());
105 accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() { 112 accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() {
106 @Override 113 @Override
@@ -109,7 +116,7 @@ public class RpcController extends BaseController { @@ -109,7 +116,7 @@ public class RpcController extends BaseController {
109 tenantId, 116 tenantId,
110 deviceId, 117 deviceId,
111 oneWay, 118 oneWay,
112 - timeout, 119 + expTime,
113 body 120 body
114 ); 121 );
115 deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse)); 122 deviceRpcService.processRestApiRpcRequest(rpcRequest, fromDeviceRpcResponse -> reply(new LocalRequestMetaData(rpcRequest, currentUser, result), fromDeviceRpcResponse));
@@ -130,10 +130,7 @@ public class RuleChainController extends BaseController { @@ -130,10 +130,7 @@ public class RuleChainController extends BaseController {
130 boolean created = ruleChain.getId() == null; 130 boolean created = ruleChain.getId() == null;
131 ruleChain.setTenantId(getCurrentUser().getTenantId()); 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 RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain)); 135 RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain));
139 136
@@ -72,10 +72,8 @@ public class TenantController extends BaseController { @@ -72,10 +72,8 @@ public class TenantController extends BaseController {
72 try { 72 try {
73 boolean newTenant = tenant.getId() == null; 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 tenant = checkNotNull(tenantService.saveTenant(tenant)); 77 tenant = checkNotNull(tenantService.saveTenant(tenant));
80 if (newTenant) { 78 if (newTenant) {
81 installScripts.createDefaultRuleChains(tenant.getId()); 79 installScripts.createDefaultRuleChains(tenant.getId());
@@ -132,17 +132,13 @@ public class UserController extends BaseController { @@ -132,17 +132,13 @@ public class UserController extends BaseController {
132 @ResponseBody 132 @ResponseBody
133 public User saveUser(@RequestBody User user, 133 public User saveUser(@RequestBody User user,
134 @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail, 134 @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail,
135 - HttpServletRequest request) throws ThingsboardException { 135 + HttpServletRequest request) throws ThingsboardException {
136 try { 136 try {
137 -  
138 if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) { 137 if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) {
139 user.setTenantId(getCurrentUser().getTenantId()); 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 boolean sendEmail = user.getId() == null && sendActivationMail; 143 boolean sendEmail = user.getId() == null && sendActivationMail;
148 User savedUser = checkNotNull(userService.saveUser(user)); 144 User savedUser = checkNotNull(userService.saveUser(user));
@@ -250,7 +246,7 @@ public class UserController extends BaseController { @@ -250,7 +246,7 @@ public class UserController extends BaseController {
250 } 246 }
251 247
252 @PreAuthorize("hasAuthority('SYS_ADMIN')") 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 @ResponseBody 250 @ResponseBody
255 public TextPageData<User> getTenantAdmins( 251 public TextPageData<User> getTenantAdmins(
256 @PathVariable("tenantId") String strTenantId, 252 @PathVariable("tenantId") String strTenantId,
@@ -269,7 +265,7 @@ public class UserController extends BaseController { @@ -269,7 +265,7 @@ public class UserController extends BaseController {
269 } 265 }
270 266
271 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 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 @ResponseBody 269 @ResponseBody
274 public TextPageData<User> getCustomerUsers( 270 public TextPageData<User> getCustomerUsers(
275 @PathVariable("customerId") String strCustomerId, 271 @PathVariable("customerId") String strCustomerId,
@@ -66,10 +66,7 @@ public class WidgetTypeController extends BaseController { @@ -66,10 +66,7 @@ public class WidgetTypeController extends BaseController {
66 widgetType.setTenantId(getCurrentUser().getTenantId()); 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 return checkNotNull(widgetTypeService.saveWidgetType(widgetType)); 71 return checkNotNull(widgetTypeService.saveWidgetType(widgetType));
75 } catch (Exception e) { 72 } catch (Exception e) {
@@ -92,7 +89,7 @@ public class WidgetTypeController extends BaseController { @@ -92,7 +89,7 @@ public class WidgetTypeController extends BaseController {
92 } 89 }
93 90
94 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") 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 @ResponseBody 93 @ResponseBody
97 public List<WidgetType> getBundleWidgetTypes( 94 public List<WidgetType> getBundleWidgetTypes(
98 @RequestParam boolean isSystem, 95 @RequestParam boolean isSystem,
@@ -111,7 +108,7 @@ public class WidgetTypeController extends BaseController { @@ -111,7 +108,7 @@ public class WidgetTypeController extends BaseController {
111 } 108 }
112 109
113 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 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 @ResponseBody 112 @ResponseBody
116 public WidgetType getWidgetType( 113 public WidgetType getWidgetType(
117 @RequestParam boolean isSystem, 114 @RequestParam boolean isSystem,
@@ -67,11 +67,7 @@ public class WidgetsBundleController extends BaseController { @@ -67,11 +67,7 @@ public class WidgetsBundleController extends BaseController {
67 widgetsBundle.setTenantId(getCurrentUser().getTenantId()); 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 return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle)); 71 return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
76 } catch (Exception e) { 72 } catch (Exception e) {
77 throw handleException(e); 73 throw handleException(e);
@@ -93,7 +89,7 @@ public class WidgetsBundleController extends BaseController { @@ -93,7 +89,7 @@ public class WidgetsBundleController extends BaseController {
93 } 89 }
94 90
95 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") 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 @ResponseBody 93 @ResponseBody
98 public TextPageData<WidgetsBundle> getWidgetsBundles( 94 public TextPageData<WidgetsBundle> getWidgetsBundles(
99 @RequestParam int limit, 95 @RequestParam int limit,
@@ -133,13 +133,20 @@ public class ThingsboardInstallService { @@ -133,13 +133,20 @@ public class ThingsboardInstallService {
133 databaseEntitiesUpgradeService.upgradeDatabase("2.4.2"); 133 databaseEntitiesUpgradeService.upgradeDatabase("2.4.2");
134 134
135 case "2.4.3": 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 if (databaseTsUpgradeService != null) { 138 if (databaseTsUpgradeService != null) {
139 databaseTsUpgradeService.upgradeDatabase("2.4.3"); 139 databaseTsUpgradeService.upgradeDatabase("2.4.3");
140 } 140 }
141 databaseEntitiesUpgradeService.upgradeDatabase("2.4.3"); 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 log.info("Updating system data..."); 150 log.info("Updating system data...");
144 151
145 systemDataLoaderService.deleteSystemWidgetBundle("charts"); 152 systemDataLoaderService.deleteSystemWidgetBundle("charts");
@@ -34,6 +34,9 @@ public abstract class AbstractSqlTsDatabaseUpgradeService { @@ -34,6 +34,9 @@ public abstract class AbstractSqlTsDatabaseUpgradeService {
34 protected static final String CALL_REGEX = "call "; 34 protected static final String CALL_REGEX = "call ";
35 protected static final String DROP_TABLE = "DROP TABLE "; 35 protected static final String DROP_TABLE = "DROP TABLE ";
36 protected static final String DROP_PROCEDURE_IF_EXISTS = "DROP PROCEDURE IF EXISTS "; 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 @Value("${spring.datasource.url}") 41 @Value("${spring.datasource.url}")
39 protected String dbUrl; 42 protected String dbUrl;
@@ -48,6 +48,8 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase @@ -48,6 +48,8 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase
48 } 48 }
49 log.info("Schema updated."); 49 log.info("Schema updated.");
50 break; 50 break;
  51 + case "2.5.0":
  52 + break;
51 default: 53 default:
52 throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); 54 throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion);
53 } 55 }
@@ -131,6 +131,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -131,6 +131,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
131 node.put("username", ""); 131 node.put("username", "");
132 node.put("password", ""); 132 node.put("password", "");
133 node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself) 133 node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself)
  134 + node.put("enableProxy", false);
134 mailSettings.setJsonValue(node); 135 mailSettings.setJsonValue(node);
135 adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings); 136 adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings);
136 } 137 }
@@ -37,8 +37,6 @@ public class PsqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaServic @@ -37,8 +37,6 @@ public class PsqlTsDatabaseSchemaService extends SqlAbstractDatabaseSchemaServic
37 @Override 37 @Override
38 public void createDatabaseSchema() throws Exception { 38 public void createDatabaseSchema() throws Exception {
39 super.createDatabaseSchema(); 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 }
@@ -16,12 +16,17 @@ @@ -16,12 +16,17 @@
16 package org.thingsboard.server.service.install; 16 package org.thingsboard.server.service.install;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.StringUtils;
  20 +import org.apache.commons.lang3.SystemUtils;
19 import org.springframework.beans.factory.annotation.Value; 21 import org.springframework.beans.factory.annotation.Value;
20 import org.springframework.context.annotation.Profile; 22 import org.springframework.context.annotation.Profile;
21 import org.springframework.stereotype.Service; 23 import org.springframework.stereotype.Service;
22 import org.thingsboard.server.dao.util.PsqlDao; 24 import org.thingsboard.server.dao.util.PsqlDao;
23 import org.thingsboard.server.dao.util.SqlTsDao; 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 import java.nio.file.Path; 30 import java.nio.file.Path;
26 import java.nio.file.Paths; 31 import java.nio.file.Paths;
27 import java.sql.Connection; 32 import java.sql.Connection;
@@ -37,6 +42,7 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe @@ -37,6 +42,7 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
37 @Value("${sql.postgres.ts_key_value_partitioning:MONTHS}") 42 @Value("${sql.postgres.ts_key_value_partitioning:MONTHS}")
38 private String partitionType; 43 private String partitionType;
39 44
  45 + private static final String TS_KV_LATEST_SQL = "ts_kv_latest.sql";
40 private static final String LOAD_FUNCTIONS_SQL = "schema_update_psql_ts.sql"; 46 private static final String LOAD_FUNCTIONS_SQL = "schema_update_psql_ts.sql";
41 private static final String LOAD_TTL_FUNCTIONS_SQL = "schema_update_ttl.sql"; 47 private static final String LOAD_TTL_FUNCTIONS_SQL = "schema_update_ttl.sql";
42 private static final String LOAD_DROP_PARTITIONS_FUNCTIONS_SQL = "schema_update_psql_drop_partitions.sql"; 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,15 +55,17 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
49 private static final String CREATE_PARTITIONS = "create_partitions(IN partition_type varchar)"; 55 private static final String CREATE_PARTITIONS = "create_partitions(IN partition_type varchar)";
50 private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()"; 56 private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()";
51 private static final String INSERT_INTO_DICTIONARY = "insert_into_dictionary()"; 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 private static final String CALL_CREATE_PARTITION_TS_KV_TABLE = CALL_REGEX + CREATE_PARTITION_TS_KV_TABLE; 63 private static final String CALL_CREATE_PARTITION_TS_KV_TABLE = CALL_REGEX + CREATE_PARTITION_TS_KV_TABLE;
56 private static final String CALL_CREATE_NEW_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_LATEST_TABLE; 64 private static final String CALL_CREATE_NEW_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_LATEST_TABLE;
57 private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE; 65 private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE;
58 private static final String CALL_INSERT_INTO_DICTIONARY = CALL_REGEX + INSERT_INTO_DICTIONARY; 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 private static final String DROP_TABLE_TS_KV_OLD = DROP_TABLE + TS_KV_OLD; 70 private static final String DROP_TABLE_TS_KV_OLD = DROP_TABLE + TS_KV_OLD;
63 private static final String DROP_TABLE_TS_KV_LATEST_OLD = DROP_TABLE + TS_KV_LATEST_OLD; 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,6 +77,8 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
69 private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY; 77 private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY;
70 private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV; 78 private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV;
71 private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; 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 private static final String DROP_FUNCTION_GET_PARTITION_DATA = "DROP FUNCTION IF EXISTS get_partitions_data;"; 82 private static final String DROP_FUNCTION_GET_PARTITION_DATA = "DROP FUNCTION IF EXISTS get_partitions_data;";
73 83
74 @Override 84 @Override
@@ -89,14 +99,63 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe @@ -89,14 +99,63 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
89 executeQuery(conn, CALL_CREATE_PARTITION_TS_KV_TABLE); 99 executeQuery(conn, CALL_CREATE_PARTITION_TS_KV_TABLE);
90 if (!partitionType.equals("INDEFINITE")) { 100 if (!partitionType.equals("INDEFINITE")) {
91 executeQuery(conn, "call create_partitions('" + partitionType + "')"); 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 executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); 103 executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE);
96 executeQuery(conn, CALL_INSERT_INTO_DICTIONARY); 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 executeQuery(conn, DROP_TABLE_TS_KV_OLD); 160 executeQuery(conn, DROP_TABLE_TS_KV_OLD);
102 executeQuery(conn, DROP_TABLE_TS_KV_LATEST_OLD); 161 executeQuery(conn, DROP_TABLE_TS_KV_LATEST_OLD);
@@ -108,6 +167,8 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe @@ -108,6 +167,8 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
108 executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV); 167 executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV);
109 executeQuery(conn, DROP_PROCEDURE_CREATE_NEW_TS_KV_LATEST_TABLE); 168 executeQuery(conn, DROP_PROCEDURE_CREATE_NEW_TS_KV_LATEST_TABLE);
110 executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST); 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 executeQuery(conn, DROP_FUNCTION_GET_PARTITION_DATA); 172 executeQuery(conn, DROP_FUNCTION_GET_PARTITION_DATA);
112 173
113 executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN IF NOT EXISTS json_v json;"); 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,11 +189,46 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe
128 } 189 }
129 } 190 }
130 break; 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 default: 198 default:
132 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); 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 @Override 232 @Override
137 protected void loadSql(Connection conn, String fileName) { 233 protected void loadSql(Connection conn, String fileName) {
138 Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); 234 Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName);
@@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
16 package org.thingsboard.server.service.install; 16 package org.thingsboard.server.service.install;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.StringUtils;
  20 +import org.apache.commons.lang3.SystemUtils;
19 import org.springframework.beans.factory.annotation.Autowired; 21 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.beans.factory.annotation.Value; 22 import org.springframework.beans.factory.annotation.Value;
21 import org.springframework.context.annotation.Profile; 23 import org.springframework.context.annotation.Profile;
@@ -23,6 +25,9 @@ import org.springframework.stereotype.Service; @@ -23,6 +25,9 @@ import org.springframework.stereotype.Service;
23 import org.thingsboard.server.dao.util.PsqlDao; 25 import org.thingsboard.server.dao.util.PsqlDao;
24 import org.thingsboard.server.dao.util.TimescaleDBTsDao; 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 import java.nio.file.Path; 31 import java.nio.file.Path;
27 import java.nio.file.Paths; 32 import java.nio.file.Paths;
28 import java.sql.Connection; 33 import java.sql.Connection;
@@ -47,15 +52,16 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr @@ -47,15 +52,16 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
47 private static final String CREATE_NEW_TS_KV_TABLE = "create_new_ts_kv_table()"; 52 private static final String CREATE_NEW_TS_KV_TABLE = "create_new_ts_kv_table()";
48 private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()"; 53 private static final String CREATE_TS_KV_DICTIONARY_TABLE = "create_ts_kv_dictionary_table()";
49 private static final String INSERT_INTO_DICTIONARY = "insert_into_dictionary()"; 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 private static final String INSERT_INTO_TS_KV_LATEST = "insert_into_ts_kv_latest()"; 57 private static final String INSERT_INTO_TS_KV_LATEST = "insert_into_ts_kv_latest()";
52 58
53 private static final String CALL_CREATE_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_TS_KV_LATEST_TABLE; 59 private static final String CALL_CREATE_TS_KV_LATEST_TABLE = CALL_REGEX + CREATE_TS_KV_LATEST_TABLE;
54 private static final String CALL_CREATE_NEW_TENANT_TS_KV_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_TABLE; 60 private static final String CALL_CREATE_NEW_TENANT_TS_KV_TABLE = CALL_REGEX + CREATE_NEW_TS_KV_TABLE;
55 private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE; 61 private static final String CALL_CREATE_TS_KV_DICTIONARY_TABLE = CALL_REGEX + CREATE_TS_KV_DICTIONARY_TABLE;
56 private static final String CALL_INSERT_INTO_DICTIONARY = CALL_REGEX + INSERT_INTO_DICTIONARY; 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 private static final String CALL_INSERT_INTO_TS_KV_LATEST = CALL_REGEX + INSERT_INTO_TS_KV_LATEST; 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 private static final String DROP_OLD_TENANT_TS_KV_TABLE = DROP_TABLE + TENANT_TS_KV_OLD_TABLE; 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,7 +69,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
63 private static final String DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY = DROP_PROCEDURE_IF_EXISTS + CREATE_NEW_TS_KV_TABLE; 69 private static final String DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY = DROP_PROCEDURE_IF_EXISTS + CREATE_NEW_TS_KV_TABLE;
64 private static final String DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE; 70 private static final String DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE = DROP_PROCEDURE_IF_EXISTS + CREATE_TS_KV_DICTIONARY_TABLE;
65 private static final String DROP_PROCEDURE_INSERT_INTO_DICTIONARY = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_DICTIONARY; 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 private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST; 74 private static final String DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST = DROP_PROCEDURE_IF_EXISTS + INSERT_INTO_TS_KV_LATEST;
68 75
69 @Autowired 76 @Autowired
@@ -91,7 +98,56 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr @@ -91,7 +98,56 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
91 98
92 executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE); 99 executeQuery(conn, CALL_CREATE_TS_KV_DICTIONARY_TABLE);
93 executeQuery(conn, CALL_INSERT_INTO_DICTIONARY); 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 executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST); 151 executeQuery(conn, CALL_INSERT_INTO_TS_KV_LATEST);
96 152
97 executeQuery(conn, DROP_OLD_TENANT_TS_KV_TABLE); 153 executeQuery(conn, DROP_OLD_TENANT_TS_KV_TABLE);
@@ -100,7 +156,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr @@ -100,7 +156,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
100 executeQuery(conn, DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY); 156 executeQuery(conn, DROP_PROCEDURE_CREATE_TENANT_TS_KV_TABLE_COPY);
101 executeQuery(conn, DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE); 157 executeQuery(conn, DROP_PROCEDURE_CREATE_TS_KV_DICTIONARY_TABLE);
102 executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_DICTIONARY); 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 executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST); 161 executeQuery(conn, DROP_PROCEDURE_INSERT_INTO_TS_KV_LATEST);
105 162
106 executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN IF NOT EXISTS json_v json;"); 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,11 +172,31 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr
115 } 172 }
116 } 173 }
117 break; 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 default: 180 default:
119 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); 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 @Override 200 @Override
124 protected void loadSql(Connection conn, String fileName) { 201 protected void loadSql(Connection conn, String fileName) {
125 Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName); 202 Path schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.4.3", fileName);
@@ -115,6 +115,21 @@ public class DefaultMailService implements MailService { @@ -115,6 +115,21 @@ public class DefaultMailService implements MailService {
115 if (enableTls && jsonConfig.has("tlsVersion") && StringUtils.isNoneEmpty(jsonConfig.get("tlsVersion").asText())) { 115 if (enableTls && jsonConfig.has("tlsVersion") && StringUtils.isNoneEmpty(jsonConfig.get("tlsVersion").asText())) {
116 javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", jsonConfig.get("tlsVersion").asText()); 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 return javaMailProperties; 133 return javaMailProperties;
119 } 134 }
120 135
@@ -46,6 +46,9 @@ import java.util.concurrent.atomic.AtomicInteger; @@ -46,6 +46,9 @@ import java.util.concurrent.atomic.AtomicInteger;
46 @Service 46 @Service
47 public class RemoteJsInvokeService extends AbstractJsInvokeService { 47 public class RemoteJsInvokeService extends AbstractJsInvokeService {
48 48
  49 + @Value("${queue.js.max_eval_requests_timeout}")
  50 + private long maxEvalRequestsTimeout;
  51 +
49 @Value("${queue.js.max_requests_timeout}") 52 @Value("${queue.js.max_requests_timeout}")
50 private long maxRequestsTimeout; 53 private long maxRequestsTimeout;
51 54
@@ -59,22 +62,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { @@ -59,22 +62,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
59 @Value("${js.remote.stats.enabled:false}") 62 @Value("${js.remote.stats.enabled:false}")
60 private boolean statsEnabled; 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 @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms}") 71 @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms}")
69 public void printStats() { 72 public void printStats() {
70 if (statsEnabled) { 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 if (pushedMsgs > 0 || invokeMsgs > 0 || evalMsgs > 0 || failed > 0 || timedOut > 0) { 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 pushedMsgs, invokeMsgs + evalMsgs, invokeMsgs, evalMsgs, failed, timedOut); 81 pushedMsgs, invokeMsgs + evalMsgs, invokeMsgs, evalMsgs, failed, timedOut);
79 } 82 }
80 } 83 }
@@ -113,22 +116,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { @@ -113,22 +116,22 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
113 116
114 log.trace("Post compile request for scriptId [{}]", scriptId); 117 log.trace("Post compile request for scriptId [{}]", scriptId);
115 ListenableFuture<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); 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 Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() { 123 Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() {
121 @Override 124 @Override
122 public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) { 125 public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) {
123 - kafkaEvalMsgs.incrementAndGet(); 126 + queueEvalMsgs.incrementAndGet();
124 } 127 }
125 128
126 @Override 129 @Override
127 public void onFailure(Throwable t) { 130 public void onFailure(Throwable t) {
128 if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { 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 }, MoreExecutors.directExecutor()); 136 }, MoreExecutors.directExecutor());
134 return Futures.transform(future, response -> { 137 return Futures.transform(future, response -> {
@@ -170,20 +173,20 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService { @@ -170,20 +173,20 @@ public class RemoteJsInvokeService extends AbstractJsInvokeService {
170 if (maxRequestsTimeout > 0) { 173 if (maxRequestsTimeout > 0) {
171 future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService); 174 future = Futures.withTimeout(future, maxRequestsTimeout, TimeUnit.MILLISECONDS, timeoutExecutorService);
172 } 175 }
173 - kafkaPushedMsgs.incrementAndGet(); 176 + queuePushedMsgs.incrementAndGet();
174 Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() { 177 Futures.addCallback(future, new FutureCallback<TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>>() {
175 @Override 178 @Override
176 public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) { 179 public void onSuccess(@Nullable TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse> result) {
177 - kafkaInvokeMsgs.incrementAndGet(); 180 + queueInvokeMsgs.incrementAndGet();
178 } 181 }
179 182
180 @Override 183 @Override
181 public void onFailure(Throwable t) { 184 public void onFailure(Throwable t) {
182 onScriptExecutionError(scriptId); 185 onScriptExecutionError(scriptId);
183 if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { 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 }, MoreExecutors.directExecutor()); 191 }, MoreExecutors.directExecutor());
189 return Futures.transform(future, response -> { 192 return Futures.transform(future, response -> {
@@ -15,6 +15,9 @@ @@ -15,6 +15,9 @@
15 */ 15 */
16 package org.thingsboard.server.service.security.auth.oauth2; 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 import lombok.extern.slf4j.Slf4j; 21 import lombok.extern.slf4j.Slf4j;
19 import org.springframework.beans.factory.annotation.Autowired; 22 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 23 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -22,14 +25,21 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -22,14 +25,21 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
22 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 25 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
23 import org.springframework.util.StringUtils; 26 import org.springframework.util.StringUtils;
24 import org.thingsboard.server.common.data.Customer; 27 import org.thingsboard.server.common.data.Customer;
  28 +import org.thingsboard.server.common.data.DashboardInfo;
25 import org.thingsboard.server.common.data.Tenant; 29 import org.thingsboard.server.common.data.Tenant;
26 import org.thingsboard.server.common.data.User; 30 import org.thingsboard.server.common.data.User;
27 import org.thingsboard.server.common.data.id.CustomerId; 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 import org.thingsboard.server.common.data.id.TenantId; 34 import org.thingsboard.server.common.data.id.TenantId;
  35 +import org.thingsboard.server.common.data.page.TextPageData;
29 import org.thingsboard.server.common.data.page.TextPageLink; 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 import org.thingsboard.server.common.data.security.Authority; 39 import org.thingsboard.server.common.data.security.Authority;
31 import org.thingsboard.server.common.data.security.UserCredentials; 40 import org.thingsboard.server.common.data.security.UserCredentials;
32 import org.thingsboard.server.dao.customer.CustomerService; 41 import org.thingsboard.server.dao.customer.CustomerService;
  42 +import org.thingsboard.server.dao.dashboard.DashboardService;
33 import org.thingsboard.server.dao.oauth2.OAuth2User; 43 import org.thingsboard.server.dao.oauth2.OAuth2User;
34 import org.thingsboard.server.dao.tenant.TenantService; 44 import org.thingsboard.server.dao.tenant.TenantService;
35 import org.thingsboard.server.dao.user.UserService; 45 import org.thingsboard.server.dao.user.UserService;
@@ -40,11 +50,15 @@ import org.thingsboard.server.service.security.model.UserPrincipal; @@ -40,11 +50,15 @@ import org.thingsboard.server.service.security.model.UserPrincipal;
40 import java.io.IOException; 50 import java.io.IOException;
41 import java.util.List; 51 import java.util.List;
42 import java.util.Optional; 52 import java.util.Optional;
  53 +import java.util.concurrent.ExecutionException;
43 import java.util.concurrent.locks.Lock; 54 import java.util.concurrent.locks.Lock;
44 import java.util.concurrent.locks.ReentrantLock; 55 import java.util.concurrent.locks.ReentrantLock;
45 56
46 @Slf4j 57 @Slf4j
47 public abstract class AbstractOAuth2ClientMapper { 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 @Autowired 63 @Autowired
50 private UserService userService; 64 private UserService userService;
@@ -59,6 +73,9 @@ public abstract class AbstractOAuth2ClientMapper { @@ -59,6 +73,9 @@ public abstract class AbstractOAuth2ClientMapper {
59 private CustomerService customerService; 73 private CustomerService customerService;
60 74
61 @Autowired 75 @Autowired
  76 + private DashboardService dashboardService;
  77 +
  78 + @Autowired
62 private InstallScripts installScripts; 79 private InstallScripts installScripts;
63 80
64 private final Lock userCreationLock = new ReentrantLock(); 81 private final Lock userCreationLock = new ReentrantLock();
@@ -92,6 +109,20 @@ public abstract class AbstractOAuth2ClientMapper { @@ -92,6 +109,20 @@ public abstract class AbstractOAuth2ClientMapper {
92 user.setEmail(oauth2User.getEmail()); 109 user.setEmail(oauth2User.getEmail());
93 user.setFirstName(oauth2User.getFirstName()); 110 user.setFirstName(oauth2User.getFirstName());
94 user.setLastName(oauth2User.getLastName()); 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 user = userService.saveUser(user); 126 user = userService.saveUser(user);
96 if (activateUser) { 127 if (activateUser) {
97 UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); 128 UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId());
@@ -143,4 +174,32 @@ public abstract class AbstractOAuth2ClientMapper { @@ -143,4 +174,32 @@ public abstract class AbstractOAuth2ClientMapper {
143 return customerService.saveCustomer(customer).getId(); 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,6 +56,10 @@ public class BasicOAuth2ClientMapper extends AbstractOAuth2ClientMapper implemen
56 String customerName = sub.replace(config.getBasic().getCustomerNamePattern()); 56 String customerName = sub.replace(config.getBasic().getCustomerNamePattern());
57 oauth2User.setCustomerName(customerName); 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 return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser()); 64 return getOrCreateSecurityUserFromOAuth2User(oauth2User, config.isAllowUserCreation(), config.isActivateUser());
61 } 65 }
@@ -56,8 +56,8 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme @@ -56,8 +56,8 @@ public class CustomOAuth2ClientMapper extends AbstractOAuth2ClientMapper impleme
56 try { 56 try {
57 return restTemplate.postForEntity(custom.getUrl(), request, OAuth2User.class).getBody(); 57 return restTemplate.postForEntity(custom.getUrl(), request, OAuth2User.class).getBody();
58 } catch (Exception e) { 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,6 +32,8 @@ import org.thingsboard.server.utils.MiscUtils;
32 import javax.servlet.http.HttpServletRequest; 32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse; 33 import javax.servlet.http.HttpServletResponse;
34 import java.io.IOException; 34 import java.io.IOException;
  35 +import java.net.URLEncoder;
  36 +import java.nio.charset.StandardCharsets;
35 37
36 @Component(value = "oauth2AuthenticationSuccessHandler") 38 @Component(value = "oauth2AuthenticationSuccessHandler")
37 @ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true") 39 @ConditionalOnProperty(prefix = "security.oauth2", value = "enabled", havingValue = "true")
@@ -57,16 +59,22 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS @@ -57,16 +59,22 @@ public class Oauth2AuthenticationSuccessHandler extends SimpleUrlAuthenticationS
57 public void onAuthenticationSuccess(HttpServletRequest request, 59 public void onAuthenticationSuccess(HttpServletRequest request,
58 HttpServletResponse response, 60 HttpServletResponse response,
59 Authentication authentication) throws IOException { 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 }
@@ -47,4 +47,13 @@ public enum Resource { @@ -47,4 +47,13 @@ public enum Resource {
47 public Optional<EntityType> getEntityType() { 47 public Optional<EntityType> getEntityType() {
48 return Optional.ofNullable(entityType); 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,28 +292,38 @@ public class DefaultDeviceStateService implements DeviceStateService {
292 } 292 }
293 } 293 }
294 294
  295 + volatile Set<TopicPartitionInfo> pendingPartitions;
  296 +
295 @Override 297 @Override
296 public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) { 298 public void onApplicationEvent(PartitionChangeEvent partitionChangeEvent) {
297 if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) { 299 if (ServiceType.TB_CORE.equals(partitionChangeEvent.getServiceType())) {
298 synchronized (this) { 300 synchronized (this) {
  301 + pendingPartitions = partitionChangeEvent.getPartitions();
299 if (!clusterUpdatePending) { 302 if (!clusterUpdatePending) {
300 clusterUpdatePending = true; 303 clusterUpdatePending = true;
301 queueExecutor.submit(() -> { 304 queueExecutor.submit(() -> {
302 clusterUpdatePending = false; 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 try { 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 addedPartitions.removeAll(partitionedDevices.keySet()); 319 addedPartitions.removeAll(partitionedDevices.keySet());
314 320
  321 + log.info("ADDED PARTITIONS: {}", addedPartitions);
  322 +
315 Set<TopicPartitionInfo> removedPartitions = new HashSet<>(partitionedDevices.keySet()); 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 // We no longer manage current partition of devices; 328 // We no longer manage current partition of devices;
319 removedPartitions.forEach(partition -> { 329 removedPartitions.forEach(partition -> {
@@ -224,7 +224,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer @@ -224,7 +224,7 @@ public class DefaultSubscriptionManagerService implements SubscriptionManagerSer
224 return null; 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 s -> { 228 s -> {
229 List<TsKvEntry> subscriptionUpdate = null; 229 List<TsKvEntry> subscriptionUpdate = null;
230 for (AttributeKvEntry kv : attributes) { 230 for (AttributeKvEntry kv : attributes) {
@@ -17,6 +17,6 @@ package org.thingsboard.server.service.subscription; @@ -17,6 +17,6 @@ package org.thingsboard.server.service.subscription;
17 17
18 public enum TbAttributeSubscriptionScope { 18 public enum TbAttributeSubscriptionScope {
19 19
20 - CLIENT_SCOPE, SHARED_SCOPE, SERVER_SCOPE 20 + ANY_SCOPE, CLIENT_SCOPE, SHARED_SCOPE, SERVER_SCOPE
21 21
22 } 22 }
@@ -345,7 +345,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi @@ -345,7 +345,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
345 keys.forEach(key -> subState.put(key, 0L)); 345 keys.forEach(key -> subState.put(key, 0L));
346 attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); 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 TbAttributeSubscription sub = TbAttributeSubscription.builder() 350 TbAttributeSubscription sub = TbAttributeSubscription.builder()
351 .serviceId(serviceId) 351 .serviceId(serviceId)
@@ -442,7 +442,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi @@ -442,7 +442,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
442 Map<String, Long> subState = new HashMap<>(attributesData.size()); 442 Map<String, Long> subState = new HashMap<>(attributesData.size());
443 attributesData.forEach(v -> subState.put(v.getKey(), v.getTs())); 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 TbAttributeSubscription sub = TbAttributeSubscription.builder() 447 TbAttributeSubscription sub = TbAttributeSubscription.builder()
448 .serviceId(serviceId) 448 .serviceId(serviceId)
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.transport; @@ -17,6 +17,7 @@ package org.thingsboard.server.service.transport;
17 17
18 import com.fasterxml.jackson.core.JsonProcessingException; 18 import com.fasterxml.jackson.core.JsonProcessingException;
19 import com.fasterxml.jackson.databind.ObjectMapper; 19 import com.fasterxml.jackson.databind.ObjectMapper;
  20 +import com.fasterxml.jackson.databind.node.ObjectNode;
20 import com.google.common.util.concurrent.Futures; 21 import com.google.common.util.concurrent.Futures;
21 import com.google.common.util.concurrent.ListenableFuture; 22 import com.google.common.util.concurrent.ListenableFuture;
22 import com.google.common.util.concurrent.MoreExecutors; 23 import com.google.common.util.concurrent.MoreExecutors;
@@ -24,13 +25,18 @@ import lombok.extern.slf4j.Slf4j; @@ -24,13 +25,18 @@ import lombok.extern.slf4j.Slf4j;
24 import org.springframework.beans.factory.annotation.Autowired; 25 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
26 import org.springframework.util.StringUtils; 27 import org.springframework.util.StringUtils;
  28 +import org.thingsboard.server.common.data.DataConstants;
27 import org.thingsboard.server.common.data.Device; 29 import org.thingsboard.server.common.data.Device;
28 import org.thingsboard.server.common.data.Tenant; 30 import org.thingsboard.server.common.data.Tenant;
  31 +import org.thingsboard.server.common.data.id.CustomerId;
29 import org.thingsboard.server.common.data.id.DeviceId; 32 import org.thingsboard.server.common.data.id.DeviceId;
30 import org.thingsboard.server.common.data.id.TenantId; 33 import org.thingsboard.server.common.data.id.TenantId;
31 import org.thingsboard.server.common.data.relation.EntityRelation; 34 import org.thingsboard.server.common.data.relation.EntityRelation;
32 import org.thingsboard.server.common.data.security.DeviceCredentials; 35 import org.thingsboard.server.common.data.security.DeviceCredentials;
33 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 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 import org.thingsboard.server.dao.device.DeviceCredentialsService; 40 import org.thingsboard.server.dao.device.DeviceCredentialsService;
35 import org.thingsboard.server.dao.device.DeviceService; 41 import org.thingsboard.server.dao.device.DeviceService;
36 import org.thingsboard.server.dao.relation.RelationService; 42 import org.thingsboard.server.dao.relation.RelationService;
@@ -48,6 +54,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509Ce @@ -48,6 +54,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509Ce
48 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 54 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
49 import org.thingsboard.server.queue.util.TbCoreComponent; 55 import org.thingsboard.server.queue.util.TbCoreComponent;
50 import org.thingsboard.server.service.executors.DbCallbackExecutorService; 56 import org.thingsboard.server.service.executors.DbCallbackExecutorService;
  57 +import org.thingsboard.server.service.queue.TbClusterService;
51 import org.thingsboard.server.service.state.DeviceStateService; 58 import org.thingsboard.server.service.state.DeviceStateService;
52 59
53 import java.util.UUID; 60 import java.util.UUID;
@@ -82,6 +89,9 @@ public class DefaultTransportApiService implements TransportApiService { @@ -82,6 +89,9 @@ public class DefaultTransportApiService implements TransportApiService {
82 @Autowired 89 @Autowired
83 private DbCallbackExecutorService dbCallbackExecutorService; 90 private DbCallbackExecutorService dbCallbackExecutorService;
84 91
  92 + @Autowired
  93 + protected TbClusterService tbClusterService;
  94 +
85 private ReentrantLock deviceCreationLock = new ReentrantLock(); 95 private ReentrantLock deviceCreationLock = new ReentrantLock();
86 96
87 @Override 97 @Override
@@ -119,14 +129,27 @@ public class DefaultTransportApiService implements TransportApiService { @@ -119,14 +129,27 @@ public class DefaultTransportApiService implements TransportApiService {
119 try { 129 try {
120 Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), requestMsg.getDeviceName()); 130 Device device = deviceService.findDeviceByTenantIdAndName(gateway.getTenantId(), requestMsg.getDeviceName());
121 if (device == null) { 131 if (device == null) {
  132 + TenantId tenantId = gateway.getTenantId();
122 device = new Device(); 133 device = new Device();
123 - device.setTenantId(gateway.getTenantId()); 134 + device.setTenantId(tenantId);
124 device.setName(requestMsg.getDeviceName()); 135 device.setName(requestMsg.getDeviceName());
125 device.setType(requestMsg.getDeviceType()); 136 device.setType(requestMsg.getDeviceType());
126 device.setCustomerId(gateway.getCustomerId()); 137 device.setCustomerId(gateway.getCustomerId());
127 device = deviceService.saveDevice(device); 138 device = deviceService.saveDevice(device);
128 relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created")); 139 relationService.saveRelationAsync(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created"));
129 deviceStateService.onDeviceAdded(device); 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 return TransportApiResponseMsg.newBuilder() 154 return TransportApiResponseMsg.newBuilder()
132 .setGetOrCreateDeviceResponseMsg(GetOrCreateDeviceFromGatewayResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build(); 155 .setGetOrCreateDeviceResponseMsg(GetOrCreateDeviceFromGatewayResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build();
@@ -54,6 +54,13 @@ server: @@ -54,6 +54,13 @@ server:
54 customer: 54 customer:
55 enabled: "${TB_SERVER_REST_LIMITS_CUSTOMER_ENABLED:false}" 55 enabled: "${TB_SERVER_REST_LIMITS_CUSTOMER_ENABLED:false}"
56 configuration: "${TB_SERVER_REST_LIMITS_CUSTOMER_CONFIGURATION:50:1,1000:60}" 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 # Zookeeper connection parameters. Used for service discovery. 65 # Zookeeper connection parameters. Used for service discovery.
59 zk: 66 zk:
@@ -148,6 +155,10 @@ security: @@ -148,6 +155,10 @@ security:
148 # If this field is not empty, user will be created as a user under defined Customer 155 # If this field is not empty, user will be created as a user under defined Customer
149 # %{attribute_key} as placeholder for attribute value of attributes of external user object 156 # %{attribute_key} as placeholder for attribute value of attributes of external user object
150 customerNamePattern: "${SECURITY_OAUTH2_DEFAULT_MAPPER_BASIC_CUSTOMER_NAME_PATTERN:}" 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 custom: 162 custom:
152 url: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_URL:}" 163 url: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_URL:}"
153 username: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_USERNAME:}" 164 username: "${SECURITY_OAUTH2_DEFAULT_MAPPER_CUSTOM_USERNAME:}"
@@ -676,7 +687,7 @@ queue: @@ -676,7 +687,7 @@ queue:
676 topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" 687 topic: "${TB_QUEUE_CORE_TOPIC:tb_core}"
677 poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" 688 poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}"
678 partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" 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 stats: 691 stats:
681 enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" 692 enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}"
682 print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:60000}" 693 print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:60000}"
@@ -688,6 +699,8 @@ queue: @@ -688,6 +699,8 @@ queue:
688 # JS Eval max pending requests 699 # JS Eval max pending requests
689 max_pending_requests: "${REMOTE_JS_MAX_PENDING_REQUESTS:10000}" 700 max_pending_requests: "${REMOTE_JS_MAX_PENDING_REQUESTS:10000}"
690 # JS Eval max request timeout 701 # JS Eval max request timeout
  702 + max_eval_requests_timeout: "${REMOTE_JS_MAX_EVAL_REQUEST_TIMEOUT:60000}"
  703 + # JS max request timeout
691 max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}" 704 max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}"
692 # JS response poll interval 705 # JS response poll interval
693 response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" 706 response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}"
@@ -696,7 +709,7 @@ queue: @@ -696,7 +709,7 @@ queue:
696 rule-engine: 709 rule-engine:
697 topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" 710 topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}"
698 poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" 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 stats: 713 stats:
701 enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" 714 enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}"
702 print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" 715 print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}"
@@ -705,7 +718,7 @@ queue: @@ -705,7 +718,7 @@ queue:
705 topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" 718 topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}"
706 poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" 719 poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}"
707 partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" 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 submit-strategy: 722 submit-strategy:
710 type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL 723 type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL
711 # For BATCH only 724 # For BATCH only
@@ -720,7 +733,7 @@ queue: @@ -720,7 +733,7 @@ queue:
720 topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" 733 topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}"
721 poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" 734 poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}"
722 partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" 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 submit-strategy: 737 submit-strategy:
725 type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL 738 type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL
726 # For BATCH only 739 # For BATCH only
@@ -735,7 +748,7 @@ queue: @@ -735,7 +748,7 @@ queue:
735 topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" 748 topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}"
736 poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" 749 poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}"
737 partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" 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 submit-strategy: 752 submit-strategy:
740 type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL 753 type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL
741 # For BATCH only 754 # For BATCH only
@@ -33,7 +33,6 @@ import org.junit.rules.TestRule; @@ -33,7 +33,6 @@ import org.junit.rules.TestRule;
33 import org.junit.rules.TestWatcher; 33 import org.junit.rules.TestWatcher;
34 import org.junit.runner.Description; 34 import org.junit.runner.Description;
35 import org.junit.runner.RunWith; 35 import org.junit.runner.RunWith;
36 -import org.mockito.Mockito;  
37 import org.springframework.beans.factory.annotation.Autowired; 36 import org.springframework.beans.factory.annotation.Autowired;
38 import org.springframework.boot.test.context.SpringBootContextLoader; 37 import org.springframework.boot.test.context.SpringBootContextLoader;
39 import org.springframework.boot.test.context.SpringBootTest; 38 import org.springframework.boot.test.context.SpringBootTest;
@@ -49,7 +48,6 @@ import org.springframework.mock.http.MockHttpOutputMessage; @@ -49,7 +48,6 @@ import org.springframework.mock.http.MockHttpOutputMessage;
49 import org.springframework.test.annotation.DirtiesContext; 48 import org.springframework.test.annotation.DirtiesContext;
50 import org.springframework.test.context.ActiveProfiles; 49 import org.springframework.test.context.ActiveProfiles;
51 import org.springframework.test.context.ContextConfiguration; 50 import org.springframework.test.context.ContextConfiguration;
52 -import org.springframework.test.context.TestPropertySource;  
53 import org.springframework.test.context.junit4.SpringRunner; 51 import org.springframework.test.context.junit4.SpringRunner;
54 import org.springframework.test.context.web.WebAppConfiguration; 52 import org.springframework.test.context.web.WebAppConfiguration;
55 import org.springframework.test.web.servlet.MockMvc; 53 import org.springframework.test.web.servlet.MockMvc;
@@ -75,7 +73,6 @@ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; @@ -75,7 +73,6 @@ import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest;
75 import org.thingsboard.server.service.security.auth.rest.LoginRequest; 73 import org.thingsboard.server.service.security.auth.rest.LoginRequest;
76 74
77 import java.io.IOException; 75 import java.io.IOException;
78 -import java.nio.charset.Charset;  
79 import java.util.ArrayList; 76 import java.util.ArrayList;
80 import java.util.Arrays; 77 import java.util.Arrays;
81 import java.util.Comparator; 78 import java.util.Comparator;
@@ -223,6 +220,27 @@ public abstract class AbstractControllerTest { @@ -223,6 +220,27 @@ public abstract class AbstractControllerTest {
223 login(CUSTOMER_USER_EMAIL, CUSTOMER_USER_PASSWORD); 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 protected User createUserAndLogin(User user, String password) throws Exception { 244 protected User createUserAndLogin(User user, String password) throws Exception {
227 User savedUser = doPost("/api/user", user, User.class); 245 User savedUser = doPost("/api/user", user, User.class);
228 logout(); 246 logout();
@@ -99,6 +99,18 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest { @@ -99,6 +99,18 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
99 } 99 }
100 100
101 @Test 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 public void testFindAssetById() throws Exception { 114 public void testFindAssetById() throws Exception {
103 Asset asset = new Asset(); 115 Asset asset = new Asset();
104 asset.setName("My asset"); 116 asset.setName("My asset");
@@ -23,6 +23,8 @@ import java.util.Collections; @@ -23,6 +23,8 @@ import java.util.Collections;
23 import java.util.List; 23 import java.util.List;
24 24
25 import org.apache.commons.lang3.RandomStringUtils; 25 import org.apache.commons.lang3.RandomStringUtils;
  26 +import org.junit.After;
  27 +import org.junit.Before;
26 import org.thingsboard.server.common.data.Customer; 28 import org.thingsboard.server.common.data.Customer;
27 import org.thingsboard.server.common.data.Tenant; 29 import org.thingsboard.server.common.data.Tenant;
28 import org.thingsboard.server.common.data.User; 30 import org.thingsboard.server.common.data.User;
@@ -38,25 +40,39 @@ import com.fasterxml.jackson.core.type.TypeReference; @@ -38,25 +40,39 @@ import com.fasterxml.jackson.core.type.TypeReference;
38 public abstract class BaseCustomerControllerTest extends AbstractControllerTest { 40 public abstract class BaseCustomerControllerTest extends AbstractControllerTest {
39 41
40 private IdComparator<Customer> idComparator = new IdComparator<>(); 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 loginSysAdmin(); 49 loginSysAdmin();
45 50
46 Tenant tenant = new Tenant(); 51 Tenant tenant = new Tenant();
47 tenant.setTitle("My tenant"); 52 tenant.setTitle("My tenant");
48 - Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 53 + savedTenant = doPost("/api/tenant", tenant, Tenant.class);
49 Assert.assertNotNull(savedTenant); 54 Assert.assertNotNull(savedTenant);
50 -  
51 - User tenantAdmin = new User(); 55 +
  56 + tenantAdmin = new User();
52 tenantAdmin.setAuthority(Authority.TENANT_ADMIN); 57 tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
53 tenantAdmin.setTenantId(savedTenant.getId()); 58 tenantAdmin.setTenantId(savedTenant.getId());
54 tenantAdmin.setEmail("tenant2@thingsboard.org"); 59 tenantAdmin.setEmail("tenant2@thingsboard.org");
55 tenantAdmin.setFirstName("Joe"); 60 tenantAdmin.setFirstName("Joe");
56 tenantAdmin.setLastName("Downs"); 61 tenantAdmin.setLastName("Downs");
57 - 62 +
58 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); 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 Customer customer = new Customer(); 76 Customer customer = new Customer();
61 customer.setTitle("My customer"); 77 customer.setTitle("My customer");
62 Customer savedCustomer = doPost("/api/customer", customer, Customer.class); 78 Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
@@ -66,266 +82,159 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest @@ -66,266 +82,159 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
66 Assert.assertEquals(customer.getTitle(), savedCustomer.getTitle()); 82 Assert.assertEquals(customer.getTitle(), savedCustomer.getTitle());
67 savedCustomer.setTitle("My new customer"); 83 savedCustomer.setTitle("My new customer");
68 doPost("/api/customer", savedCustomer, Customer.class); 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 Assert.assertEquals(foundCustomer.getTitle(), savedCustomer.getTitle()); 87 Assert.assertEquals(foundCustomer.getTitle(), savedCustomer.getTitle());
72 - 88 +
73 doDelete("/api/customer/"+savedCustomer.getId().getId().toString()) 89 doDelete("/api/customer/"+savedCustomer.getId().getId().toString())
74 .andExpect(status().isOk()); 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 @Test 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 Customer customer = new Customer(); 111 Customer customer = new Customer();
102 customer.setTitle("My customer"); 112 customer.setTitle("My customer");
103 Customer savedCustomer = doPost("/api/customer", customer, Customer.class); 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 Assert.assertNotNull(foundCustomer); 116 Assert.assertNotNull(foundCustomer);
107 Assert.assertEquals(savedCustomer, foundCustomer); 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 @Test 123 @Test
119 public void testDeleteCustomer() throws Exception { 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 Customer customer = new Customer(); 125 Customer customer = new Customer();
138 customer.setTitle("My customer"); 126 customer.setTitle("My customer");
139 Customer savedCustomer = doPost("/api/customer", customer, Customer.class); 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 @Test 136 @Test
154 public void testSaveCustomerWithEmptyTitle() throws Exception { 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 Customer customer = new Customer(); 138 Customer customer = new Customer();
173 doPost("/api/customer", customer) 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 @Test 144 @Test
184 public void testSaveCustomerWithInvalidEmail() throws Exception { 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 Customer customer = new Customer(); 146 Customer customer = new Customer();
203 customer.setTitle("My customer"); 147 customer.setTitle("My customer");
204 customer.setEmail("invalid@mail"); 148 customer.setEmail("invalid@mail");
205 doPost("/api/customer", customer) 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 @Test 159 @Test
216 public void testFindCustomers() throws Exception { 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 TenantId tenantId = savedTenant.getId(); 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 List<Customer> customers = new ArrayList<>(); 163 List<Customer> customers = new ArrayList<>();
236 - for (int i=0;i<135;i++) { 164 + for (int i = 0; i < 135; i++) {
237 Customer customer = new Customer(); 165 Customer customer = new Customer();
238 customer.setTenantId(tenantId); 166 customer.setTenantId(tenantId);
239 - customer.setTitle("Customer"+i); 167 + customer.setTitle("Customer" + i);
240 customers.add(doPost("/api/customer", customer, Customer.class)); 168 customers.add(doPost("/api/customer", customer, Customer.class));
241 } 169 }
242 - 170 +
243 List<Customer> loadedCustomers = new ArrayList<>(); 171 List<Customer> loadedCustomers = new ArrayList<>();
244 TextPageLink pageLink = new TextPageLink(23); 172 TextPageLink pageLink = new TextPageLink(23);
245 TextPageData<Customer> pageData = null; 173 TextPageData<Customer> pageData = null;
246 do { 174 do {
247 - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); 175 + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() {
  176 + }, pageLink);
248 loadedCustomers.addAll(pageData.getData()); 177 loadedCustomers.addAll(pageData.getData());
249 if (pageData.hasNext()) { 178 if (pageData.hasNext()) {
250 pageLink = pageData.getNextPageLink(); 179 pageLink = pageData.getNextPageLink();
251 } 180 }
252 } while (pageData.hasNext()); 181 } while (pageData.hasNext());
253 - 182 +
254 Collections.sort(customers, idComparator); 183 Collections.sort(customers, idComparator);
255 Collections.sort(loadedCustomers, idComparator); 184 Collections.sort(loadedCustomers, idComparator);
256 - 185 +
257 Assert.assertEquals(customers, loadedCustomers); 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 @Test 189 @Test
266 public void testFindCustomersByTitle() throws Exception { 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 TenantId tenantId = savedTenant.getId(); 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 String title1 = "Customer title 1"; 193 String title1 = "Customer title 1";
287 List<Customer> customersTitle1 = new ArrayList<>(); 194 List<Customer> customersTitle1 = new ArrayList<>();
288 - for (int i=0;i<143;i++) { 195 + for (int i = 0; i < 143; i++) {
289 Customer customer = new Customer(); 196 Customer customer = new Customer();
290 customer.setTenantId(tenantId); 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 title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); 200 title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
294 customer.setTitle(title); 201 customer.setTitle(title);
295 customersTitle1.add(doPost("/api/customer", customer, Customer.class)); 202 customersTitle1.add(doPost("/api/customer", customer, Customer.class));
296 } 203 }
297 String title2 = "Customer title 2"; 204 String title2 = "Customer title 2";
298 List<Customer> customersTitle2 = new ArrayList<>(); 205 List<Customer> customersTitle2 = new ArrayList<>();
299 - for (int i=0;i<175;i++) { 206 + for (int i = 0; i < 175; i++) {
300 Customer customer = new Customer(); 207 Customer customer = new Customer();
301 customer.setTenantId(tenantId); 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 title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase(); 211 title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
305 customer.setTitle(title); 212 customer.setTitle(title);
306 customersTitle2.add(doPost("/api/customer", customer, Customer.class)); 213 customersTitle2.add(doPost("/api/customer", customer, Customer.class));
307 } 214 }
308 - 215 +
309 List<Customer> loadedCustomersTitle1 = new ArrayList<>(); 216 List<Customer> loadedCustomersTitle1 = new ArrayList<>();
310 TextPageLink pageLink = new TextPageLink(15, title1); 217 TextPageLink pageLink = new TextPageLink(15, title1);
311 TextPageData<Customer> pageData = null; 218 TextPageData<Customer> pageData = null;
312 do { 219 do {
313 - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); 220 + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() {
  221 + }, pageLink);
314 loadedCustomersTitle1.addAll(pageData.getData()); 222 loadedCustomersTitle1.addAll(pageData.getData());
315 if (pageData.hasNext()) { 223 if (pageData.hasNext()) {
316 pageLink = pageData.getNextPageLink(); 224 pageLink = pageData.getNextPageLink();
317 } 225 }
318 } while (pageData.hasNext()); 226 } while (pageData.hasNext());
319 - 227 +
320 Collections.sort(customersTitle1, idComparator); 228 Collections.sort(customersTitle1, idComparator);
321 Collections.sort(loadedCustomersTitle1, idComparator); 229 Collections.sort(loadedCustomersTitle1, idComparator);
322 - 230 +
323 Assert.assertEquals(customersTitle1, loadedCustomersTitle1); 231 Assert.assertEquals(customersTitle1, loadedCustomersTitle1);
324 - 232 +
325 List<Customer> loadedCustomersTitle2 = new ArrayList<>(); 233 List<Customer> loadedCustomersTitle2 = new ArrayList<>();
326 pageLink = new TextPageLink(4, title2); 234 pageLink = new TextPageLink(4, title2);
327 do { 235 do {
328 - pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>(){}, pageLink); 236 + pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference<TextPageData<Customer>>() {
  237 + }, pageLink);
329 loadedCustomersTitle2.addAll(pageData.getData()); 238 loadedCustomersTitle2.addAll(pageData.getData());
330 if (pageData.hasNext()) { 239 if (pageData.hasNext()) {
331 pageLink = pageData.getNextPageLink(); 240 pageLink = pageData.getNextPageLink();
@@ -334,33 +243,30 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest @@ -334,33 +243,30 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
334 243
335 Collections.sort(customersTitle2, idComparator); 244 Collections.sort(customersTitle2, idComparator);
336 Collections.sort(loadedCustomersTitle2, idComparator); 245 Collections.sort(loadedCustomersTitle2, idComparator);
337 - 246 +
338 Assert.assertEquals(customersTitle2, loadedCustomersTitle2); 247 Assert.assertEquals(customersTitle2, loadedCustomersTitle2);
339 - 248 +
340 for (Customer customer : loadedCustomersTitle1) { 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 pageLink = new TextPageLink(4, title1); 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 Assert.assertFalse(pageData.hasNext()); 257 Assert.assertFalse(pageData.hasNext());
348 Assert.assertEquals(0, pageData.getData().size()); 258 Assert.assertEquals(0, pageData.getData().size());
349 - 259 +
350 for (Customer customer : loadedCustomersTitle2) { 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 pageLink = new TextPageLink(4, title2); 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 Assert.assertFalse(pageData.hasNext()); 268 Assert.assertFalse(pageData.hasNext());
358 Assert.assertEquals(0, pageData.getData().size()); 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,10 +16,8 @@
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
18 import static org.hamcrest.Matchers.containsString; 18 import static org.hamcrest.Matchers.containsString;
19 -import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;  
20 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 19 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
21 20
22 -import java.sql.Time;  
23 import java.util.ArrayList; 21 import java.util.ArrayList;
24 import java.util.Collections; 22 import java.util.Collections;
25 import java.util.List; 23 import java.util.List;
@@ -33,7 +31,6 @@ import org.thingsboard.server.common.data.page.TextPageLink; @@ -33,7 +31,6 @@ import org.thingsboard.server.common.data.page.TextPageLink;
33 import org.thingsboard.server.common.data.page.TimePageData; 31 import org.thingsboard.server.common.data.page.TimePageData;
34 import org.thingsboard.server.common.data.page.TimePageLink; 32 import org.thingsboard.server.common.data.page.TimePageLink;
35 import org.thingsboard.server.common.data.security.Authority; 33 import org.thingsboard.server.common.data.security.Authority;
36 -import org.thingsboard.server.dao.model.ModelConstants;  
37 import org.junit.After; 34 import org.junit.After;
38 import org.junit.Assert; 35 import org.junit.Assert;
39 import org.junit.Before; 36 import org.junit.Before;
@@ -93,6 +90,17 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest @@ -93,6 +90,17 @@ public abstract class BaseDashboardControllerTest extends AbstractControllerTest
93 Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class); 90 Dashboard foundDashboard = doGet("/api/dashboard/" + savedDashboard.getId().getId().toString(), Dashboard.class);
94 Assert.assertEquals(foundDashboard.getTitle(), savedDashboard.getTitle()); 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 @Test 105 @Test
98 public void testFindDashboardById() throws Exception { 106 public void testFindDashboardById() throws Exception {
@@ -107,6 +107,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { @@ -107,6 +107,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
107 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); 107 Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
108 Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); 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 @Test 122 @Test
112 public void testFindDeviceById() throws Exception { 123 public void testFindDeviceById() throws Exception {
@@ -25,7 +25,6 @@ import org.eclipse.paho.client.mqttv3.MqttMessage; @@ -25,7 +25,6 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
25 import org.junit.After; 25 import org.junit.After;
26 import org.junit.Assert; 26 import org.junit.Assert;
27 import org.junit.Before; 27 import org.junit.Before;
28 -import org.junit.Ignore;  
29 import org.junit.Test; 28 import org.junit.Test;
30 import org.thingsboard.server.common.data.Customer; 29 import org.thingsboard.server.common.data.Customer;
31 import org.thingsboard.server.common.data.Device; 30 import org.thingsboard.server.common.data.Device;
@@ -132,6 +131,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes @@ -132,6 +131,15 @@ public abstract class BaseEntityViewControllerTest extends AbstractControllerTes
132 assertEquals(foundEntityView.getKeys(), telemetry); 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 @Test 143 @Test
136 public void testDeleteEntityView() throws Exception { 144 public void testDeleteEntityView() throws Exception {
137 EntityView view = getNewSavedEntityView("Test entity view"); 145 EntityView view = getNewSavedEntityView("Test entity view");
@@ -38,21 +38,23 @@ import java.util.List; @@ -38,21 +38,23 @@ import java.util.List;
38 38
39 import static org.hamcrest.Matchers.containsString; 39 import static org.hamcrest.Matchers.containsString;
40 import static org.hamcrest.Matchers.is; 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 public abstract class BaseUserControllerTest extends AbstractControllerTest { 45 public abstract class BaseUserControllerTest extends AbstractControllerTest {
44 - 46 +
45 private IdComparator<User> idComparator = new IdComparator<>(); 47 private IdComparator<User> idComparator = new IdComparator<>();
46 48
47 @Test 49 @Test
48 public void testSaveUser() throws Exception { 50 public void testSaveUser() throws Exception {
49 loginSysAdmin(); 51 loginSysAdmin();
50 - 52 +
51 Tenant tenant = new Tenant(); 53 Tenant tenant = new Tenant();
52 tenant.setTitle("My tenant"); 54 tenant.setTitle("My tenant");
53 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 55 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
54 Assert.assertNotNull(savedTenant); 56 Assert.assertNotNull(savedTenant);
55 - 57 +
56 String email = "tenant2@thingsboard.org"; 58 String email = "tenant2@thingsboard.org";
57 User user = new User(); 59 User user = new User();
58 user.setAuthority(Authority.TENANT_ADMIN); 60 user.setAuthority(Authority.TENANT_ADMIN);
@@ -66,13 +68,13 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -66,13 +68,13 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
66 Assert.assertTrue(savedUser.getCreatedTime() > 0); 68 Assert.assertTrue(savedUser.getCreatedTime() > 0);
67 Assert.assertEquals(user.getEmail(), savedUser.getEmail()); 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 Assert.assertEquals(foundUser, savedUser); 72 Assert.assertEquals(foundUser, savedUser);
71 - 73 +
72 logout(); 74 logout();
73 doGet("/api/noauth/activate?activateToken={activateToken}", TestMailService.currentActivateToken) 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 JsonNode activateRequest = new ObjectMapper().createObjectNode() 79 JsonNode activateRequest = new ObjectMapper().createObjectNode()
78 .put("activateToken", TestMailService.currentActivateToken) 80 .put("activateToken", TestMailService.currentActivateToken)
@@ -82,36 +84,61 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -82,36 +84,61 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
82 validateAndSetJwtToken(tokenInfo, email); 84 validateAndSetJwtToken(tokenInfo, email);
83 85
84 doGet("/api/auth/user") 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 logout(); 91 logout();
90 - 92 +
91 login(email, "testPassword"); 93 login(email, "testPassword");
92 - 94 +
93 doGet("/api/auth/user") 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 loginSysAdmin(); 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 @Test 133 @Test
107 public void testResetPassword() throws Exception { 134 public void testResetPassword() throws Exception {
108 loginSysAdmin(); 135 loginSysAdmin();
109 - 136 +
110 Tenant tenant = new Tenant(); 137 Tenant tenant = new Tenant();
111 tenant.setTitle("My tenant"); 138 tenant.setTitle("My tenant");
112 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 139 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
113 Assert.assertNotNull(savedTenant); 140 Assert.assertNotNull(savedTenant);
114 - 141 +
115 String email = "tenant2@thingsboard.org"; 142 String email = "tenant2@thingsboard.org";
116 User user = new User(); 143 User user = new User();
117 user.setAuthority(Authority.TENANT_ADMIN); 144 user.setAuthority(Authority.TENANT_ADMIN);
@@ -119,7 +146,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -119,7 +146,7 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
119 user.setEmail(email); 146 user.setEmail(email);
120 user.setFirstName("Joe"); 147 user.setFirstName("Joe");
121 user.setLastName("Downs"); 148 user.setLastName("Downs");
122 - 149 +
123 User savedUser = createUserAndLogin(user, "testPassword1"); 150 User savedUser = createUserAndLogin(user, "testPassword1");
124 logout(); 151 logout();
125 152
@@ -127,10 +154,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -127,10 +154,10 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
127 .put("email", email); 154 .put("email", email);
128 155
129 doPost("/api/noauth/resetPasswordByEmail", resetPasswordByEmailRequest) 156 doPost("/api/noauth/resetPasswordByEmail", resetPasswordByEmailRequest)
130 - .andExpect(status().isOk()); 157 + .andExpect(status().isOk());
131 doGet("/api/noauth/resetPassword?resetToken={resetToken}", TestMailService.currentResetPasswordToken) 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 JsonNode resetPasswordRequest = new ObjectMapper().createObjectNode() 162 JsonNode resetPasswordRequest = new ObjectMapper().createObjectNode()
136 .put("resetToken", TestMailService.currentResetPasswordToken) 163 .put("resetToken", TestMailService.currentResetPasswordToken)
@@ -140,35 +167,35 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -140,35 +167,35 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
140 validateAndSetJwtToken(tokenInfo, email); 167 validateAndSetJwtToken(tokenInfo, email);
141 168
142 doGet("/api/auth/user") 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 logout(); 174 logout();
148 - 175 +
149 login(email, "testPassword2"); 176 login(email, "testPassword2");
150 doGet("/api/auth/user") 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 loginSysAdmin(); 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 @Test 190 @Test
164 public void testFindUserById() throws Exception { 191 public void testFindUserById() throws Exception {
165 loginSysAdmin(); 192 loginSysAdmin();
166 - 193 +
167 Tenant tenant = new Tenant(); 194 Tenant tenant = new Tenant();
168 tenant.setTitle("My tenant"); 195 tenant.setTitle("My tenant");
169 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 196 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
170 Assert.assertNotNull(savedTenant); 197 Assert.assertNotNull(savedTenant);
171 - 198 +
172 String email = "tenant2@thingsboard.org"; 199 String email = "tenant2@thingsboard.org";
173 User user = new User(); 200 User user = new User();
174 user.setAuthority(Authority.TENANT_ADMIN); 201 user.setAuthority(Authority.TENANT_ADMIN);
@@ -176,25 +203,25 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -176,25 +203,25 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
176 user.setEmail(email); 203 user.setEmail(email);
177 user.setFirstName("Joe"); 204 user.setFirstName("Joe");
178 user.setLastName("Downs"); 205 user.setLastName("Downs");
179 - 206 +
180 User savedUser = doPost("/api/user", user, User.class); 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 Assert.assertNotNull(foundUser); 209 Assert.assertNotNull(foundUser);
183 Assert.assertEquals(savedUser, foundUser); 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 @Test 216 @Test
190 public void testSaveUserWithSameEmail() throws Exception { 217 public void testSaveUserWithSameEmail() throws Exception {
191 loginSysAdmin(); 218 loginSysAdmin();
192 - 219 +
193 Tenant tenant = new Tenant(); 220 Tenant tenant = new Tenant();
194 tenant.setTitle("My tenant"); 221 tenant.setTitle("My tenant");
195 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 222 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
196 Assert.assertNotNull(savedTenant); 223 Assert.assertNotNull(savedTenant);
197 - 224 +
198 String email = TENANT_ADMIN_EMAIL; 225 String email = TENANT_ADMIN_EMAIL;
199 User user = new User(); 226 User user = new User();
200 user.setAuthority(Authority.TENANT_ADMIN); 227 user.setAuthority(Authority.TENANT_ADMIN);
@@ -202,24 +229,24 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -202,24 +229,24 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
202 user.setEmail(email); 229 user.setEmail(email);
203 user.setFirstName("Joe"); 230 user.setFirstName("Joe");
204 user.setLastName("Downs"); 231 user.setLastName("Downs");
205 - 232 +
206 doPost("/api/user", user) 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 @Test 241 @Test
215 public void testSaveUserWithInvalidEmail() throws Exception { 242 public void testSaveUserWithInvalidEmail() throws Exception {
216 loginSysAdmin(); 243 loginSysAdmin();
217 - 244 +
218 Tenant tenant = new Tenant(); 245 Tenant tenant = new Tenant();
219 tenant.setTitle("My tenant"); 246 tenant.setTitle("My tenant");
220 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 247 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
221 Assert.assertNotNull(savedTenant); 248 Assert.assertNotNull(savedTenant);
222 - 249 +
223 String email = "tenant_thingsboard.org"; 250 String email = "tenant_thingsboard.org";
224 User user = new User(); 251 User user = new User();
225 user.setAuthority(Authority.TENANT_ADMIN); 252 user.setAuthority(Authority.TENANT_ADMIN);
@@ -227,62 +254,62 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -227,62 +254,62 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
227 user.setEmail(email); 254 user.setEmail(email);
228 user.setFirstName("Joe"); 255 user.setFirstName("Joe");
229 user.setLastName("Downs"); 256 user.setLastName("Downs");
230 - 257 +
231 doPost("/api/user", user) 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 @Test 266 @Test
240 public void testSaveUserWithEmptyEmail() throws Exception { 267 public void testSaveUserWithEmptyEmail() throws Exception {
241 loginSysAdmin(); 268 loginSysAdmin();
242 - 269 +
243 Tenant tenant = new Tenant(); 270 Tenant tenant = new Tenant();
244 tenant.setTitle("My tenant"); 271 tenant.setTitle("My tenant");
245 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 272 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
246 Assert.assertNotNull(savedTenant); 273 Assert.assertNotNull(savedTenant);
247 - 274 +
248 User user = new User(); 275 User user = new User();
249 user.setAuthority(Authority.TENANT_ADMIN); 276 user.setAuthority(Authority.TENANT_ADMIN);
250 user.setTenantId(savedTenant.getId()); 277 user.setTenantId(savedTenant.getId());
251 user.setFirstName("Joe"); 278 user.setFirstName("Joe");
252 user.setLastName("Downs"); 279 user.setLastName("Downs");
253 - 280 +
254 doPost("/api/user", user) 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 @Test 289 @Test
263 public void testSaveUserWithoutTenant() throws Exception { 290 public void testSaveUserWithoutTenant() throws Exception {
264 loginSysAdmin(); 291 loginSysAdmin();
265 - 292 +
266 User user = new User(); 293 User user = new User();
267 user.setAuthority(Authority.TENANT_ADMIN); 294 user.setAuthority(Authority.TENANT_ADMIN);
268 user.setEmail("tenant2@thingsboard.org"); 295 user.setEmail("tenant2@thingsboard.org");
269 user.setFirstName("Joe"); 296 user.setFirstName("Joe");
270 user.setLastName("Downs"); 297 user.setLastName("Downs");
271 - 298 +
272 doPost("/api/user", user) 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 @Test 304 @Test
278 public void testDeleteUser() throws Exception { 305 public void testDeleteUser() throws Exception {
279 loginSysAdmin(); 306 loginSysAdmin();
280 - 307 +
281 Tenant tenant = new Tenant(); 308 Tenant tenant = new Tenant();
282 tenant.setTitle("My tenant"); 309 tenant.setTitle("My tenant");
283 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 310 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
284 Assert.assertNotNull(savedTenant); 311 Assert.assertNotNull(savedTenant);
285 - 312 +
286 String email = "tenant2@thingsboard.org"; 313 String email = "tenant2@thingsboard.org";
287 User user = new User(); 314 User user = new User();
288 user.setAuthority(Authority.TENANT_ADMIN); 315 user.setAuthority(Authority.TENANT_ADMIN);
@@ -290,176 +317,182 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -290,176 +317,182 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
290 user.setEmail(email); 317 user.setEmail(email);
291 user.setFirstName("Joe"); 318 user.setFirstName("Joe");
292 user.setLastName("Downs"); 319 user.setLastName("Downs");
293 - 320 +
294 User savedUser = doPost("/api/user", user, User.class); 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 Assert.assertNotNull(foundUser); 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 @Test 335 @Test
309 public void testFindTenantAdmins() throws Exception { 336 public void testFindTenantAdmins() throws Exception {
310 loginSysAdmin(); 337 loginSysAdmin();
311 - 338 +
312 Tenant tenant = new Tenant(); 339 Tenant tenant = new Tenant();
313 tenant.setTitle("My tenant"); 340 tenant.setTitle("My tenant");
314 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 341 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
315 Assert.assertNotNull(savedTenant); 342 Assert.assertNotNull(savedTenant);
316 - 343 +
317 TenantId tenantId = savedTenant.getId(); 344 TenantId tenantId = savedTenant.getId();
318 - 345 +
319 List<User> tenantAdmins = new ArrayList<>(); 346 List<User> tenantAdmins = new ArrayList<>();
320 - for (int i=0;i<64;i++) { 347 + for (int i = 0; i < 64; i++) {
321 User user = new User(); 348 User user = new User();
322 user.setAuthority(Authority.TENANT_ADMIN); 349 user.setAuthority(Authority.TENANT_ADMIN);
323 user.setTenantId(tenantId); 350 user.setTenantId(tenantId);
324 user.setEmail("testTenant" + i + "@thingsboard.org"); 351 user.setEmail("testTenant" + i + "@thingsboard.org");
325 tenantAdmins.add(doPost("/api/user", user, User.class)); 352 tenantAdmins.add(doPost("/api/user", user, User.class));
326 } 353 }
327 - 354 +
328 List<User> loadedTenantAdmins = new ArrayList<>(); 355 List<User> loadedTenantAdmins = new ArrayList<>();
329 TextPageLink pageLink = new TextPageLink(33); 356 TextPageLink pageLink = new TextPageLink(33);
330 TextPageData<User> pageData = null; 357 TextPageData<User> pageData = null;
331 do { 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 loadedTenantAdmins.addAll(pageData.getData()); 362 loadedTenantAdmins.addAll(pageData.getData());
335 if (pageData.hasNext()) { 363 if (pageData.hasNext()) {
336 pageLink = pageData.getNextPageLink(); 364 pageLink = pageData.getNextPageLink();
337 } 365 }
338 } while (pageData.hasNext()); 366 } while (pageData.hasNext());
339 - 367 +
340 Collections.sort(tenantAdmins, idComparator); 368 Collections.sort(tenantAdmins, idComparator);
341 Collections.sort(loadedTenantAdmins, idComparator); 369 Collections.sort(loadedTenantAdmins, idComparator);
342 - 370 +
343 Assert.assertEquals(tenantAdmins, loadedTenantAdmins); 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 pageLink = new TextPageLink(33); 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 Assert.assertFalse(pageData.hasNext()); 380 Assert.assertFalse(pageData.hasNext());
352 Assert.assertTrue(pageData.getData().isEmpty()); 381 Assert.assertTrue(pageData.getData().isEmpty());
353 } 382 }
354 - 383 +
355 @Test 384 @Test
356 public void testFindTenantAdminsByEmail() throws Exception { 385 public void testFindTenantAdminsByEmail() throws Exception {
357 - 386 +
358 loginSysAdmin(); 387 loginSysAdmin();
359 - 388 +
360 Tenant tenant = new Tenant(); 389 Tenant tenant = new Tenant();
361 tenant.setTitle("My tenant"); 390 tenant.setTitle("My tenant");
362 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 391 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
363 Assert.assertNotNull(savedTenant); 392 Assert.assertNotNull(savedTenant);
364 - 393 +
365 TenantId tenantId = savedTenant.getId(); 394 TenantId tenantId = savedTenant.getId();
366 -  
367 - String email1 = "testEmail1"; 395 +
  396 + String email1 = "testEmail1";
368 List<User> tenantAdminsEmail1 = new ArrayList<>(); 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 User user = new User(); 400 User user = new User();
372 user.setAuthority(Authority.TENANT_ADMIN); 401 user.setAuthority(Authority.TENANT_ADMIN);
373 user.setTenantId(tenantId); 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 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); 405 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase();
377 user.setEmail(email); 406 user.setEmail(email);
378 tenantAdminsEmail1.add(doPost("/api/user", user, User.class)); 407 tenantAdminsEmail1.add(doPost("/api/user", user, User.class));
379 } 408 }
380 -  
381 - String email2 = "testEmail2"; 409 +
  410 + String email2 = "testEmail2";
382 List<User> tenantAdminsEmail2 = new ArrayList<>(); 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 User user = new User(); 414 User user = new User();
386 user.setAuthority(Authority.TENANT_ADMIN); 415 user.setAuthority(Authority.TENANT_ADMIN);
387 user.setTenantId(tenantId); 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 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); 419 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase();
391 user.setEmail(email); 420 user.setEmail(email);
392 tenantAdminsEmail2.add(doPost("/api/user", user, User.class)); 421 tenantAdminsEmail2.add(doPost("/api/user", user, User.class));
393 } 422 }
394 - 423 +
395 List<User> loadedTenantAdminsEmail1 = new ArrayList<>(); 424 List<User> loadedTenantAdminsEmail1 = new ArrayList<>();
396 TextPageLink pageLink = new TextPageLink(33, email1); 425 TextPageLink pageLink = new TextPageLink(33, email1);
397 TextPageData<User> pageData = null; 426 TextPageData<User> pageData = null;
398 do { 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 loadedTenantAdminsEmail1.addAll(pageData.getData()); 431 loadedTenantAdminsEmail1.addAll(pageData.getData());
402 if (pageData.hasNext()) { 432 if (pageData.hasNext()) {
403 pageLink = pageData.getNextPageLink(); 433 pageLink = pageData.getNextPageLink();
404 } 434 }
405 } while (pageData.hasNext()); 435 } while (pageData.hasNext());
406 - 436 +
407 Collections.sort(tenantAdminsEmail1, idComparator); 437 Collections.sort(tenantAdminsEmail1, idComparator);
408 Collections.sort(loadedTenantAdminsEmail1, idComparator); 438 Collections.sort(loadedTenantAdminsEmail1, idComparator);
409 - 439 +
410 Assert.assertEquals(tenantAdminsEmail1, loadedTenantAdminsEmail1); 440 Assert.assertEquals(tenantAdminsEmail1, loadedTenantAdminsEmail1);
411 - 441 +
412 List<User> loadedTenantAdminsEmail2 = new ArrayList<>(); 442 List<User> loadedTenantAdminsEmail2 = new ArrayList<>();
413 pageLink = new TextPageLink(16, email2); 443 pageLink = new TextPageLink(16, email2);
414 do { 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 loadedTenantAdminsEmail2.addAll(pageData.getData()); 448 loadedTenantAdminsEmail2.addAll(pageData.getData());
418 if (pageData.hasNext()) { 449 if (pageData.hasNext()) {
419 pageLink = pageData.getNextPageLink(); 450 pageLink = pageData.getNextPageLink();
420 } 451 }
421 } while (pageData.hasNext()); 452 } while (pageData.hasNext());
422 - 453 +
423 Collections.sort(tenantAdminsEmail2, idComparator); 454 Collections.sort(tenantAdminsEmail2, idComparator);
424 Collections.sort(loadedTenantAdminsEmail2, idComparator); 455 Collections.sort(loadedTenantAdminsEmail2, idComparator);
425 - 456 +
426 Assert.assertEquals(tenantAdminsEmail2, loadedTenantAdminsEmail2); 457 Assert.assertEquals(tenantAdminsEmail2, loadedTenantAdminsEmail2);
427 - 458 +
428 for (User user : loadedTenantAdminsEmail1) { 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 pageLink = new TextPageLink(4, email1); 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 Assert.assertFalse(pageData.hasNext()); 468 Assert.assertFalse(pageData.hasNext());
437 Assert.assertEquals(0, pageData.getData().size()); 469 Assert.assertEquals(0, pageData.getData().size());
438 - 470 +
439 for (User user : loadedTenantAdminsEmail2) { 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 pageLink = new TextPageLink(4, email2); 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 Assert.assertFalse(pageData.hasNext()); 480 Assert.assertFalse(pageData.hasNext());
448 Assert.assertEquals(0, pageData.getData().size()); 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 @Test 487 @Test
455 public void testFindCustomerUsers() throws Exception { 488 public void testFindCustomerUsers() throws Exception {
456 - 489 +
457 loginSysAdmin(); 490 loginSysAdmin();
458 Tenant tenant = new Tenant(); 491 Tenant tenant = new Tenant();
459 tenant.setTitle("My tenant"); 492 tenant.setTitle("My tenant");
460 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 493 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
461 Assert.assertNotNull(savedTenant); 494 Assert.assertNotNull(savedTenant);
462 - 495 +
463 TenantId tenantId = savedTenant.getId(); 496 TenantId tenantId = savedTenant.getId();
464 User tenantAdmin = new User(); 497 User tenantAdmin = new User();
465 tenantAdmin.setAuthority(Authority.TENANT_ADMIN); 498 tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
@@ -467,59 +500,60 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -467,59 +500,60 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
467 tenantAdmin.setEmail("tenant2@thingsboard.org"); 500 tenantAdmin.setEmail("tenant2@thingsboard.org");
468 tenantAdmin.setFirstName("Joe"); 501 tenantAdmin.setFirstName("Joe");
469 tenantAdmin.setLastName("Downs"); 502 tenantAdmin.setLastName("Downs");
470 - 503 +
471 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); 504 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
472 - 505 +
473 Customer customer = new Customer(); 506 Customer customer = new Customer();
474 customer.setTitle("My customer"); 507 customer.setTitle("My customer");
475 Customer savedCustomer = doPost("/api/customer", customer, Customer.class); 508 Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
476 509
477 CustomerId customerId = savedCustomer.getId(); 510 CustomerId customerId = savedCustomer.getId();
478 - 511 +
479 List<User> customerUsers = new ArrayList<>(); 512 List<User> customerUsers = new ArrayList<>();
480 - for (int i=0;i<56;i++) { 513 + for (int i = 0; i < 56; i++) {
481 User user = new User(); 514 User user = new User();
482 user.setAuthority(Authority.CUSTOMER_USER); 515 user.setAuthority(Authority.CUSTOMER_USER);
483 user.setCustomerId(customerId); 516 user.setCustomerId(customerId);
484 user.setEmail("testCustomer" + i + "@thingsboard.org"); 517 user.setEmail("testCustomer" + i + "@thingsboard.org");
485 customerUsers.add(doPost("/api/user", user, User.class)); 518 customerUsers.add(doPost("/api/user", user, User.class));
486 } 519 }
487 - 520 +
488 List<User> loadedCustomerUsers = new ArrayList<>(); 521 List<User> loadedCustomerUsers = new ArrayList<>();
489 TextPageLink pageLink = new TextPageLink(33); 522 TextPageLink pageLink = new TextPageLink(33);
490 TextPageData<User> pageData = null; 523 TextPageData<User> pageData = null;
491 do { 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 loadedCustomerUsers.addAll(pageData.getData()); 528 loadedCustomerUsers.addAll(pageData.getData());
495 if (pageData.hasNext()) { 529 if (pageData.hasNext()) {
496 pageLink = pageData.getNextPageLink(); 530 pageLink = pageData.getNextPageLink();
497 } 531 }
498 } while (pageData.hasNext()); 532 } while (pageData.hasNext());
499 - 533 +
500 Collections.sort(customerUsers, idComparator); 534 Collections.sort(customerUsers, idComparator);
501 Collections.sort(loadedCustomerUsers, idComparator); 535 Collections.sort(loadedCustomerUsers, idComparator);
502 - 536 +
503 Assert.assertEquals(customerUsers, loadedCustomerUsers); 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 loginSysAdmin(); 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 @Test 548 @Test
515 public void testFindCustomerUsersByEmail() throws Exception { 549 public void testFindCustomerUsersByEmail() throws Exception {
516 - 550 +
517 loginSysAdmin(); 551 loginSysAdmin();
518 Tenant tenant = new Tenant(); 552 Tenant tenant = new Tenant();
519 tenant.setTitle("My tenant"); 553 tenant.setTitle("My tenant");
520 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class); 554 Tenant savedTenant = doPost("/api/tenant", tenant, Tenant.class);
521 Assert.assertNotNull(savedTenant); 555 Assert.assertNotNull(savedTenant);
522 - 556 +
523 TenantId tenantId = savedTenant.getId(); 557 TenantId tenantId = savedTenant.getId();
524 User tenantAdmin = new User(); 558 User tenantAdmin = new User();
525 tenantAdmin.setAuthority(Authority.TENANT_ADMIN); 559 tenantAdmin.setAuthority(Authority.TENANT_ADMIN);
@@ -527,105 +561,109 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest { @@ -527,105 +561,109 @@ public abstract class BaseUserControllerTest extends AbstractControllerTest {
527 tenantAdmin.setEmail("tenant2@thingsboard.org"); 561 tenantAdmin.setEmail("tenant2@thingsboard.org");
528 tenantAdmin.setFirstName("Joe"); 562 tenantAdmin.setFirstName("Joe");
529 tenantAdmin.setLastName("Downs"); 563 tenantAdmin.setLastName("Downs");
530 - 564 +
531 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); 565 tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1");
532 - 566 +
533 Customer customer = new Customer(); 567 Customer customer = new Customer();
534 customer.setTitle("My customer"); 568 customer.setTitle("My customer");
535 Customer savedCustomer = doPost("/api/customer", customer, Customer.class); 569 Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
536 570
537 CustomerId customerId = savedCustomer.getId(); 571 CustomerId customerId = savedCustomer.getId();
538 -  
539 - String email1 = "testEmail1"; 572 +
  573 + String email1 = "testEmail1";
540 List<User> customerUsersEmail1 = new ArrayList<>(); 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 User user = new User(); 577 User user = new User();
544 user.setAuthority(Authority.CUSTOMER_USER); 578 user.setAuthority(Authority.CUSTOMER_USER);
545 user.setCustomerId(customerId); 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 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); 582 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase();
549 user.setEmail(email); 583 user.setEmail(email);
550 customerUsersEmail1.add(doPost("/api/user", user, User.class)); 584 customerUsersEmail1.add(doPost("/api/user", user, User.class));
551 } 585 }
552 -  
553 - String email2 = "testEmail2"; 586 +
  587 + String email2 = "testEmail2";
554 List<User> customerUsersEmail2 = new ArrayList<>(); 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 User user = new User(); 591 User user = new User();
558 user.setAuthority(Authority.CUSTOMER_USER); 592 user.setAuthority(Authority.CUSTOMER_USER);
559 user.setCustomerId(customerId); 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 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase(); 596 email = i % 2 == 0 ? email.toLowerCase() : email.toUpperCase();
563 user.setEmail(email); 597 user.setEmail(email);
564 customerUsersEmail2.add(doPost("/api/user", user, User.class)); 598 customerUsersEmail2.add(doPost("/api/user", user, User.class));
565 } 599 }
566 - 600 +
567 List<User> loadedCustomerUsersEmail1 = new ArrayList<>(); 601 List<User> loadedCustomerUsersEmail1 = new ArrayList<>();
568 TextPageLink pageLink = new TextPageLink(33, email1); 602 TextPageLink pageLink = new TextPageLink(33, email1);
569 TextPageData<User> pageData = null; 603 TextPageData<User> pageData = null;
570 do { 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 loadedCustomerUsersEmail1.addAll(pageData.getData()); 608 loadedCustomerUsersEmail1.addAll(pageData.getData());
574 if (pageData.hasNext()) { 609 if (pageData.hasNext()) {
575 pageLink = pageData.getNextPageLink(); 610 pageLink = pageData.getNextPageLink();
576 } 611 }
577 } while (pageData.hasNext()); 612 } while (pageData.hasNext());
578 - 613 +
579 Collections.sort(customerUsersEmail1, idComparator); 614 Collections.sort(customerUsersEmail1, idComparator);
580 Collections.sort(loadedCustomerUsersEmail1, idComparator); 615 Collections.sort(loadedCustomerUsersEmail1, idComparator);
581 - 616 +
582 Assert.assertEquals(customerUsersEmail1, loadedCustomerUsersEmail1); 617 Assert.assertEquals(customerUsersEmail1, loadedCustomerUsersEmail1);
583 - 618 +
584 List<User> loadedCustomerUsersEmail2 = new ArrayList<>(); 619 List<User> loadedCustomerUsersEmail2 = new ArrayList<>();
585 pageLink = new TextPageLink(16, email2); 620 pageLink = new TextPageLink(16, email2);
586 do { 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 loadedCustomerUsersEmail2.addAll(pageData.getData()); 625 loadedCustomerUsersEmail2.addAll(pageData.getData());
590 if (pageData.hasNext()) { 626 if (pageData.hasNext()) {
591 pageLink = pageData.getNextPageLink(); 627 pageLink = pageData.getNextPageLink();
592 } 628 }
593 } while (pageData.hasNext()); 629 } while (pageData.hasNext());
594 - 630 +
595 Collections.sort(customerUsersEmail2, idComparator); 631 Collections.sort(customerUsersEmail2, idComparator);
596 Collections.sort(loadedCustomerUsersEmail2, idComparator); 632 Collections.sort(loadedCustomerUsersEmail2, idComparator);
597 - 633 +
598 Assert.assertEquals(customerUsersEmail2, loadedCustomerUsersEmail2); 634 Assert.assertEquals(customerUsersEmail2, loadedCustomerUsersEmail2);
599 - 635 +
600 for (User user : loadedCustomerUsersEmail1) { 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 pageLink = new TextPageLink(4, email1); 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 Assert.assertFalse(pageData.hasNext()); 645 Assert.assertFalse(pageData.hasNext());
609 Assert.assertEquals(0, pageData.getData().size()); 646 Assert.assertEquals(0, pageData.getData().size());
610 - 647 +
611 for (User user : loadedCustomerUsersEmail2) { 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 pageLink = new TextPageLink(4, email2); 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 Assert.assertFalse(pageData.hasNext()); 657 Assert.assertFalse(pageData.hasNext());
620 Assert.assertEquals(0, pageData.getData().size()); 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 loginSysAdmin(); 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,7 +64,6 @@ public abstract class BaseWidgetTypeControllerTest extends AbstractControllerTes
64 WidgetsBundle widgetsBundle = new WidgetsBundle(); 64 WidgetsBundle widgetsBundle = new WidgetsBundle();
65 widgetsBundle.setTitle("My widgets bundle"); 65 widgetsBundle.setTitle("My widgets bundle");
66 savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class); 66 savedWidgetsBundle = doPost("/api/widgetsBundle", widgetsBundle, WidgetsBundle.class);
67 -  
68 } 67 }
69 68
70 @After 69 @After
@@ -101,6 +100,19 @@ public abstract class BaseWidgetTypeControllerTest extends AbstractControllerTes @@ -101,6 +100,19 @@ public abstract class BaseWidgetTypeControllerTest extends AbstractControllerTes
101 } 100 }
102 101
103 @Test 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 public void testFindWidgetTypeById() throws Exception { 116 public void testFindWidgetTypeById() throws Exception {
105 WidgetType widgetType = new WidgetType(); 117 WidgetType widgetType = new WidgetType();
106 widgetType.setBundleAlias(savedWidgetsBundle.getAlias()); 118 widgetType.setBundleAlias(savedWidgetsBundle.getAlias());
@@ -89,6 +89,17 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController @@ -89,6 +89,17 @@ public abstract class BaseWidgetsBundleControllerTest extends AbstractController
89 } 89 }
90 90
91 @Test 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 public void testFindWidgetsBundleById() throws Exception { 103 public void testFindWidgetsBundleById() throws Exception {
93 WidgetsBundle widgetsBundle = new WidgetsBundle(); 104 WidgetsBundle widgetsBundle = new WidgetsBundle();
94 widgetsBundle.setTitle("My widgets bundle"); 105 widgetsBundle.setTitle("My widgets bundle");
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,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -28,4 +28,6 @@ public class OAuth2User { @@ -28,4 +28,6 @@ public class OAuth2User {
28 private String email; 28 private String email;
29 private String firstName; 29 private String firstName;
30 private String lastName; 30 private String lastName;
  31 + private boolean alwaysFullScreen;
  32 + private String defaultDashboardName;
31 } 33 }
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -40,6 +40,7 @@ import java.util.UUID; @@ -40,6 +40,7 @@ import java.util.UUID;
40 public final class TbMsg implements Serializable { 40 public final class TbMsg implements Serializable {
41 41
42 private final UUID id; 42 private final UUID id;
  43 + private final long ts;
43 private final String type; 44 private final String type;
44 private final EntityId originator; 45 private final EntityId originator;
45 private final TbMsgMetaData metaData; 46 private final TbMsgMetaData metaData;
@@ -51,38 +52,43 @@ public final class TbMsg implements Serializable { @@ -51,38 +52,43 @@ public final class TbMsg implements Serializable {
51 transient private final TbMsgCallback callback; 52 transient private final TbMsgCallback callback;
52 53
53 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data) { 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 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 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 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data) { 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 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, TbMsgDataType dataType, String data, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 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 public static TbMsg newMsg(String type, EntityId originator, TbMsgMetaData metaData, String data, TbMsgCallback callback) { 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 public static TbMsg transformMsg(TbMsg origMsg, String type, EntityId originator, TbMsgMetaData metaData, String data) { 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 data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), origMsg.getCallback()); 76 data, origMsg.getRuleChainId(), origMsg.getRuleNodeId(), origMsg.getCallback());
76 } 77 }
77 78
78 public static TbMsg newMsg(TbMsg tbMsg, RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 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 tbMsg.getDataType(), tbMsg.getData(), ruleChainId, ruleNodeId, TbMsgCallback.EMPTY); 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 RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgCallback callback) { 85 RuleChainId ruleChainId, RuleNodeId ruleNodeId, TbMsgCallback callback) {
85 this.id = id; 86 this.id = id;
  87 + if (ts > 0) {
  88 + this.ts = ts;
  89 + } else {
  90 + this.ts = System.currentTimeMillis();
  91 + }
86 this.type = type; 92 this.type = type;
87 this.originator = originator; 93 this.originator = originator;
88 this.metaData = metaData; 94 this.metaData = metaData;
@@ -105,6 +111,7 @@ public final class TbMsg implements Serializable { @@ -105,6 +111,7 @@ public final class TbMsg implements Serializable {
105 public static byte[] toByteArray(TbMsg msg) { 111 public static byte[] toByteArray(TbMsg msg) {
106 MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder(); 112 MsgProtos.TbMsgProto.Builder builder = MsgProtos.TbMsgProto.newBuilder();
107 builder.setId(msg.getId().toString()); 113 builder.setId(msg.getId().toString());
  114 + builder.setTs(msg.getTs());
108 builder.setType(msg.getType()); 115 builder.setType(msg.getType());
109 builder.setEntityType(msg.getOriginator().getEntityType().name()); 116 builder.setEntityType(msg.getOriginator().getEntityType().name());
110 builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits()); 117 builder.setEntityIdMSB(msg.getOriginator().getId().getMostSignificantBits());
@@ -124,7 +131,6 @@ public final class TbMsg implements Serializable { @@ -124,7 +131,6 @@ public final class TbMsg implements Serializable {
124 builder.setMetaData(MsgProtos.TbMsgMetaDataProto.newBuilder().putAllData(msg.getMetaData().getData()).build()); 131 builder.setMetaData(MsgProtos.TbMsgMetaDataProto.newBuilder().putAllData(msg.getMetaData().getData()).build());
125 } 132 }
126 133
127 -  
128 builder.setDataType(msg.getDataType().ordinal()); 134 builder.setDataType(msg.getDataType().ordinal());
129 builder.setData(msg.getData()); 135 builder.setData(msg.getData());
130 return builder.build().toByteArray(); 136 return builder.build().toByteArray();
@@ -144,18 +150,18 @@ public final class TbMsg implements Serializable { @@ -144,18 +150,18 @@ public final class TbMsg implements Serializable {
144 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB())); 150 ruleNodeId = new RuleNodeId(new UUID(proto.getRuleNodeIdMSB(), proto.getRuleNodeIdLSB()));
145 } 151 }
146 TbMsgDataType dataType = TbMsgDataType.values()[proto.getDataType()]; 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 } catch (InvalidProtocolBufferException e) { 154 } catch (InvalidProtocolBufferException e) {
149 throw new IllegalStateException("Could not parse protobuf for TbMsg", e); 155 throw new IllegalStateException("Could not parse protobuf for TbMsg", e);
150 } 156 }
151 } 157 }
152 158
153 public TbMsg copyWithRuleChainId(RuleChainId ruleChainId) { 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 public TbMsg copyWithRuleNodeId(RuleChainId ruleChainId, RuleNodeId ruleNodeId) { 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 public TbMsgCallback getCallback() { 167 public TbMsgCallback getCallback() {
@@ -44,4 +44,5 @@ message TbMsgProto { @@ -44,4 +44,5 @@ message TbMsgProto {
44 int32 dataType = 13; 44 int32 dataType = 13;
45 string data = 14; 45 string data = 14;
46 46
  47 + int64 ts = 15;
47 } 48 }
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>common</artifactId> 26 <artifactId>common</artifactId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -101,7 +101,7 @@ public class TbServiceBusConsumerTemplate<T extends TbQueueMsg> extends Abstract @@ -101,7 +101,7 @@ public class TbServiceBusConsumerTemplate<T extends TbQueueMsg> extends Abstract
101 @Override 101 @Override
102 protected void doSubscribe(List<String> topicNames) { 102 protected void doSubscribe(List<String> topicNames) {
103 createReceivers(); 103 createReceivers();
104 - messagesPerQueue = receivers.size() / partitions.size(); 104 + messagesPerQueue = receivers.size() / Math.max(partitions.size(), 1);
105 } 105 }
106 106
107 @Override 107 @Override
@@ -85,7 +85,12 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i @@ -85,7 +85,12 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i
85 subscribed = true; 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 if (!records.isEmpty()) { 94 if (!records.isEmpty()) {
90 List<T> result = new ArrayList<>(records.size()); 95 List<T> result = new ArrayList<>(records.size());
91 records.forEach(record -> { 96 records.forEach(record -> {
@@ -36,6 +36,7 @@ import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; @@ -36,6 +36,7 @@ import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings;
36 import javax.annotation.PostConstruct; 36 import javax.annotation.PostConstruct;
37 import java.nio.charset.StandardCharsets; 37 import java.nio.charset.StandardCharsets;
38 import java.util.ArrayList; 38 import java.util.ArrayList;
  39 +import java.util.Collections;
39 import java.util.Comparator; 40 import java.util.Comparator;
40 import java.util.HashMap; 41 import java.util.HashMap;
41 import java.util.HashSet; 42 import java.util.HashSet;
@@ -148,6 +149,14 @@ public class HashPartitionService implements PartitionService { @@ -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 myPartitions.forEach((serviceQueueKey, partitions) -> { 160 myPartitions.forEach((serviceQueueKey, partitions) -> {
152 if (!partitions.equals(oldPartitions.get(serviceQueueKey))) { 161 if (!partitions.equals(oldPartitions.get(serviceQueueKey))) {
153 log.info("[{}] NEW PARTITIONS: {}", serviceQueueKey, partitions); 162 log.info("[{}] NEW PARTITIONS: {}", serviceQueueKey, partitions);
@@ -71,8 +71,12 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue @@ -71,8 +71,12 @@ public class TbKafkaConsumerTemplate<T extends TbQueueMsg> extends AbstractTbQue
71 71
72 @Override 72 @Override
73 protected void doSubscribe(List<String> topicNames) { 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 @Override 82 @Override
@@ -200,7 +200,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi @@ -200,7 +200,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi
200 consumerBuilder.settings(kafkaSettings); 200 consumerBuilder.settings(kafkaSettings);
201 consumerBuilder.topic(transportApiSettings.getRequestsTopic()); 201 consumerBuilder.topic(transportApiSettings.getRequestsTopic());
202 consumerBuilder.clientId("monolith-transport-api-consumer-" + serviceInfoProvider.getServiceId()); 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 consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); 204 consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders()));
205 consumerBuilder.admin(transportApiAdmin); 205 consumerBuilder.admin(transportApiAdmin);
206 return consumerBuilder.build(); 206 return consumerBuilder.build();
@@ -170,7 +170,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { @@ -170,7 +170,7 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory {
170 consumerBuilder.settings(kafkaSettings); 170 consumerBuilder.settings(kafkaSettings);
171 consumerBuilder.topic(transportApiSettings.getRequestsTopic()); 171 consumerBuilder.topic(transportApiSettings.getRequestsTopic());
172 consumerBuilder.clientId("tb-core-transport-api-consumer-" + serviceInfoProvider.getServiceId()); 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 consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders())); 174 consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), TransportApiRequestMsg.parseFrom(msg.getData()), msg.getHeaders()));
175 consumerBuilder.admin(transportApiAdmin); 175 consumerBuilder.admin(transportApiAdmin);
176 return consumerBuilder.build(); 176 return consumerBuilder.build();
@@ -106,7 +106,7 @@ public class TbPubSubConsumerTemplate<T extends TbQueueMsg> extends AbstractPara @@ -106,7 +106,7 @@ public class TbPubSubConsumerTemplate<T extends TbQueueMsg> extends AbstractPara
106 subscriptionNames = new LinkedHashSet<>(topicNames); 106 subscriptionNames = new LinkedHashSet<>(topicNames);
107 subscriptionNames.forEach(admin::createTopicIfNotExists); 107 subscriptionNames.forEach(admin::createTopicIfNotExists);
108 initNewExecutor(subscriptionNames.size() + 1); 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 @Override 112 @Override
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -294,7 +294,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @@ -294,7 +294,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
294 break; 294 break;
295 } 295 }
296 } catch (Exception e) { 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 grantedQoSList.add(FAILURE.value()); 298 grantedQoSList.add(FAILURE.value());
299 } 299 }
300 } 300 }
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard.common</groupId> 22 <groupId>org.thingsboard.common</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>transport</artifactId> 24 <artifactId>transport</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common.transport</groupId> 26 <groupId>org.thingsboard.common.transport</groupId>
@@ -53,10 +53,6 @@ @@ -53,10 +53,6 @@
53 <artifactId>util</artifactId> 53 <artifactId>util</artifactId>
54 </dependency> 54 </dependency>
55 <dependency> 55 <dependency>
56 - <groupId>org.thingsboard.common</groupId>  
57 - <artifactId>queue</artifactId>  
58 - </dependency>  
59 - <dependency>  
60 <groupId>com.google.code.gson</groupId> 56 <groupId>com.google.code.gson</groupId>
61 <artifactId>gson</artifactId> 57 <artifactId>gson</artifactId>
62 </dependency> 58 </dependency>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>common</artifactId> 24 <artifactId>common</artifactId>
25 </parent> 25 </parent>
26 <groupId>org.thingsboard.common</groupId> 26 <groupId>org.thingsboard.common</groupId>
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 <modelVersion>4.0.0</modelVersion> 20 <modelVersion>4.0.0</modelVersion>
21 <parent> 21 <parent>
22 <groupId>org.thingsboard</groupId> 22 <groupId>org.thingsboard</groupId>
23 - <version>2.5.0-SNAPSHOT</version> 23 + <version>2.5.1-SNAPSHOT</version>
24 <artifactId>thingsboard</artifactId> 24 <artifactId>thingsboard</artifactId>
25 </parent> 25 </parent>
26 <artifactId>dao</artifactId> 26 <artifactId>dao</artifactId>
@@ -112,7 +112,7 @@ public class EventEntity extends BaseSqlEntity<Event> implements BaseEntity<Eve @@ -112,7 +112,7 @@ public class EventEntity extends BaseSqlEntity<Event> implements BaseEntity<Eve
112 return event; 112 return event;
113 } 113 }
114 114
115 - private long getTs(UUID uuid) { 115 + private static long getTs(UUID uuid) {
116 return (uuid.timestamp() - EPOCH_DIFF) / 10000; 116 return (uuid.timestamp() - EPOCH_DIFF) / 10000;
117 } 117 }
118 } 118 }
@@ -34,6 +34,8 @@ public class OAuth2ClientMapperConfig { @@ -34,6 +34,8 @@ public class OAuth2ClientMapperConfig {
34 private String tenantNameStrategy; 34 private String tenantNameStrategy;
35 private String tenantNamePattern; 35 private String tenantNamePattern;
36 private String customerNamePattern; 36 private String customerNamePattern;
  37 + private boolean alwaysFullScreen;
  38 + private String defaultDashboardName;
37 } 39 }
38 40
39 @Data 41 @Data
@@ -90,7 +90,7 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa @@ -90,7 +90,7 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa
90 } 90 }
91 91
92 private void savePartitionIfNotExist(long ts) { 92 private void savePartitionIfNotExist(long ts) {
93 - if (!tsFormat.equals(SqlTsPartitionDate.INDEFINITE)) { 93 + if (!tsFormat.equals(SqlTsPartitionDate.INDEFINITE) && ts >= 0) {
94 LocalDateTime time = LocalDateTime.ofInstant(Instant.ofEpochMilli(ts), ZoneOffset.UTC); 94 LocalDateTime time = LocalDateTime.ofInstant(Instant.ofEpochMilli(ts), ZoneOffset.UTC);
95 LocalDateTime localDateTimeStart = tsFormat.trancateTo(time); 95 LocalDateTime localDateTimeStart = tsFormat.trancateTo(time);
96 long partitionStartTs = toMills(localDateTimeStart); 96 long partitionStartTs = toMills(localDateTimeStart);
@@ -52,7 +52,7 @@ CREATE TABLE IF NOT EXISTS tb_schema_settings @@ -52,7 +52,7 @@ CREATE TABLE IF NOT EXISTS tb_schema_settings
52 CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) 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 CREATE OR REPLACE FUNCTION to_uuid(IN entity_id varchar, OUT uuid_id uuid) AS 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,7 +53,7 @@ CREATE TABLE IF NOT EXISTS tb_schema_settings
53 CONSTRAINT tb_schema_settings_pkey PRIMARY KEY (schema_version) 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 CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint) 58 CREATE OR REPLACE PROCEDURE drop_partitions_by_max_ttl(IN partition_type varchar, IN system_ttl bigint, INOUT deleted bigint)
59 LANGUAGE plpgsql AS 59 LANGUAGE plpgsql AS
  1 +TB_QUEUE_TYPE=kafka
1 2
2 DOCKER_REPO=thingsboard 3 DOCKER_REPO=thingsboard
3 4
@@ -32,6 +32,32 @@ function additionalComposeArgs() { @@ -32,6 +32,32 @@ function additionalComposeArgs() {
32 echo $ADDITIONAL_COMPOSE_ARGS 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 function additionalStartupServices() { 61 function additionalStartupServices() {
36 source .env 62 source .env
37 ADDITIONAL_STARTUP_SERVICES="" 63 ADDITIONAL_STARTUP_SERVICES=""
  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
@@ -28,27 +28,27 @@ services: @@ -28,27 +28,27 @@ services:
28 env_file: 28 env_file:
29 - tb-node.cassandra.env 29 - tb-node.cassandra.env
30 depends_on: 30 depends_on:
31 - - kafka 31 + - zookeeper
32 - redis 32 - redis
33 - cassandra 33 - cassandra
34 tb-core2: 34 tb-core2:
35 env_file: 35 env_file:
36 - tb-node.cassandra.env 36 - tb-node.cassandra.env
37 depends_on: 37 depends_on:
38 - - kafka 38 + - zookeeper
39 - redis 39 - redis
40 - cassandra 40 - cassandra
41 tb-rule-engine1: 41 tb-rule-engine1:
42 env_file: 42 env_file:
43 - tb-node.cassandra.env 43 - tb-node.cassandra.env
44 depends_on: 44 depends_on:
45 - - kafka 45 + - zookeeper
46 - redis 46 - redis
47 - cassandra 47 - cassandra
48 tb-rule-engine2: 48 tb-rule-engine2:
49 env_file: 49 env_file:
50 - tb-node.cassandra.env 50 - tb-node.cassandra.env
51 depends_on: 51 depends_on:
52 - - kafka 52 + - zookeeper
53 - redis 53 - redis
54 - cassandra 54 - cassandra
  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,27 +31,27 @@ services:
31 env_file: 31 env_file:
32 - tb-node.postgres.env 32 - tb-node.postgres.env
33 depends_on: 33 depends_on:
34 - - kafka 34 + - zookeeper
35 - redis 35 - redis
36 - postgres 36 - postgres
37 tb-core2: 37 tb-core2:
38 env_file: 38 env_file:
39 - tb-node.postgres.env 39 - tb-node.postgres.env
40 depends_on: 40 depends_on:
41 - - kafka 41 + - zookeeper
42 - redis 42 - redis
43 - postgres 43 - postgres
44 tb-rule-engine1: 44 tb-rule-engine1:
45 env_file: 45 env_file:
46 - tb-node.postgres.env 46 - tb-node.postgres.env
47 depends_on: 47 depends_on:
48 - - kafka 48 + - zookeeper
49 - redis 49 - redis
50 - postgres 50 - postgres
51 tb-rule-engine2: 51 tb-rule-engine2:
52 env_file: 52 env_file:
53 - tb-node.postgres.env 53 - tb-node.postgres.env
54 depends_on: 54 depends_on:
55 - - kafka 55 + - zookeeper
56 - redis 56 - redis
57 - postgres 57 - postgres
  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
  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
  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
@@ -26,15 +26,6 @@ services: @@ -26,15 +26,6 @@ services:
26 environment: 26 environment:
27 ZOO_MY_ID: 1 27 ZOO_MY_ID: 1
28 ZOO_SERVERS: server.1=zookeeper:2888:3888;zookeeper:2181 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 redis: 29 redis:
39 restart: always 30 restart: always
40 image: redis:4.0 31 image: redis:4.0
@@ -46,8 +37,6 @@ services: @@ -46,8 +37,6 @@ services:
46 scale: 20 37 scale: 20
47 env_file: 38 env_file:
48 - tb-js-executor.env 39 - tb-js-executor.env
49 - depends_on:  
50 - - kafka  
51 tb-core1: 40 tb-core1:
52 restart: always 41 restart: always
53 image: "${DOCKER_REPO}/${TB_NODE_DOCKER_NAME}:${TB_VERSION}" 42 image: "${DOCKER_REPO}/${TB_NODE_DOCKER_NAME}:${TB_VERSION}"
@@ -67,7 +56,7 @@ services: @@ -67,7 +56,7 @@ services:
67 - ./tb-node/conf:/config 56 - ./tb-node/conf:/config
68 - ./tb-node/log:/var/log/thingsboard 57 - ./tb-node/log:/var/log/thingsboard
69 depends_on: 58 depends_on:
70 - - kafka 59 + - zookeeper
71 - redis 60 - redis
72 - tb-js-executor 61 - tb-js-executor
73 - tb-rule-engine1 62 - tb-rule-engine1
@@ -91,7 +80,7 @@ services: @@ -91,7 +80,7 @@ services:
91 - ./tb-node/conf:/config 80 - ./tb-node/conf:/config
92 - ./tb-node/log:/var/log/thingsboard 81 - ./tb-node/log:/var/log/thingsboard
93 depends_on: 82 depends_on:
94 - - kafka 83 + - zookeeper
95 - redis 84 - redis
96 - tb-js-executor 85 - tb-js-executor
97 - tb-rule-engine1 86 - tb-rule-engine1
@@ -115,7 +104,7 @@ services: @@ -115,7 +104,7 @@ services:
115 - ./tb-node/conf:/config 104 - ./tb-node/conf:/config
116 - ./tb-node/log:/var/log/thingsboard 105 - ./tb-node/log:/var/log/thingsboard
117 depends_on: 106 depends_on:
118 - - kafka 107 + - zookeeper
119 - redis 108 - redis
120 - tb-js-executor 109 - tb-js-executor
121 tb-rule-engine2: 110 tb-rule-engine2:
@@ -137,7 +126,7 @@ services: @@ -137,7 +126,7 @@ services:
137 - ./tb-node/conf:/config 126 - ./tb-node/conf:/config
138 - ./tb-node/log:/var/log/thingsboard 127 - ./tb-node/log:/var/log/thingsboard
139 depends_on: 128 depends_on:
140 - - kafka 129 + - zookeeper
141 - redis 130 - redis
142 - tb-js-executor 131 - tb-js-executor
143 tb-mqtt-transport1: 132 tb-mqtt-transport1:
@@ -153,7 +142,7 @@ services: @@ -153,7 +142,7 @@ services:
153 - ./tb-transports/mqtt/conf:/config 142 - ./tb-transports/mqtt/conf:/config
154 - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport 143 - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport
155 depends_on: 144 depends_on:
156 - - kafka 145 + - zookeeper
157 tb-mqtt-transport2: 146 tb-mqtt-transport2:
158 restart: always 147 restart: always
159 image: "${DOCKER_REPO}/${MQTT_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" 148 image: "${DOCKER_REPO}/${MQTT_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
@@ -167,7 +156,7 @@ services: @@ -167,7 +156,7 @@ services:
167 - ./tb-transports/mqtt/conf:/config 156 - ./tb-transports/mqtt/conf:/config
168 - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport 157 - ./tb-transports/mqtt/log:/var/log/tb-mqtt-transport
169 depends_on: 158 depends_on:
170 - - kafka 159 + - zookeeper
171 tb-http-transport1: 160 tb-http-transport1:
172 restart: always 161 restart: always
173 image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" 162 image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
@@ -181,7 +170,7 @@ services: @@ -181,7 +170,7 @@ services:
181 - ./tb-transports/http/conf:/config 170 - ./tb-transports/http/conf:/config
182 - ./tb-transports/http/log:/var/log/tb-http-transport 171 - ./tb-transports/http/log:/var/log/tb-http-transport
183 depends_on: 172 depends_on:
184 - - kafka 173 + - zookeeper
185 tb-http-transport2: 174 tb-http-transport2:
186 restart: always 175 restart: always
187 image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" 176 image: "${DOCKER_REPO}/${HTTP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
@@ -195,7 +184,7 @@ services: @@ -195,7 +184,7 @@ services:
195 - ./tb-transports/http/conf:/config 184 - ./tb-transports/http/conf:/config
196 - ./tb-transports/http/log:/var/log/tb-http-transport 185 - ./tb-transports/http/log:/var/log/tb-http-transport
197 depends_on: 186 depends_on:
198 - - kafka 187 + - zookeeper
199 tb-coap-transport: 188 tb-coap-transport:
200 restart: always 189 restart: always
201 image: "${DOCKER_REPO}/${COAP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}" 190 image: "${DOCKER_REPO}/${COAP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
@@ -209,7 +198,7 @@ services: @@ -209,7 +198,7 @@ services:
209 - ./tb-transports/coap/conf:/config 198 - ./tb-transports/coap/conf:/config
210 - ./tb-transports/coap/log:/var/log/tb-coap-transport 199 - ./tb-transports/coap/log:/var/log/tb-coap-transport
211 depends_on: 200 depends_on:
212 - - kafka 201 + - zookeeper
213 tb-web-ui1: 202 tb-web-ui1:
214 restart: always 203 restart: always
215 image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}" 204 image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}"
@@ -41,14 +41,16 @@ set -e @@ -41,14 +41,16 @@ set -e
41 41
42 source compose-utils.sh 42 source compose-utils.sh
43 43
  44 +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $?
  45 +
44 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? 46 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $?
45 47
46 ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? 48 ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $?
47 49
48 if [ ! -z "${ADDITIONAL_STARTUP_SERVICES// }" ]; then 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 fi 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,6 +19,8 @@ set -e
19 19
20 source compose-utils.sh 20 source compose-utils.sh
21 21
  22 +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $?
  23 +
22 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? 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,6 +19,8 @@ set -e
19 19
20 source compose-utils.sh 20 source compose-utils.sh
21 21
  22 +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $?
  23 +
22 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? 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,6 +19,8 @@ set -e
19 19
20 source compose-utils.sh 20 source compose-utils.sh
21 21
  22 +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $?
  23 +
22 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? 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,7 +19,9 @@ set -e
19 19
20 source compose-utils.sh 20 source compose-utils.sh
21 21
  22 +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $?
  23 +
22 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? 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,12 +40,14 @@ set -e
40 40
41 source compose-utils.sh 41 source compose-utils.sh
42 42
  43 +ADDITIONAL_COMPOSE_QUEUE_ARGS=$(additionalComposeQueueArgs) || exit $?
  44 +
43 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $? 45 ADDITIONAL_COMPOSE_ARGS=$(additionalComposeArgs) || exit $?
44 46
45 ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? 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
  1 +TB_QUEUE_TYPE=aws-sqs
  2 +TB_QUEUE_AWS_SQS_ACCESS_KEY_ID=YOUR_KEY
  3 +TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY=YOUR_SECRET
  4 +TB_QUEUE_AWS_SQS_REGION=YOUR_REGION
  1 +TB_QUEUE_TYPE=kafka
  2 +TB_KAFKA_SERVERS=kafka:9092
  1 +TB_QUEUE_TYPE=pubsub
  2 +TB_QUEUE_PUBSUB_PROJECT_ID=YOUR_PROJECT_ID
  3 +TB_QUEUE_PUBSUB_SERVICE_ACCOUNT=YOUR_SERVICE_ACCOUNT
  1 +TB_QUEUE_TYPE=rabbitmq
  2 +TB_QUEUE_RABBIT_MQ_HOST=localhost
  3 +TB_QUEUE_RABBIT_MQ_PORT=5672
  4 +TB_QUEUE_RABBIT_MQ_USERNAME=YOUR_USERNAME
  5 +TB_QUEUE_RABBIT_MQ_PASSWORD=YOUR_PASSWORD
  1 +TB_QUEUE_TYPE=service-bus
  2 +TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME=YOUR_NAMESPACE_NAME
  3 +TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME=YOUR_SAS_KEY_NAME
  4 +TB_QUEUE_SERVICE_BUS_SAS_KEY=YOUR_SAS_KEY
@@ -4,6 +4,3 @@ ZOOKEEPER_URL=zookeeper:2181 @@ -4,6 +4,3 @@ ZOOKEEPER_URL=zookeeper:2181
4 COAP_BIND_ADDRESS=0.0.0.0 4 COAP_BIND_ADDRESS=0.0.0.0
5 COAP_BIND_PORT=5683 5 COAP_BIND_PORT=5683
6 COAP_TIMEOUT=10000 6 COAP_TIMEOUT=10000
7 -  
8 -TB_QUEUE_TYPE=kafka  
9 -TB_KAFKA_SERVERS=kafka:9092