Commit 3b1e1416fba029c9f768cc6f539b8ad58dfdbd20

Authored by deaflynx
2 parents 36997c5c 3d3dd887

Merge with 2.5.1

Showing 88 changed files with 1353 additions and 1225 deletions

Too many changes to show.

To preserve performance only 88 of 337 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 }
@@ -206,7 +206,7 @@ public class TenantActor extends RuleChainManagerActor { @@ -206,7 +206,7 @@ public class TenantActor extends RuleChainManagerActor {
206 if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { 206 if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) {
207 RuleChain ruleChain = systemContext.getRuleChainService(). 207 RuleChain ruleChain = systemContext.getRuleChainService().
208 findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); 208 findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId()));
209 - if (ruleChain.getType().equals(RuleChainType.SYSTEM)) { 209 + if (ruleChain != null && ruleChain.getType().equals(RuleChainType.SYSTEM)) {
210 visit(ruleChain, target); 210 visit(ruleChain, target);
211 } 211 }
212 } 212 }
@@ -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(),
@@ -40,6 +40,8 @@ import org.thingsboard.server.common.data.id.EdgeId; @@ -40,6 +40,8 @@ import org.thingsboard.server.common.data.id.EdgeId;
40 import org.thingsboard.server.common.data.id.TenantId; 40 import org.thingsboard.server.common.data.id.TenantId;
41 import org.thingsboard.server.common.data.page.TextPageData; 41 import org.thingsboard.server.common.data.page.TextPageData;
42 import org.thingsboard.server.common.data.page.TextPageLink; 42 import org.thingsboard.server.common.data.page.TextPageLink;
  43 +import org.thingsboard.server.common.data.page.TimePageData;
  44 +import org.thingsboard.server.common.data.page.TimePageLink;
43 import org.thingsboard.server.dao.exception.IncorrectParameterException; 45 import org.thingsboard.server.dao.exception.IncorrectParameterException;
44 import org.thingsboard.server.dao.model.ModelConstants; 46 import org.thingsboard.server.dao.model.ModelConstants;
45 import org.thingsboard.server.queue.util.TbCoreComponent; 47 import org.thingsboard.server.queue.util.TbCoreComponent;
@@ -51,6 +53,8 @@ import java.util.ArrayList; @@ -51,6 +53,8 @@ import java.util.ArrayList;
51 import java.util.List; 53 import java.util.List;
52 import java.util.stream.Collectors; 54 import java.util.stream.Collectors;
53 55
  56 +import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
  57 +
54 @RestController 58 @RestController
55 @TbCoreComponent 59 @TbCoreComponent
56 @RequestMapping("/api") 60 @RequestMapping("/api")
@@ -78,18 +82,15 @@ public class AssetController extends BaseController { @@ -78,18 +82,15 @@ public class AssetController extends BaseController {
78 try { 82 try {
79 asset.setTenantId(getCurrentUser().getTenantId()); 83 asset.setTenantId(getCurrentUser().getTenantId());
80 84
81 - Operation operation = asset.getId() == null ? Operation.CREATE : Operation.WRITE;  
82 -  
83 - accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation,  
84 - asset.getId(), asset); 85 + checkEntity(asset.getId(), asset, Resource.ASSET);
85 86
86 - Asset savedAsset = checkNotNull(assetService.saveAsset(asset)); 87 + Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
87 88
88 logEntityAction(savedAsset.getId(), savedAsset, 89 logEntityAction(savedAsset.getId(), savedAsset,
89 savedAsset.getCustomerId(), 90 savedAsset.getCustomerId(),
90 asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); 91 asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
91 92
92 - return savedAsset; 93 + return savedAsset;
93 } catch (Exception e) { 94 } catch (Exception e) {
94 logEntityAction(emptyId(EntityType.ASSET), asset, 95 logEntityAction(emptyId(EntityType.ASSET), asset,
95 null, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); 96 null, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
@@ -140,7 +141,7 @@ public class AssetController extends BaseController { @@ -140,7 +141,7 @@ public class AssetController extends BaseController {
140 savedAsset.getCustomerId(), 141 savedAsset.getCustomerId(),
141 ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName()); 142 ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName());
142 143
143 - return savedAsset; 144 + return savedAsset;
144 } catch (Exception e) { 145 } catch (Exception e) {
145 146
146 logEntityAction(emptyId(EntityType.ASSET), null, 147 logEntityAction(emptyId(EntityType.ASSET), null,
@@ -220,7 +221,7 @@ public class AssetController extends BaseController { @@ -220,7 +221,7 @@ public class AssetController extends BaseController {
220 try { 221 try {
221 TenantId tenantId = getCurrentUser().getTenantId(); 222 TenantId tenantId = getCurrentUser().getTenantId();
222 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 223 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
223 - if (type != null && type.trim().length()>0) { 224 + if (type != null && type.trim().length() > 0) {
224 return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink)); 225 return checkNotNull(assetService.findAssetsByTenantIdAndType(tenantId, type, pageLink));
225 } else { 226 } else {
226 return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink)); 227 return checkNotNull(assetService.findAssetsByTenantId(tenantId, pageLink));
@@ -259,7 +260,7 @@ public class AssetController extends BaseController { @@ -259,7 +260,7 @@ public class AssetController extends BaseController {
259 CustomerId customerId = new CustomerId(toUUID(strCustomerId)); 260 CustomerId customerId = new CustomerId(toUUID(strCustomerId));
260 checkCustomerId(customerId, Operation.READ); 261 checkCustomerId(customerId, Operation.READ);
261 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset); 262 TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
262 - if (type != null && type.trim().length()>0) { 263 + if (type != null && type.trim().length() > 0) {
263 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink)); 264 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerIdAndType(tenantId, customerId, type, pageLink));
264 } else { 265 } else {
265 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink)); 266 return checkNotNull(assetService.findAssetsByTenantIdAndCustomerId(tenantId, customerId, pageLink));
@@ -336,9 +337,9 @@ public class AssetController extends BaseController { @@ -336,9 +337,9 @@ public class AssetController extends BaseController {
336 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 337 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
337 @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST) 338 @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.POST)
338 @ResponseBody 339 @ResponseBody
339 - public Asset assignAssetToEdge(@PathVariable("edgeId") String strEdgeId, 340 + public Asset assignAssetToEdge(@PathVariable(EDGE_ID) String strEdgeId,
340 @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { 341 @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
341 - checkParameter("edgeId", strEdgeId); 342 + checkParameter(EDGE_ID, strEdgeId);
342 checkParameter(ASSET_ID, strAssetId); 343 checkParameter(ASSET_ID, strAssetId);
343 try { 344 try {
344 EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); 345 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
@@ -365,20 +366,20 @@ public class AssetController extends BaseController { @@ -365,20 +366,20 @@ public class AssetController extends BaseController {
365 } 366 }
366 367
367 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 368 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
368 - @RequestMapping(value = "/edge/asset/{assetId}", method = RequestMethod.DELETE) 369 + @RequestMapping(value = "/edge/{edgeId}/asset/{assetId}", method = RequestMethod.DELETE)
369 @ResponseBody 370 @ResponseBody
370 - public Asset unassignAssetFromEdge(@PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException { 371 + public Asset unassignAssetFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
  372 + @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
  373 + checkParameter(EDGE_ID, strEdgeId);
371 checkParameter(ASSET_ID, strAssetId); 374 checkParameter(ASSET_ID, strAssetId);
372 try { 375 try {
  376 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  377 + Edge edge = checkEdgeId(edgeId, Operation.READ);
  378 +
373 AssetId assetId = new AssetId(toUUID(strAssetId)); 379 AssetId assetId = new AssetId(toUUID(strAssetId));
374 Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_EDGE); 380 Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_EDGE);
375 - if (asset.getEdgeId() == null || asset.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) {  
376 - throw new IncorrectParameterException("Asset isn't assigned to any edge!");  
377 - }  
378 -  
379 - Edge edge = checkEdgeId(asset.getEdgeId(), Operation.READ);  
380 381
381 - Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId)); 382 + Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId, edgeId));
382 383
383 logEntityAction(assetId, asset, 384 logEntityAction(assetId, asset,
384 asset.getCustomerId(), 385 asset.getCustomerId(),
@@ -398,24 +399,20 @@ public class AssetController extends BaseController { @@ -398,24 +399,20 @@ public class AssetController extends BaseController {
398 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") 399 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
399 @RequestMapping(value = "/edge/{edgeId}/assets", params = {"limit"}, method = RequestMethod.GET) 400 @RequestMapping(value = "/edge/{edgeId}/assets", params = {"limit"}, method = RequestMethod.GET)
400 @ResponseBody 401 @ResponseBody
401 - public TextPageData<Asset> getEdgeAssets(  
402 - @PathVariable("edgeId") String strEdgeId, 402 + public TimePageData<Asset> getEdgeAssets(
  403 + @PathVariable(EDGE_ID) String strEdgeId,
403 @RequestParam int limit, 404 @RequestParam int limit,
404 - @RequestParam(required = false) String type,  
405 - @RequestParam(required = false) String textSearch,  
406 - @RequestParam(required = false) String idOffset,  
407 - @RequestParam(required = false) String textOffset) throws ThingsboardException {  
408 - checkParameter("edgeId", strEdgeId); 405 + @RequestParam(required = false) Long startTime,
  406 + @RequestParam(required = false) Long endTime,
  407 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  408 + @RequestParam(required = false) String offset) throws ThingsboardException {
  409 + checkParameter(EDGE_ID, strEdgeId);
409 try { 410 try {
410 TenantId tenantId = getCurrentUser().getTenantId(); 411 TenantId tenantId = getCurrentUser().getTenantId();
411 EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); 412 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
412 checkEdgeId(edgeId, Operation.READ); 413 checkEdgeId(edgeId, Operation.READ);
413 - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);  
414 - if (type != null && type.trim().length()>0) {  
415 - return checkNotNull(assetService.findAssetsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink));  
416 - } else {  
417 - return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink));  
418 - } 414 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  415 + return checkNotNull(assetService.findAssetsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
419 } catch (Exception e) { 416 } catch (Exception e) {
420 throw handleException(e); 417 throw handleException(e);
421 } 418 }
@@ -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,
@@ -49,6 +49,9 @@ import org.thingsboard.server.common.data.id.EdgeId; @@ -49,6 +49,9 @@ import org.thingsboard.server.common.data.id.EdgeId;
49 import org.thingsboard.server.common.data.id.TenantId; 49 import org.thingsboard.server.common.data.id.TenantId;
50 import org.thingsboard.server.common.data.page.TextPageData; 50 import org.thingsboard.server.common.data.page.TextPageData;
51 import org.thingsboard.server.common.data.page.TextPageLink; 51 import org.thingsboard.server.common.data.page.TextPageLink;
  52 +import org.thingsboard.server.common.data.page.TimePageData;
  53 +import org.thingsboard.server.common.data.page.TimePageLink;
  54 +import org.thingsboard.server.common.data.rule.RuleChain;
52 import org.thingsboard.server.common.data.security.DeviceCredentials; 55 import org.thingsboard.server.common.data.security.DeviceCredentials;
53 import org.thingsboard.server.dao.device.claim.ClaimResponse; 56 import org.thingsboard.server.dao.device.claim.ClaimResponse;
54 import org.thingsboard.server.dao.device.claim.ClaimResult; 57 import org.thingsboard.server.dao.device.claim.ClaimResult;
@@ -96,10 +99,7 @@ public class DeviceController extends BaseController { @@ -96,10 +99,7 @@ public class DeviceController extends BaseController {
96 try { 99 try {
97 device.setTenantId(getCurrentUser().getTenantId()); 100 device.setTenantId(getCurrentUser().getTenantId());
98 101
99 - Operation operation = device.getId() == null ? Operation.CREATE : Operation.WRITE;  
100 -  
101 - accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation,  
102 - device.getId(), device); 102 + checkEntity(device.getId(), device, Resource.DEVICE);
103 103
104 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken)); 104 Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
105 105
@@ -519,19 +519,20 @@ public class DeviceController extends BaseController { @@ -519,19 +519,20 @@ public class DeviceController extends BaseController {
519 } 519 }
520 520
521 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 521 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
522 - @RequestMapping(value = "/edge/device/{deviceId}", method = RequestMethod.DELETE) 522 + @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.DELETE)
523 @ResponseBody 523 @ResponseBody
524 - public Device unassignDeviceFromEdge(@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { 524 + public Device unassignDeviceFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
  525 + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
  526 + checkParameter(EDGE_ID, strEdgeId);
525 checkParameter(DEVICE_ID, strDeviceId); 527 checkParameter(DEVICE_ID, strDeviceId);
526 try { 528 try {
  529 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  530 + Edge edge = checkEdgeId(edgeId, Operation.READ);
  531 +
527 DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); 532 DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
528 Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_EDGE); 533 Device device = checkDeviceId(deviceId, Operation.UNASSIGN_FROM_EDGE);
529 - if (device.getEdgeId() == null || device.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) {  
530 - throw new IncorrectParameterException("Device isn't assigned to any edge!");  
531 - }  
532 - Edge edge = checkEdgeId(device.getEdgeId(), Operation.READ);  
533 534
534 - Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId)); 535 + Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId, edgeId));
535 536
536 logEntityAction(deviceId, device, 537 logEntityAction(deviceId, device,
537 device.getCustomerId(), 538 device.getCustomerId(),
@@ -549,24 +550,20 @@ public class DeviceController extends BaseController { @@ -549,24 +550,20 @@ public class DeviceController extends BaseController {
549 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") 550 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
550 @RequestMapping(value = "/edge/{edgeId}/devices", params = {"limit"}, method = RequestMethod.GET) 551 @RequestMapping(value = "/edge/{edgeId}/devices", params = {"limit"}, method = RequestMethod.GET)
551 @ResponseBody 552 @ResponseBody
552 - public TextPageData<Device> getEdgeDevices(  
553 - @PathVariable("edgeId") String strEdgeId, 553 + public TimePageData<Device> getEdgeDevices(
  554 + @PathVariable(EDGE_ID) String strEdgeId,
554 @RequestParam int limit, 555 @RequestParam int limit,
555 - @RequestParam(required = false) String type,  
556 - @RequestParam(required = false) String textSearch,  
557 - @RequestParam(required = false) String idOffset,  
558 - @RequestParam(required = false) String textOffset) throws ThingsboardException {  
559 - checkParameter("edgeId", strEdgeId); 556 + @RequestParam(required = false) Long startTime,
  557 + @RequestParam(required = false) Long endTime,
  558 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  559 + @RequestParam(required = false) String offset) throws ThingsboardException {
  560 + checkParameter(EDGE_ID, strEdgeId);
560 try { 561 try {
561 TenantId tenantId = getCurrentUser().getTenantId(); 562 TenantId tenantId = getCurrentUser().getTenantId();
562 EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); 563 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
563 checkEdgeId(edgeId, Operation.READ); 564 checkEdgeId(edgeId, Operation.READ);
564 - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);  
565 - if (type != null && type.trim().length()>0) {  
566 - return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink));  
567 - } else {  
568 - return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink));  
569 - } 565 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  566 + return checkNotNull(deviceService.findDevicesByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
570 } catch (Exception e) { 567 } catch (Exception e) {
571 throw handleException(e); 568 throw handleException(e);
572 } 569 }
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.controller; 16 package org.thingsboard.server.controller;
17 17
  18 +import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture; 19 import com.google.common.util.concurrent.ListenableFuture;
19 import org.springframework.http.HttpStatus; 20 import org.springframework.http.HttpStatus;
20 import org.springframework.security.access.prepost.PreAuthorize; 21 import org.springframework.security.access.prepost.PreAuthorize;
@@ -92,15 +93,16 @@ public class EdgeController extends BaseController { @@ -92,15 +93,16 @@ public class EdgeController extends BaseController {
92 accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, 93 accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation,
93 edge.getId(), edge); 94 edge.getId(), edge);
94 95
95 - Edge result = checkNotNull(edgeService.saveEdge(edge)); 96 + Edge savedEdge = checkNotNull(edgeService.saveEdge(edge));
96 97
97 if (created) { 98 if (created) {
98 - ruleChainService.assignRuleChainToEdge(tenantId, defaultRootEdgeRuleChain.getId(), result.getId());  
99 - edgeService.setEdgeRootRuleChain(tenantId, result, defaultRootEdgeRuleChain.getId()); 99 + ruleChainService.assignRuleChainToEdge(tenantId, defaultRootEdgeRuleChain.getId(), savedEdge.getId());
  100 + edgeService.setEdgeRootRuleChain(tenantId, savedEdge, defaultRootEdgeRuleChain.getId());
  101 + edgeService.assignDefaultRuleChainsToEdge(tenantId, savedEdge.getId());
100 } 102 }
101 103
102 - logEntityAction(result.getId(), result, null, created ? ActionType.ADDED : ActionType.UPDATED, null);  
103 - return result; 104 + logEntityAction(savedEdge.getId(), savedEdge, null, created ? ActionType.ADDED : ActionType.UPDATED, null);
  105 + return savedEdge;
104 } catch (Exception e) { 106 } catch (Exception e) {
105 logEntityAction(emptyId(EntityType.EDGE), edge, 107 logEntityAction(emptyId(EntityType.EDGE), edge,
106 null, edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); 108 null, edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
@@ -48,6 +48,8 @@ import org.thingsboard.server.common.data.id.UUIDBased; @@ -48,6 +48,8 @@ import org.thingsboard.server.common.data.id.UUIDBased;
48 import org.thingsboard.server.common.data.kv.AttributeKvEntry; 48 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
49 import org.thingsboard.server.common.data.page.TextPageData; 49 import org.thingsboard.server.common.data.page.TextPageData;
50 import org.thingsboard.server.common.data.page.TextPageLink; 50 import org.thingsboard.server.common.data.page.TextPageLink;
  51 +import org.thingsboard.server.common.data.page.TimePageData;
  52 +import org.thingsboard.server.common.data.page.TimePageLink;
51 import org.thingsboard.server.dao.exception.IncorrectParameterException; 53 import org.thingsboard.server.dao.exception.IncorrectParameterException;
52 import org.thingsboard.server.dao.model.ModelConstants; 54 import org.thingsboard.server.dao.model.ModelConstants;
53 import org.thingsboard.server.queue.util.TbCoreComponent; 55 import org.thingsboard.server.queue.util.TbCoreComponent;
@@ -95,10 +97,7 @@ public class EntityViewController extends BaseController { @@ -95,10 +97,7 @@ public class EntityViewController extends BaseController {
95 try { 97 try {
96 entityView.setTenantId(getCurrentUser().getTenantId()); 98 entityView.setTenantId(getCurrentUser().getTenantId());
97 99
98 - Operation operation = entityView.getId() == null ? Operation.CREATE : Operation.WRITE;  
99 -  
100 - accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation,  
101 - entityView.getId(), entityView); 100 + checkEntity(entityView.getId(), entityView, Resource.ENTITY_VIEW);
102 101
103 EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView)); 102 EntityView savedEntityView = checkNotNull(entityViewService.saveEntityView(entityView));
104 List<ListenableFuture<List<Void>>> futures = new ArrayList<>(); 103 List<ListenableFuture<List<Void>>> futures = new ArrayList<>();
@@ -400,18 +399,20 @@ public class EntityViewController extends BaseController { @@ -400,18 +399,20 @@ public class EntityViewController extends BaseController {
400 } 399 }
401 400
402 @PreAuthorize("hasAuthority('TENANT_ADMIN')") 401 @PreAuthorize("hasAuthority('TENANT_ADMIN')")
403 - @RequestMapping(value = "/edge/entityView/{entityViewId}", method = RequestMethod.DELETE) 402 + @RequestMapping(value = "/edge/{edgeId}/entityView/{entityViewId}", method = RequestMethod.DELETE)
404 @ResponseBody 403 @ResponseBody
405 - public EntityView unassignEntityViewFromEdge(@PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException { 404 + public EntityView unassignEntityViewFromEdge(@PathVariable(EDGE_ID) String strEdgeId,
  405 + @PathVariable(ENTITY_VIEW_ID) String strEntityViewId) throws ThingsboardException {
  406 + checkParameter(EDGE_ID, strEdgeId);
406 checkParameter(ENTITY_VIEW_ID, strEntityViewId); 407 checkParameter(ENTITY_VIEW_ID, strEntityViewId);
407 try { 408 try {
  409 + EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
  410 + Edge edge = checkEdgeId(edgeId, Operation.READ);
  411 +
408 EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId)); 412 EntityViewId entityViewId = new EntityViewId(toUUID(strEntityViewId));
409 EntityView entityView = checkEntityViewId(entityViewId, Operation.UNASSIGN_FROM_EDGE); 413 EntityView entityView = checkEntityViewId(entityViewId, Operation.UNASSIGN_FROM_EDGE);
410 - if (entityView.getEdgeId() == null || entityView.getEdgeId().getId().equals(ModelConstants.NULL_UUID)) {  
411 - throw new IncorrectParameterException("Entity View isn't assigned to any edge!");  
412 - }  
413 - Edge edge = checkEdgeId(entityView.getEdgeId(), Operation.READ);  
414 - EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId)); 414 +
  415 + EntityView savedEntityView = checkNotNull(entityViewService.unassignEntityViewFromEdge(getTenantId(), entityViewId, edgeId));
415 logEntityAction(entityViewId, entityView, 416 logEntityAction(entityViewId, entityView,
416 entityView.getCustomerId(), 417 entityView.getCustomerId(),
417 ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName()); 418 ActionType.UNASSIGNED_FROM_EDGE, null, strEntityViewId, edge.getId().toString(), edge.getName());
@@ -428,24 +429,20 @@ public class EntityViewController extends BaseController { @@ -428,24 +429,20 @@ public class EntityViewController extends BaseController {
428 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") 429 @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
429 @RequestMapping(value = "/edge/{edgeId}/entityViews", params = {"limit"}, method = RequestMethod.GET) 430 @RequestMapping(value = "/edge/{edgeId}/entityViews", params = {"limit"}, method = RequestMethod.GET)
430 @ResponseBody 431 @ResponseBody
431 - public TextPageData<EntityView> getEdgeEntityViews(  
432 - @PathVariable("edgeId") String strEdgeId, 432 + public TimePageData<EntityView> getEdgeEntityViews(
  433 + @PathVariable(EDGE_ID) String strEdgeId,
433 @RequestParam int limit, 434 @RequestParam int limit,
434 - @RequestParam(required = false) String type,  
435 - @RequestParam(required = false) String textSearch,  
436 - @RequestParam(required = false) String idOffset,  
437 - @RequestParam(required = false) String textOffset) throws ThingsboardException {  
438 - checkParameter("edgeId", strEdgeId); 435 + @RequestParam(required = false) Long startTime,
  436 + @RequestParam(required = false) Long endTime,
  437 + @RequestParam(required = false, defaultValue = "false") boolean ascOrder,
  438 + @RequestParam(required = false) String offset) throws ThingsboardException {
  439 + checkParameter(EDGE_ID, strEdgeId);
439 try { 440 try {
440 TenantId tenantId = getCurrentUser().getTenantId(); 441 TenantId tenantId = getCurrentUser().getTenantId();
441 EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); 442 EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
442 checkEdgeId(edgeId, Operation.READ); 443 checkEdgeId(edgeId, Operation.READ);
443 - TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);  
444 - if (type != null && type.trim().length()>0) {  
445 - return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeIdAndType(tenantId, edgeId, type, pageLink));  
446 - } else {  
447 - return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink));  
448 - } 444 + TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
  445 + return checkNotNull(entityViewService.findEntityViewsByTenantIdAndEdgeId(tenantId, edgeId, pageLink).get());
449 } catch (Exception e) { 446 } catch (Exception e) {
450 throw handleException(e); 447 throw handleException(e);
451 } 448 }
@@ -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,15 +130,14 @@ public class RuleChainController extends BaseController { @@ -130,15 +130,14 @@ 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
140 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(),  
141 - created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); 137 + if (RuleChainType.SYSTEM.equals(savedRuleChain.getType())) {
  138 + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(),
  139 + created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
  140 + }
142 141
143 logEntityAction(savedRuleChain.getId(), savedRuleChain, 142 logEntityAction(savedRuleChain.getId(), savedRuleChain,
144 null, 143 null,
@@ -210,7 +209,9 @@ public class RuleChainController extends BaseController { @@ -210,7 +209,9 @@ public class RuleChainController extends BaseController {
210 RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE); 209 RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
211 RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData)); 210 RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(tenantId, ruleChainMetaData));
212 211
213 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED); 212 + if (RuleChainType.SYSTEM.equals(ruleChain.getType())) {
  213 + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
  214 + }
214 215
215 logEntityAction(ruleChain.getId(), ruleChain, 216 logEntityAction(ruleChain.getId(), ruleChain,
216 null, 217 null,
@@ -266,10 +267,12 @@ public class RuleChainController extends BaseController { @@ -266,10 +267,12 @@ public class RuleChainController extends BaseController {
266 267
267 referencingRuleChainIds.remove(ruleChain.getId()); 268 referencingRuleChainIds.remove(ruleChain.getId());
268 269
269 - referencingRuleChainIds.forEach(referencingRuleChainId ->  
270 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED)); 270 + if (RuleChainType.SYSTEM.equals(ruleChain.getType())) {
  271 + referencingRuleChainIds.forEach(referencingRuleChainId ->
  272 + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), referencingRuleChainId, ComponentLifecycleEvent.UPDATED));
271 273
272 - tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED); 274 + tbClusterService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.DELETED);
  275 + }
273 276
274 logEntityAction(ruleChainId, ruleChain, 277 logEntityAction(ruleChainId, ruleChain,
275 null, 278 null,
@@ -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");
@@ -554,7 +554,7 @@ public final class EdgeGrpcSession implements Closeable { @@ -554,7 +554,7 @@ public final class EdgeGrpcSession implements Closeable {
554 case ENTITY_DELETED_RPC_MESSAGE: 554 case ENTITY_DELETED_RPC_MESSAGE:
555 Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName); 555 Device device = ctx.getDeviceService().findDeviceByTenantIdAndName(edge.getTenantId(), deviceName);
556 if (device != null) { 556 if (device != null) {
557 - ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), device.getId()); 557 + ctx.getDeviceService().unassignDeviceFromEdge(edge.getTenantId(), device.getId(), edge.getId());
558 } 558 }
559 break; 559 break;
560 } 560 }
@@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
15 */ 15 */
16 package org.thingsboard.server.service.edge.rpc.init; 16 package org.thingsboard.server.service.edge.rpc.init;
17 17
  18 +import com.google.common.util.concurrent.Futures;
18 import io.grpc.stub.StreamObserver; 19 import io.grpc.stub.StreamObserver;
19 import lombok.extern.slf4j.Slf4j; 20 import lombok.extern.slf4j.Slf4j;
20 import org.springframework.beans.factory.annotation.Autowired; 21 import org.springframework.beans.factory.annotation.Autowired;
@@ -54,6 +55,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgCo @@ -54,6 +55,7 @@ import org.thingsboard.server.service.edge.rpc.constructor.EntityViewUpdateMsgCo
54 import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor; 55 import org.thingsboard.server.service.edge.rpc.constructor.RuleChainUpdateMsgConstructor;
55 56
56 import java.util.UUID; 57 import java.util.UUID;
  58 +import java.util.concurrent.Future;
57 59
58 @Service 60 @Service
59 @Slf4j 61 @Slf4j
@@ -100,10 +102,10 @@ public class DefaultInitEdgeService implements InitEdgeService { @@ -100,10 +102,10 @@ public class DefaultInitEdgeService implements InitEdgeService {
100 102
101 private void initDevices(Edge edge, StreamObserver<ResponseMsg> outputStream) { 103 private void initDevices(Edge edge, StreamObserver<ResponseMsg> outputStream) {
102 try { 104 try {
103 - TextPageLink pageLink = new TextPageLink(100);  
104 - TextPageData<Device> pageData; 105 + TimePageLink pageLink = new TimePageLink(100);
  106 + TimePageData<Device> pageData;
105 do { 107 do {
106 - pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink); 108 + pageData = deviceService.findDevicesByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
107 if (!pageData.getData().isEmpty()) { 109 if (!pageData.getData().isEmpty()) {
108 log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); 110 log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
109 for (Device device : pageData.getData()) { 111 for (Device device : pageData.getData()) {
@@ -130,10 +132,10 @@ public class DefaultInitEdgeService implements InitEdgeService { @@ -130,10 +132,10 @@ public class DefaultInitEdgeService implements InitEdgeService {
130 132
131 private void initAssets(Edge edge, StreamObserver<ResponseMsg> outputStream) { 133 private void initAssets(Edge edge, StreamObserver<ResponseMsg> outputStream) {
132 try { 134 try {
133 - TextPageLink pageLink = new TextPageLink(100);  
134 - TextPageData<Asset> pageData; 135 + TimePageLink pageLink = new TimePageLink(100);
  136 + TimePageData<Asset> pageData;
135 do { 137 do {
136 - pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink); 138 + pageData = assetService.findAssetsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
137 if (!pageData.getData().isEmpty()) { 139 if (!pageData.getData().isEmpty()) {
138 log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); 140 log.trace("[{}] [{}] asset(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
139 for (Asset asset : pageData.getData()) { 141 for (Asset asset : pageData.getData()) {
@@ -160,10 +162,10 @@ public class DefaultInitEdgeService implements InitEdgeService { @@ -160,10 +162,10 @@ public class DefaultInitEdgeService implements InitEdgeService {
160 162
161 private void initEntityViews(Edge edge, StreamObserver<ResponseMsg> outputStream) { 163 private void initEntityViews(Edge edge, StreamObserver<ResponseMsg> outputStream) {
162 try { 164 try {
163 - TextPageLink pageLink = new TextPageLink(100);  
164 - TextPageData<EntityView> pageData; 165 + TimePageLink pageLink = new TimePageLink(100);
  166 + TimePageData<EntityView> pageData;
165 do { 167 do {
166 - pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink); 168 + pageData = entityViewService.findEntityViewsByTenantIdAndEdgeId(edge.getTenantId(), edge.getId(), pageLink).get();
167 if (!pageData.getData().isEmpty()) { 169 if (!pageData.getData().isEmpty()) {
168 log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size()); 170 log.trace("[{}] [{}] entity view(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
169 for (EntityView entityView : pageData.getData()) { 171 for (EntityView entityView : pageData.getData()) {
@@ -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;
@@ -312,18 +312,6 @@ public class CassandraDatabaseUpgradeService extends AbstractCassandraDatabaseUp @@ -312,18 +312,6 @@ public class CassandraDatabaseUpgradeService extends AbstractCassandraDatabaseUp
312 loadCql(schemaUpdateFile); 312 loadCql(schemaUpdateFile);
313 313
314 try { 314 try {
315 - cluster.getSession().execute("alter table asset add edge_id text");  
316 - Thread.sleep(2500);  
317 - } catch (InvalidQueryException e) {}  
318 - try {  
319 - cluster.getSession().execute("alter table device add edge_id text");  
320 - Thread.sleep(2500);  
321 - } catch (InvalidQueryException e) {}  
322 - try {  
323 - cluster.getSession().execute("alter table entity_view add edge_id text");  
324 - Thread.sleep(2500);  
325 - } catch (InvalidQueryException e) {}  
326 - try {  
327 cluster.getSession().execute("alter table rule_chain add type text"); 315 cluster.getSession().execute("alter table rule_chain add type text");
328 Thread.sleep(2500); 316 Thread.sleep(2500);
329 } catch (InvalidQueryException e) {} 317 } catch (InvalidQueryException e) {}
@@ -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);
@@ -239,15 +239,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @@ -239,15 +239,6 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
239 schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.6.0", SCHEMA_UPDATE_SQL); 239 schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "2.6.0", SCHEMA_UPDATE_SQL);
240 loadSql(schemaUpdateFile, conn); 240 loadSql(schemaUpdateFile, conn);
241 try { 241 try {
242 - conn.createStatement().execute("ALTER TABLE asset ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script  
243 - } catch (Exception e) {}  
244 - try {  
245 - conn.createStatement().execute("ALTER TABLE device ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script  
246 - } catch (Exception e) {}  
247 - try {  
248 - conn.createStatement().execute("ALTER TABLE entity_view ADD edge_id varchar(31)"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script  
249 - } catch (Exception e) {}  
250 - try {  
251 conn.createStatement().execute("ALTER TABLE rule_chain ADD type varchar(255) DEFAULT 'SYSTEM'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script 242 conn.createStatement().execute("ALTER TABLE rule_chain ADD type varchar(255) DEFAULT 'SYSTEM'"); //NOSONAR, ignoring because method used to execute thingsboard database upgrade script
252 } catch (Exception e) {} 243 } catch (Exception e) {}
253 log.info("Schema updated."); 244 log.info("Schema updated.");
@@ -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>
@@ -25,6 +25,8 @@ import org.thingsboard.server.common.data.id.EdgeId; @@ -25,6 +25,8 @@ import org.thingsboard.server.common.data.id.EdgeId;
25 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
26 import org.thingsboard.server.common.data.page.TextPageData; 26 import org.thingsboard.server.common.data.page.TextPageData;
27 import org.thingsboard.server.common.data.page.TextPageLink; 27 import org.thingsboard.server.common.data.page.TextPageLink;
  28 +import org.thingsboard.server.common.data.page.TimePageData;
  29 +import org.thingsboard.server.common.data.page.TimePageLink;
28 30
29 import java.util.List; 31 import java.util.List;
30 import java.util.Optional; 32 import java.util.Optional;
@@ -67,9 +69,7 @@ public interface AssetService { @@ -67,9 +69,7 @@ public interface AssetService {
67 69
68 Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId); 70 Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId);
69 71
70 - Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId); 72 + Asset unassignAssetFromEdge(TenantId tenantId, AssetId assetId, EdgeId edgeId);
71 73
72 - TextPageData<Asset> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink);  
73 -  
74 - TextPageData<Asset> findAssetsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); 74 + ListenableFuture<TimePageData<Asset>> findAssetsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
75 } 75 }
@@ -25,11 +25,13 @@ import org.thingsboard.server.common.data.id.EdgeId; @@ -25,11 +25,13 @@ import org.thingsboard.server.common.data.id.EdgeId;
25 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
26 import org.thingsboard.server.common.data.page.TextPageData; 26 import org.thingsboard.server.common.data.page.TextPageData;
27 import org.thingsboard.server.common.data.page.TextPageLink; 27 import org.thingsboard.server.common.data.page.TextPageLink;
  28 +import org.thingsboard.server.common.data.page.TimePageData;
  29 +import org.thingsboard.server.common.data.page.TimePageLink;
28 30
29 import java.util.List; 31 import java.util.List;
30 32
31 public interface DeviceService { 33 public interface DeviceService {
32 - 34 +
33 Device findDeviceById(TenantId tenantId, DeviceId deviceId); 35 Device findDeviceById(TenantId tenantId, DeviceId deviceId);
34 36
35 ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId); 37 ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId);
@@ -68,10 +70,7 @@ public interface DeviceService { @@ -68,10 +70,7 @@ public interface DeviceService {
68 70
69 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); 71 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);
70 72
71 - Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId);  
72 -  
73 - TextPageData<Device> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink);  
74 -  
75 - TextPageData<Device> findDevicesByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink); 73 + Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);
76 74
  75 + ListenableFuture<TimePageData<Device>> findDevicesByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
77 } 76 }
@@ -82,6 +82,8 @@ public interface EdgeService { @@ -82,6 +82,8 @@ public interface EdgeService {
82 82
83 Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException; 83 Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException;
84 84
  85 + void assignDefaultRuleChainsToEdge(TenantId tenantId, EdgeId edgeId);
  86 +
85 ListenableFuture<TimePageData<Edge>> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId, TimePageLink pageLink); 87 ListenableFuture<TimePageData<Edge>> findEdgesByTenantIdAndRuleChainId(TenantId tenantId, RuleChainId ruleChainId, TimePageLink pageLink);
86 88
87 ListenableFuture<TimePageData<Edge>> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId, TimePageLink pageLink); 89 ListenableFuture<TimePageData<Edge>> findEdgesByTenantIdAndDashboardId(TenantId tenantId, DashboardId dashboardId, TimePageLink pageLink);
@@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.id.EntityViewId; @@ -26,6 +26,8 @@ import org.thingsboard.server.common.data.id.EntityViewId;
26 import org.thingsboard.server.common.data.id.TenantId; 26 import org.thingsboard.server.common.data.id.TenantId;
27 import org.thingsboard.server.common.data.page.TextPageData; 27 import org.thingsboard.server.common.data.page.TextPageData;
28 import org.thingsboard.server.common.data.page.TextPageLink; 28 import org.thingsboard.server.common.data.page.TextPageLink;
  29 +import org.thingsboard.server.common.data.page.TimePageData;
  30 +import org.thingsboard.server.common.data.page.TimePageLink;
29 31
30 import java.util.List; 32 import java.util.List;
31 33
@@ -68,11 +70,7 @@ public interface EntityViewService { @@ -68,11 +70,7 @@ public interface EntityViewService {
68 70
69 EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId); 71 EntityView assignEntityViewToEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId);
70 72
71 - EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId);  
72 -  
73 - TextPageData<EntityView> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TextPageLink pageLink);  
74 -  
75 - TextPageData<EntityView> findEntityViewsByTenantIdAndEdgeIdAndType(TenantId tenantId, EdgeId edgeId, String type, TextPageLink pageLink);  
76 - 73 + EntityView unassignEntityViewFromEdge(TenantId tenantId, EntityViewId entityViewId, EdgeId edgeId);
77 74
  75 + ListenableFuture<TimePageData<EntityView>> findEntityViewsByTenantIdAndEdgeId(TenantId tenantId, EdgeId edgeId, TimePageLink pageLink);
78 } 76 }
@@ -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>
@@ -18,7 +18,6 @@ package org.thingsboard.server.common.data; @@ -18,7 +18,6 @@ package org.thingsboard.server.common.data;
18 import lombok.EqualsAndHashCode; 18 import lombok.EqualsAndHashCode;
19 import org.thingsboard.server.common.data.id.CustomerId; 19 import org.thingsboard.server.common.data.id.CustomerId;
20 import org.thingsboard.server.common.data.id.DeviceId; 20 import org.thingsboard.server.common.data.id.DeviceId;
21 -import org.thingsboard.server.common.data.id.EdgeId;  
22 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
23 22
24 @EqualsAndHashCode(callSuper = true) 23 @EqualsAndHashCode(callSuper = true)
@@ -28,7 +27,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -28,7 +27,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
28 27
29 private TenantId tenantId; 28 private TenantId tenantId;
30 private CustomerId customerId; 29 private CustomerId customerId;
31 - private EdgeId edgeId;  
32 private String name; 30 private String name;
33 private String type; 31 private String type;
34 private String label; 32 private String label;
@@ -48,7 +46,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -48,7 +46,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
48 this.name = device.getName(); 46 this.name = device.getName();
49 this.type = device.getType(); 47 this.type = device.getType();
50 this.label = device.getLabel(); 48 this.label = device.getLabel();
51 - this.edgeId = device.getEdgeId();  
52 } 49 }
53 50
54 public TenantId getTenantId() { 51 public TenantId getTenantId() {
@@ -67,14 +64,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -67,14 +64,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
67 this.customerId = customerId; 64 this.customerId = customerId;
68 } 65 }
69 66
70 - public EdgeId getEdgeId() {  
71 - return edgeId;  
72 - }  
73 -  
74 - public void setEdgeId(EdgeId edgeId) {  
75 - this.edgeId = edgeId;  
76 - }  
77 -  
78 @Override 67 @Override
79 public String getName() { 68 public String getName() {
80 return name; 69 return name;
@@ -112,8 +101,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen @@ -112,8 +101,6 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen
112 builder.append(tenantId); 101 builder.append(tenantId);
113 builder.append(", customerId="); 102 builder.append(", customerId=");
114 builder.append(customerId); 103 builder.append(customerId);
115 - builder.append(", edgeId=");  
116 - builder.append(edgeId);  
117 builder.append(", name="); 104 builder.append(", name=");
118 builder.append(name); 105 builder.append(name);
119 builder.append(", type="); 106 builder.append(", type=");
@@ -19,7 +19,6 @@ import lombok.AllArgsConstructor; @@ -19,7 +19,6 @@ import lombok.AllArgsConstructor;
19 import lombok.Data; 19 import lombok.Data;
20 import lombok.EqualsAndHashCode; 20 import lombok.EqualsAndHashCode;
21 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
22 -import org.thingsboard.server.common.data.id.EdgeId;  
23 import org.thingsboard.server.common.data.id.EntityId; 22 import org.thingsboard.server.common.data.id.EntityId;
24 import org.thingsboard.server.common.data.id.EntityViewId; 23 import org.thingsboard.server.common.data.id.EntityViewId;
25 import org.thingsboard.server.common.data.id.TenantId; 24 import org.thingsboard.server.common.data.id.TenantId;
@@ -40,7 +39,6 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> @@ -40,7 +39,6 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId>
40 private EntityId entityId; 39 private EntityId entityId;
41 private TenantId tenantId; 40 private TenantId tenantId;
42 private CustomerId customerId; 41 private CustomerId customerId;
43 - private EdgeId edgeId;  
44 private String name; 42 private String name;
45 private String type; 43 private String type;
46 private TelemetryEntityView keys; 44 private TelemetryEntityView keys;
@@ -15,13 +15,10 @@ @@ -15,13 +15,10 @@
15 */ 15 */
16 package org.thingsboard.server.common.data.asset; 16 package org.thingsboard.server.common.data.asset;
17 17
18 -import com.fasterxml.jackson.databind.JsonNode;  
19 import lombok.EqualsAndHashCode; 18 import lombok.EqualsAndHashCode;
20 import org.thingsboard.server.common.data.*; 19 import org.thingsboard.server.common.data.*;
21 import org.thingsboard.server.common.data.id.AssetId; 20 import org.thingsboard.server.common.data.id.AssetId;
22 import org.thingsboard.server.common.data.id.CustomerId; 21 import org.thingsboard.server.common.data.id.CustomerId;
23 -import org.thingsboard.server.common.data.id.EdgeId;  
24 -import org.thingsboard.server.common.data.id.EdgeId;  
25 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
26 23
27 @EqualsAndHashCode(callSuper = true) 24 @EqualsAndHashCode(callSuper = true)
@@ -34,7 +31,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements @@ -34,7 +31,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
34 private String name; 31 private String name;
35 private String type; 32 private String type;
36 private String label; 33 private String label;
37 - private EdgeId edgeId;  
38 34
39 public Asset() { 35 public Asset() {
40 super(); 36 super();
@@ -51,7 +47,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements @@ -51,7 +47,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
51 this.name = asset.getName(); 47 this.name = asset.getName();
52 this.type = asset.getType(); 48 this.type = asset.getType();
53 this.label = asset.getLabel(); 49 this.label = asset.getLabel();
54 - this.edgeId = asset.getEdgeId();  
55 } 50 }
56 51
57 public TenantId getTenantId() { 52 public TenantId getTenantId() {
@@ -70,14 +65,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements @@ -70,14 +65,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
70 this.customerId = customerId; 65 this.customerId = customerId;
71 } 66 }
72 67
73 - public EdgeId getEdgeId() {  
74 - return edgeId;  
75 - }  
76 -  
77 - public void setEdgeId(EdgeId edgeId) {  
78 - this.edgeId = edgeId;  
79 - }  
80 -  
81 @Override 68 @Override
82 public String getName() { 69 public String getName() {
83 return name; 70 return name;
@@ -115,8 +102,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements @@ -115,8 +102,6 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements
115 builder.append(tenantId); 102 builder.append(tenantId);
116 builder.append(", customerId="); 103 builder.append(", customerId=");
117 builder.append(customerId); 104 builder.append(customerId);
118 - builder.append(", edgeId=");  
119 - builder.append(edgeId);  
120 builder.append(", name="); 105 builder.append(", name=");
121 builder.append(name); 106 builder.append(name);
122 builder.append(", type="); 107 builder.append(", type=");
@@ -22,6 +22,7 @@ public enum RelationTypeGroup { @@ -22,6 +22,7 @@ public enum RelationTypeGroup {
22 DASHBOARD, 22 DASHBOARD,
23 RULE_CHAIN, 23 RULE_CHAIN,
24 RULE_NODE, 24 RULE_NODE,
25 - EDGE 25 + EDGE,
  26 + EDGE_DEFAULT_RULE_CHAIN
26 27
27 } 28 }
@@ -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>
@@ -341,16 +341,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -341,16 +341,6 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
341 } 341 }
342 } 342 }
343 343
344 - private void deleteRelation(TenantId tenantId, EntityRelation alarmRelation) {  
345 - log.debug("Deleting Alarm relation: {}", alarmRelation);  
346 - relationService.deleteRelation(tenantId, alarmRelation);  
347 - }  
348 -  
349 - private void createRelation(TenantId tenantId, EntityRelation alarmRelation) {  
350 - log.debug("Creating Alarm relation: {}", alarmRelation);  
351 - relationService.saveRelation(tenantId, alarmRelation);  
352 - }  
353 -  
354 private Alarm merge(Alarm existing, Alarm alarm) { 344 private Alarm merge(Alarm existing, Alarm alarm) {
355 if (alarm.getStartTs() > existing.getEndTs()) { 345 if (alarm.getStartTs() > existing.getEndTs()) {
356 existing.setEndTs(alarm.getStartTs()); 346 existing.setEndTs(alarm.getStartTs());
@@ -395,7 +385,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -395,7 +385,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
395 } 385 }
396 } 386 }
397 387
398 - private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) { 388 + private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status, boolean createAnyRelation) throws ExecutionException, InterruptedException {
399 if (createAnyRelation) { 389 if (createAnyRelation) {
400 createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM)); 390 createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM));
401 } 391 }
@@ -404,13 +394,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -404,13 +394,13 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
404 createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM)); 394 createRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
405 } 395 }
406 396
407 - private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) { 397 + private void deleteAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus status) throws ExecutionException, InterruptedException {
408 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM)); 398 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.name(), RelationTypeGroup.ALARM));
409 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM)); 399 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getClearSearchStatus().name(), RelationTypeGroup.ALARM));
410 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM)); 400 deleteRelation(tenantId, new EntityRelation(entityId, alarmId, ALARM_RELATION_PREFIX + status.getAckSearchStatus().name(), RelationTypeGroup.ALARM));
411 } 401 }
412 402
413 - private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) { 403 + private void updateAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId, AlarmStatus oldStatus, AlarmStatus newStatus) throws ExecutionException, InterruptedException {
414 deleteAlarmRelation(tenantId, entityId, alarmId, oldStatus); 404 deleteAlarmRelation(tenantId, entityId, alarmId, oldStatus);
415 createAlarmRelation(tenantId, entityId, alarmId, newStatus, false); 405 createAlarmRelation(tenantId, entityId, alarmId, newStatus, false);
416 } 406 }
@@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.EntitySubtype; @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.EntitySubtype;
20 import org.thingsboard.server.common.data.asset.Asset; 20 import org.thingsboard.server.common.data.asset.Asset;
21 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
22 import org.thingsboard.server.common.data.page.TextPageLink; 22 import org.thingsboard.server.common.data.page.TextPageLink;
  23 +import org.thingsboard.server.common.data.page.TimePageLink;
23 import org.thingsboard.server.dao.Dao; 24 import org.thingsboard.server.dao.Dao;
24 25
25 import java.util.List; 26 import java.util.List;
@@ -116,23 +117,12 @@ public interface AssetDao extends Dao<Asset> { @@ -116,23 +117,12 @@ public interface AssetDao extends Dao<Asset> {
116 ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId); 117 ListenableFuture<List<EntitySubtype>> findTenantAssetTypesAsync(UUID tenantId);
117 118
118 /** 119 /**
119 - * Find assets by tenantId, customerId and page link. 120 + * Find assets by tenantId, edgeId and page link.
120 * 121 *
121 * @param tenantId the tenantId 122 * @param tenantId the tenantId
122 * @param edgeId the edgeId 123 * @param edgeId the edgeId
123 * @param pageLink the page link 124 * @param pageLink the page link
124 * @return the list of asset objects 125 * @return the list of asset objects
125 */ 126 */
126 - List<Asset> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TextPageLink pageLink);  
127 -  
128 - /**  
129 - * Find assets by tenantId, customerId, type and page link.  
130 - *  
131 - * @param tenantId the tenantId  
132 - * @param edgeId the edgeId  
133 - * @param type the type  
134 - * @param pageLink the page link  
135 - * @return the list of asset objects  
136 - */  
137 - List<Asset> findAssetsByTenantIdAndEdgeIdAndType(UUID tenantId, UUID edgeId, String type, TextPageLink pageLink); 127 + ListenableFuture<List<Asset>> findAssetsByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink);
138 } 128 }