diff --git a/application/pom.xml b/application/pom.xml
index 8508466012..ad4dd02794 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
application
diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java
index 58180583ef..96bf414240 100644
--- a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java
+++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java
@@ -48,8 +48,6 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase
}
log.info("Schema updated.");
break;
- case "2.5.0":
- break;
default:
throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion);
}
diff --git a/common/actor/pom.xml b/common/actor/pom.xml
new file mode 100644
index 0000000000..c0dd554f0e
--- /dev/null
+++ b/common/actor/pom.xml
@@ -0,0 +1,75 @@
+
+
+ 4.0.0
+
+ org.thingsboard
+ 3.0.1-SNAPSHOT
+ common
+
+ org.thingsboard.common
+ actor
+ jar
+
+ Thingsboard Actor system
+ https://thingsboard.io
+
+
+ UTF-8
+ ${basedir}/../..
+
+
+
+
+ org.thingsboard.common
+ util
+
+
+ org.thingsboard.common
+ message
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.slf4j
+ log4j-over-slf4j
+
+
+ ch.qos.logback
+ logback-core
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-all
+ test
+
+
+
+
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/DefaultTbActorSystem.java b/common/actor/src/main/java/org/thingsboard/server/actors/DefaultTbActorSystem.java
new file mode 100644
index 0000000000..7d89abd3bb
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/DefaultTbActorSystem.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.common.util.ThingsBoardThreadFactory;
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+@Slf4j
+@Data
+public class DefaultTbActorSystem implements TbActorSystem {
+
+ private final ConcurrentMap dispatchers = new ConcurrentHashMap<>();
+ private final ConcurrentMap actors = new ConcurrentHashMap<>();
+ private final ConcurrentMap actorCreationLocks = new ConcurrentHashMap<>();
+ @Getter
+ private final TbActorSystemSettings settings;
+ @Getter
+ private final ScheduledExecutorService scheduler;
+
+ public DefaultTbActorSystem(TbActorSystemSettings settings) {
+ this.settings = settings;
+ this.scheduler = Executors.newScheduledThreadPool(settings.getSchedulerPoolSize(), ThingsBoardThreadFactory.forName("actor-system-scheduler"));
+ }
+
+ @Override
+ public void createDispatcher(String dispatcherId, ExecutorService executor) {
+ Dispatcher current = dispatchers.putIfAbsent(dispatcherId, new Dispatcher(dispatcherId, executor));
+ if (current != null) {
+ throw new RuntimeException("Dispatcher with id [" + dispatcherId + "] is already registered!");
+ }
+ }
+
+ @Override
+ public void destroyDispatcher(String dispatcherId) {
+ Dispatcher dispatcher = dispatchers.remove(dispatcherId);
+ if (dispatcher != null) {
+ dispatcher.getExecutor().shutdownNow();
+ } else {
+ throw new RuntimeException("Dispatcher with id [" + dispatcherId + "] is not registered!");
+ }
+ }
+
+ @Override
+ public TbActorId createRootActor(String dispatcherId, TbActorCreator creator) {
+ return createActor(dispatcherId, creator, null);
+ }
+
+ @Override
+ public TbActorId createChildActor(String dispatcherId, TbActorCreator creator, TbActorId parent) {
+ return createActor(dispatcherId, creator, parent);
+ }
+
+ private TbActorId createActor(String dispatcherId, TbActorCreator creator, TbActorId parent) {
+ Dispatcher dispatcher = dispatchers.get(dispatcherId);
+ if (dispatcher == null) {
+ log.warn("Dispatcher with id [{}] is not registered!", dispatcherId);
+ throw new RuntimeException("Dispatcher with id [" + dispatcherId + "] is not registered!");
+ }
+
+ TbActorId actorId = creator.createActorId();
+ TbActorMailbox actorMailbox = actors.get(actorId);
+ if (actorMailbox != null) {
+ log.debug("Actor with id [{}] is already registered!", actorId);
+ } else {
+ Lock actorCreationLock = actorCreationLocks.computeIfAbsent(actorId, id -> new ReentrantLock());
+ actorCreationLock.lock();
+ try {
+ actorMailbox = actors.get(actorId);
+ if (actorMailbox == null) {
+ log.debug("Creating actor with id [{}]!", actorId);
+ TbActor actor = creator.createActor();
+ TbActorMailbox mailbox = new TbActorMailbox(this, settings, actorId, parent, actor, dispatcher);
+ actors.put(actorId, mailbox);
+ mailbox.initActor();
+ } else {
+ log.debug("Actor with id [{}] is already registered!", actorId);
+ }
+ } finally {
+ actorCreationLock.unlock();
+ actorCreationLocks.remove(actorId);
+ }
+ }
+ return actorId;
+ }
+
+ @Override
+ public void tell(TbActorId target, TbActorMsg actorMsg) {
+ TbActorMailbox mailbox = actors.get(target);
+ if (mailbox == null) {
+ throw new TbActorNotRegisteredException(target, "Actor with id [" + target + "] is not registered!");
+ }
+ mailbox.enqueue(actorMsg);
+ }
+
+ @Override
+ public void stop(TbActorId actorId) {
+ TbActorMailbox mailbox = actors.remove(actorId);
+ if (mailbox != null) {
+ mailbox.destroy();
+ }
+ }
+
+ @Override
+ public void stop() {
+ dispatchers.values().forEach(dispatcher -> dispatcher.getExecutor().shutdownNow());
+ actors.clear();
+ }
+
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/Dispatcher.java b/common/actor/src/main/java/org/thingsboard/server/actors/Dispatcher.java
new file mode 100644
index 0000000000..bd02e74603
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/Dispatcher.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Data;
+
+import java.util.concurrent.ExecutorService;
+
+@Data
+class Dispatcher {
+
+ private final String dispatcherId;
+ private final ExecutorService executor;
+
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/InitFailureStrategy.java b/common/actor/src/main/java/org/thingsboard/server/actors/InitFailureStrategy.java
new file mode 100644
index 0000000000..37d0379bb0
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/InitFailureStrategy.java
@@ -0,0 +1,45 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+public class InitFailureStrategy {
+
+ @Getter
+ private boolean stop;
+ @Getter
+ private long retryDelay;
+
+ private InitFailureStrategy(boolean stop, long retryDelay) {
+ this.stop = stop;
+ this.retryDelay = retryDelay;
+ }
+
+ public static InitFailureStrategy retryImmediately() {
+ return new InitFailureStrategy(false, 0);
+ }
+
+ public static InitFailureStrategy retryWithDelay(long ms) {
+ return new InitFailureStrategy(false, ms);
+ }
+
+ public static InitFailureStrategy stop() {
+ return new InitFailureStrategy(true, 0);
+ }
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/ProcessFailureStrategy.java b/common/actor/src/main/java/org/thingsboard/server/actors/ProcessFailureStrategy.java
new file mode 100644
index 0000000000..7448ba964b
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/ProcessFailureStrategy.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Getter;
+import lombok.ToString;
+
+@ToString
+public class ProcessFailureStrategy {
+
+ @Getter
+ private boolean stop;
+
+ private ProcessFailureStrategy(boolean stop) {
+ this.stop = stop;
+ }
+
+ public static ProcessFailureStrategy stop() {
+ return new ProcessFailureStrategy(true);
+ }
+
+ public static ProcessFailureStrategy resume() {
+ return new ProcessFailureStrategy(false);
+ }
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActor.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActor.java
new file mode 100644
index 0000000000..55419582bc
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActor.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+public interface TbActor {
+
+ void init();
+
+ boolean process(TbActorCtx ctx, TbActorMsg msg);
+
+ void destroy();
+
+ default InitFailureStrategy onInitFailure(int attempt, Throwable t) {
+ return InitFailureStrategy.retryWithDelay(5000);
+ }
+
+ default ProcessFailureStrategy onProcessFailure(Throwable t) {
+ if (t instanceof Error) {
+ return ProcessFailureStrategy.stop();
+ } else {
+ return ProcessFailureStrategy.resume();
+ }
+ }
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorCreator.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorCreator.java
new file mode 100644
index 0000000000..f62bf17d53
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorCreator.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+public interface TbActorCreator {
+
+ TbActorId createActorId();
+
+ TbActor createActor();
+
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorCtx.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorCtx.java
new file mode 100644
index 0000000000..7dd90c3478
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorCtx.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+public interface TbActorCtx {
+
+ TbActorId getSelf();
+
+ TbActorId getParent();
+
+ void tell(TbActorId target, TbActorMsg actorMsg);
+
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorId.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorId.java
new file mode 100644
index 0000000000..91f4363348
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorId.java
@@ -0,0 +1,47 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import org.thingsboard.server.common.data.id.EntityId;
+
+import java.util.Objects;
+
+public class TbActorId {
+
+ private final EntityId entityId;
+
+ public TbActorId(EntityId entityId) {
+ this.entityId = entityId;
+ }
+
+ @Override
+ public String toString() {
+ return entityId.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ TbActorId actorId = (TbActorId) o;
+ return entityId.equals(actorId.entityId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(entityId);
+ }
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java
new file mode 100644
index 0000000000..cbd3f3903f
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorMailbox.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@Slf4j
+@Data
+public final class TbActorMailbox implements TbActorCtx {
+ private static final boolean FREE = false;
+ private static final boolean BUSY = true;
+
+ private static final boolean NOT_READY = false;
+ private static final boolean READY = true;
+
+ private final TbActorSystem system;
+ private final TbActorSystemSettings settings;
+ private final TbActorId selfId;
+ private final TbActorId parentId;
+ private final TbActor actor;
+ private final Dispatcher dispatcher;
+ private final ConcurrentLinkedQueue msgs = new ConcurrentLinkedQueue<>();
+ private final AtomicBoolean busy = new AtomicBoolean(FREE);
+ private final AtomicBoolean ready = new AtomicBoolean(NOT_READY);
+ private final AtomicBoolean destroyInProgress = new AtomicBoolean();
+
+ public void initActor() {
+ dispatcher.getExecutor().execute(() -> tryInit(1));
+ }
+
+ private void tryInit(int attempt) {
+ try {
+ log.debug("[{}] Trying to init actor, attempt: {}", selfId, attempt);
+ if (!destroyInProgress.get()) {
+ actor.init();
+ if (!destroyInProgress.get()) {
+ ready.set(READY);
+ tryProcessQueue(false);
+ }
+ }
+ } catch (Throwable t) {
+ log.debug("[{}] Failed to init actor, attempt: {}", selfId, attempt, t);
+ int attemptIdx = attempt + 1;
+ InitFailureStrategy strategy = actor.onInitFailure(attempt, t);
+ if (strategy.isStop() || (settings.getMaxActorInitAttempts() > 0 && attemptIdx > settings.getMaxActorInitAttempts())) {
+ log.info("[{}] Failed to init actor, attempt {}, going to stop attempts.", selfId, attempt, t);
+ system.stop(selfId);
+ } else if (strategy.getRetryDelay() > 0) {
+ log.info("[{}] Failed to init actor, attempt {}, going to retry in attempts in {}ms", selfId, attempt, strategy.getRetryDelay(), t);
+ system.getScheduler().schedule(() -> dispatcher.getExecutor().execute(() -> tryInit(attemptIdx)), strategy.getRetryDelay(), TimeUnit.MILLISECONDS);
+ } else {
+ log.info("[{}] Failed to init actor, attempt {}, going to retry immediately", selfId, attempt, t);
+ dispatcher.getExecutor().execute(() -> tryInit(attemptIdx));
+ }
+ }
+ }
+
+ public void enqueue(TbActorMsg msg) {
+ msgs.add(msg);
+ tryProcessQueue(true);
+ }
+
+ private void tryProcessQueue(boolean newMsg) {
+ if (ready.get() == READY && (newMsg || !msgs.isEmpty()) && busy.compareAndSet(FREE, BUSY)) {
+ dispatcher.getExecutor().execute(this::processMailbox);
+ } else {
+ log.trace("[{}] MessageBox is busy, new msg: {}", selfId, newMsg);
+ }
+ }
+
+ private void processMailbox() {
+ boolean noMoreElements = false;
+ for (int i = 0; i < settings.getActorThroughput(); i++) {
+ TbActorMsg msg = msgs.poll();
+ if (msg != null) {
+ try {
+ log.debug("[{}] Going to process message: {}", selfId, msg);
+ actor.process(this, msg);
+ } catch (Throwable t) {
+ log.debug("[{}] Failed to process message: {}", selfId, msg, t);
+ ProcessFailureStrategy strategy = actor.onProcessFailure(t);
+ if (strategy.isStop()) {
+ system.stop(selfId);
+ }
+ }
+ } else {
+ noMoreElements = true;
+ break;
+ }
+ }
+ if (noMoreElements) {
+ busy.set(FREE);
+ dispatcher.getExecutor().execute(() -> tryProcessQueue(false));
+ } else {
+ dispatcher.getExecutor().execute(this::processMailbox);
+ }
+ }
+
+ @Override
+ public TbActorId getSelf() {
+ return selfId;
+ }
+
+ @Override
+ public TbActorId getParent() {
+ return parentId;
+ }
+
+ @Override
+ public void tell(TbActorId target, TbActorMsg actorMsg) {
+ system.tell(target, actorMsg);
+ }
+
+ public void destroy() {
+ destroyInProgress.set(true);
+ dispatcher.getExecutor().execute(() -> {
+ try {
+ ready.set(NOT_READY);
+ actor.destroy();
+ } catch (Throwable t) {
+ log.warn("[{}] Failed to destroy actor: {}", selfId, t);
+ }
+ });
+ }
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorNotRegisteredException.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorNotRegisteredException.java
new file mode 100644
index 0000000000..1f30b29c1b
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorNotRegisteredException.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Getter;
+
+public class TbActorNotRegisteredException extends RuntimeException {
+
+ @Getter
+ private TbActorId target;
+
+ public TbActorNotRegisteredException(TbActorId target, String message) {
+ super(message);
+ this.target = target;
+ }
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorSystem.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorSystem.java
new file mode 100644
index 0000000000..f2f08fb06a
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorSystem.java
@@ -0,0 +1,41 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ScheduledExecutorService;
+
+public interface TbActorSystem {
+
+ ScheduledExecutorService getScheduler();
+
+ void createDispatcher(String dispatcherId, ExecutorService executor);
+
+ void destroyDispatcher(String dispatcherId);
+
+ TbActorId createRootActor(String dispatcherId, TbActorCreator creator);
+
+ TbActorId createChildActor(String dispatcherId, TbActorCreator creator, TbActorId parent);
+
+ void tell(TbActorId target, TbActorMsg actorMsg);
+
+ void stop(TbActorId actorId);
+
+ void stop();
+
+}
diff --git a/common/actor/src/main/java/org/thingsboard/server/actors/TbActorSystemSettings.java b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorSystemSettings.java
new file mode 100644
index 0000000000..51798611f2
--- /dev/null
+++ b/common/actor/src/main/java/org/thingsboard/server/actors/TbActorSystemSettings.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Data;
+
+@Data
+public class TbActorSystemSettings {
+
+ private final int actorThroughput;
+ private final int schedulerPoolSize;
+ private final int maxActorInitAttempts;
+
+}
diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java b/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java
new file mode 100644
index 0000000000..2f7a786fe3
--- /dev/null
+++ b/common/actor/src/test/java/org/thingsboard/server/actors/ActorSystemTest.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.thingsboard.server.common.data.id.DeviceId;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+@Slf4j
+@RunWith(MockitoJUnitRunner.class)
+public class ActorSystemTest {
+
+ public static final String ROOT_DISPATCHER = "root-dispatcher";
+ private static final int _1M = 1024 * 1024;
+
+ private TbActorSystem actorSystem;
+ private ExecutorService submitPool;
+
+ @Before
+ public void initActorSystem() {
+ int cores = Runtime.getRuntime().availableProcessors();
+ int parallelism = Math.max(1, cores / 2);
+ TbActorSystemSettings settings = new TbActorSystemSettings(5, parallelism, 42);
+ actorSystem = new DefaultTbActorSystem(settings);
+ submitPool = Executors.newWorkStealingPool(parallelism);
+ actorSystem.createDispatcher(ROOT_DISPATCHER, Executors.newWorkStealingPool(parallelism));
+ }
+
+ @After
+ public void shutdownActorSystem() {
+ actorSystem.stop();
+ submitPool.shutdownNow();
+ }
+
+ @Test
+ public void test10actorsAnd1MMessages() throws InterruptedException {
+ testActorsAndMessages(10, _1M);
+ }
+
+ @Test
+ public void test1MActorsAnd10Messages() throws InterruptedException {
+ testActorsAndMessages(_1M, 10);
+ }
+
+ @Test
+ public void test1KActorsAnd1KMessages() throws InterruptedException {
+ testActorsAndMessages(1000, 1000);
+ }
+
+ @Test
+ public void testNoMessagesAfterDestroy() throws InterruptedException {
+ ActorTestCtx testCtx1 = getActorTestCtx(1);
+ ActorTestCtx testCtx2 = getActorTestCtx(1);
+
+ TbActorId actorId1 = actorSystem.createRootActor(ROOT_DISPATCHER, new SlowInitActor.SlowInitActorCreator(
+ new TbActorId(new DeviceId(UUID.randomUUID())), testCtx1));
+ TbActorId actorId2 = actorSystem.createRootActor(ROOT_DISPATCHER, new SlowInitActor.SlowInitActorCreator(
+ new TbActorId(new DeviceId(UUID.randomUUID())), testCtx2));
+
+ actorSystem.tell(actorId1, new IntTbActorMsg(42));
+ actorSystem.tell(actorId2, new IntTbActorMsg(42));
+ actorSystem.stop(actorId1);
+
+ Assert.assertTrue(testCtx2.getLatch().await(1, TimeUnit.SECONDS));
+ Assert.assertFalse(testCtx1.getLatch().await(2, TimeUnit.SECONDS));
+ }
+
+ @Test
+ public void testOneActorCreated() throws InterruptedException {
+ ActorTestCtx testCtx1 = getActorTestCtx(1);
+ ActorTestCtx testCtx2 = getActorTestCtx(1);
+ TbActorId actorId = new TbActorId(new DeviceId(UUID.randomUUID()));
+ submitPool.submit(() -> actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx1)));
+ submitPool.submit(() -> actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx2)));
+
+ Thread.sleep(1000);
+ actorSystem.tell(actorId, new IntTbActorMsg(42));
+
+ Assert.assertTrue(testCtx1.getLatch().await(3, TimeUnit.SECONDS));
+ Assert.assertFalse(testCtx2.getLatch().await(3, TimeUnit.SECONDS));
+ }
+
+ @Test
+ public void testActorCreatorCalledOnce() throws InterruptedException {
+ ActorTestCtx testCtx = getActorTestCtx(1);
+ TbActorId actorId = new TbActorId(new DeviceId(UUID.randomUUID()));
+ for(int i =0; i < 1000; i++) {
+ submitPool.submit(() -> actorSystem.createRootActor(ROOT_DISPATCHER, new SlowCreateActor.SlowCreateActorCreator(actorId, testCtx)));
+ }
+ Thread.sleep(1000);
+ actorSystem.tell(actorId, new IntTbActorMsg(42));
+
+ Assert.assertTrue(testCtx.getLatch().await(1, TimeUnit.SECONDS));
+ //One for creation and one for message
+ Assert.assertEquals(2, testCtx.getInvocationCount().get());
+ }
+
+
+ public void testActorsAndMessages(int actorsCount, int msgNumber) throws InterruptedException {
+ Random random = new Random();
+ int[] randomIntegers = new int[msgNumber];
+ long sumTmp = 0;
+ for (int i = 0; i < msgNumber; i++) {
+ int tmp = random.nextInt();
+ randomIntegers[i] = tmp;
+ sumTmp += tmp;
+ }
+ long expected = sumTmp;
+
+ List testCtxes = new ArrayList<>();
+
+ List actorIds = new ArrayList<>();
+ for (int actorIdx = 0; actorIdx < actorsCount; actorIdx++) {
+ ActorTestCtx testCtx = getActorTestCtx(msgNumber);
+
+ actorIds.add(actorSystem.createRootActor(ROOT_DISPATCHER, new TestRootActor.TestRootActorCreator(
+ new TbActorId(new DeviceId(UUID.randomUUID())), testCtx)));
+ testCtxes.add(testCtx);
+ }
+
+ long start = System.nanoTime();
+
+ for (int i = 0; i < msgNumber; i++) {
+ int tmp = randomIntegers[i];
+ submitPool.execute(() -> actorIds.forEach(actorId -> actorSystem.tell(actorId, new IntTbActorMsg(tmp))));
+ }
+ log.info("Submitted all messages");
+
+ testCtxes.forEach(ctx -> {
+ try {
+ Assert.assertTrue(ctx.getLatch().await(1, TimeUnit.MINUTES));
+ Assert.assertEquals(expected, ctx.getActual().get());
+ Assert.assertEquals(msgNumber, ctx.getInvocationCount().get());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ });
+
+ long duration = System.nanoTime() - start;
+ log.info("Time spend: {}ns ({} ms)", duration, TimeUnit.NANOSECONDS.toMillis(duration));
+ }
+
+ private ActorTestCtx getActorTestCtx(int i) {
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ AtomicLong actual = new AtomicLong();
+ AtomicInteger invocations = new AtomicInteger();
+ return new ActorTestCtx(countDownLatch, invocations, i, actual);
+ }
+}
diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/ActorTestCtx.java b/common/actor/src/test/java/org/thingsboard/server/actors/ActorTestCtx.java
new file mode 100644
index 0000000000..7e898f51ac
--- /dev/null
+++ b/common/actor/src/test/java/org/thingsboard/server/actors/ActorTestCtx.java
@@ -0,0 +1,31 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Data;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+@Data
+public class ActorTestCtx {
+
+ private final CountDownLatch latch;
+ private final AtomicInteger invocationCount;
+ private final int expectedInvocationCount;
+ private final AtomicLong actual;
+}
diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/IntTbActorMsg.java b/common/actor/src/test/java/org/thingsboard/server/actors/IntTbActorMsg.java
new file mode 100644
index 0000000000..b3591d9642
--- /dev/null
+++ b/common/actor/src/test/java/org/thingsboard/server/actors/IntTbActorMsg.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Getter;
+import org.thingsboard.server.common.msg.MsgType;
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+public class IntTbActorMsg implements TbActorMsg {
+
+ @Getter
+ private final int value;
+
+ public IntTbActorMsg(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public MsgType getMsgType() {
+ return MsgType.QUEUE_TO_RULE_ENGINE_MSG;
+ }
+}
diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/SlowCreateActor.java b/common/actor/src/test/java/org/thingsboard/server/actors/SlowCreateActor.java
new file mode 100644
index 0000000000..af1dfa6b45
--- /dev/null
+++ b/common/actor/src/test/java/org/thingsboard/server/actors/SlowCreateActor.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SlowCreateActor extends TestRootActor {
+
+ public SlowCreateActor(TbActorId actorId, ActorTestCtx testCtx) {
+ super(actorId, testCtx);
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ testCtx.getInvocationCount().incrementAndGet();
+ }
+
+ public static class SlowCreateActorCreator implements TbActorCreator {
+
+ private final TbActorId actorId;
+ private final ActorTestCtx testCtx;
+
+ public SlowCreateActorCreator(TbActorId actorId, ActorTestCtx testCtx) {
+ this.actorId = actorId;
+ this.testCtx = testCtx;
+ }
+
+ @Override
+ public TbActorId createActorId() {
+ return actorId;
+ }
+
+ @Override
+ public TbActor createActor() {
+ return new SlowCreateActor(actorId, testCtx);
+ }
+ }
+}
diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/SlowInitActor.java b/common/actor/src/test/java/org/thingsboard/server/actors/SlowInitActor.java
new file mode 100644
index 0000000000..4cb59be058
--- /dev/null
+++ b/common/actor/src/test/java/org/thingsboard/server/actors/SlowInitActor.java
@@ -0,0 +1,57 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class SlowInitActor extends TestRootActor {
+
+ public SlowInitActor(TbActorId actorId, ActorTestCtx testCtx) {
+ super(actorId, testCtx);
+ }
+
+ @Override
+ public void init() {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ super.init();
+ }
+
+ public static class SlowInitActorCreator implements TbActorCreator {
+
+ private final TbActorId actorId;
+ private final ActorTestCtx testCtx;
+
+ public SlowInitActorCreator(TbActorId actorId, ActorTestCtx testCtx) {
+ this.actorId = actorId;
+ this.testCtx = testCtx;
+ }
+
+ @Override
+ public TbActorId createActorId() {
+ return actorId;
+ }
+
+ @Override
+ public TbActor createActor() {
+ return new SlowInitActor(actorId, testCtx);
+ }
+ }
+}
diff --git a/common/actor/src/test/java/org/thingsboard/server/actors/TestRootActor.java b/common/actor/src/test/java/org/thingsboard/server/actors/TestRootActor.java
new file mode 100644
index 0000000000..54bf044aa8
--- /dev/null
+++ b/common/actor/src/test/java/org/thingsboard/server/actors/TestRootActor.java
@@ -0,0 +1,84 @@
+/**
+ * Copyright © 2016-2020 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.actors;
+
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.msg.TbActorMsg;
+
+@Slf4j
+public class TestRootActor implements TbActor {
+
+ @Getter
+ private final TbActorId actorId;
+ @Getter
+ private final ActorTestCtx testCtx;
+
+ private boolean initialized;
+ private long sum;
+ private int count;
+
+ public TestRootActor(TbActorId actorId, ActorTestCtx testCtx) {
+ this.actorId = actorId;
+ this.testCtx = testCtx;
+ }
+
+ @Override
+ public void init() {
+ initialized = true;
+ }
+
+ @Override
+ public boolean process(TbActorCtx ctx, TbActorMsg msg) {
+ if (initialized) {
+ int value = ((IntTbActorMsg) msg).getValue();
+ sum += value;
+ count += 1;
+ if (count == testCtx.getExpectedInvocationCount()) {
+ testCtx.getActual().set(sum);
+ testCtx.getInvocationCount().addAndGet(count);
+ testCtx.getLatch().countDown();
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+
+ public static class TestRootActorCreator implements TbActorCreator {
+
+ private final TbActorId actorId;
+ private final ActorTestCtx testCtx;
+
+ public TestRootActorCreator(TbActorId actorId, ActorTestCtx testCtx) {
+ this.actorId = actorId;
+ this.testCtx = testCtx;
+ }
+
+ @Override
+ public TbActorId createActorId() {
+ return actorId;
+ }
+
+ @Override
+ public TbActor createActor() {
+ return new TestRootActor(actorId, testCtx);
+ }
+ }
+}
diff --git a/common/actor/src/test/resources/logback.xml b/common/actor/src/test/resources/logback.xml
new file mode 100644
index 0000000000..52f2a77588
--- /dev/null
+++ b/common/actor/src/test/resources/logback.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ %d{ISO8601} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml
index d9692f0a90..4bde73d29b 100644
--- a/common/dao-api/pom.xml
+++ b/common/dao-api/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/data/pom.xml b/common/data/pom.xml
index e529157f47..51fa32c2bb 100644
--- a/common/data/pom.xml
+++ b/common/data/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/message/pom.xml b/common/message/pom.xml
index 54df1085b8..4cc3473dda 100644
--- a/common/message/pom.xml
+++ b/common/message/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/pom.xml b/common/pom.xml
index 4eeebbb8ac..cc2e2a47e2 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
common
@@ -37,6 +37,7 @@
data
util
message
+ actor
queue
transport
dao-api
diff --git a/common/queue/pom.xml b/common/queue/pom.xml
index 8376d30484..eb8cb4da45 100644
--- a/common/queue/pom.xml
+++ b/common/queue/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml
index cdc4978892..d1df792d33 100644
--- a/common/transport/coap/pom.xml
+++ b/common/transport/coap/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.common
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.common.transport
diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml
index 5f715a7a27..a9501d17ca 100644
--- a/common/transport/http/pom.xml
+++ b/common/transport/http/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.common
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.common.transport
diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml
index 3fd09077f4..b14205f2c1 100644
--- a/common/transport/mqtt/pom.xml
+++ b/common/transport/mqtt/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.common
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.common.transport
diff --git a/common/transport/pom.xml b/common/transport/pom.xml
index 9f10a8959d..fd9b183f90 100644
--- a/common/transport/pom.xml
+++ b/common/transport/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
common
org.thingsboard.common
diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml
index a836a98ebb..b2d1d33139 100644
--- a/common/transport/transport-api/pom.xml
+++ b/common/transport/transport-api/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.common
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.common.transport
diff --git a/common/util/pom.xml b/common/util/pom.xml
index d32c56bc1b..49efd021be 100644
--- a/common/util/pom.xml
+++ b/common/util/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
common
org.thingsboard.common
diff --git a/dao/pom.xml b/dao/pom.xml
index 6413a2472a..fc991101ab 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
dao
diff --git a/k8s/README.md b/k8s/README.md
index ce1df8ec05..9d91c8c0e8 100644
--- a/k8s/README.md
+++ b/k8s/README.md
@@ -4,15 +4,15 @@ This folder containing scripts and Kubernetes resources configurations to run Th
## Prerequisites
-ThingsBoard Microservices are running on Kubernetes cluster.
+ThingsBoard Microservices run on the Kubernetes cluster.
You need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster.
-If you do not already have a cluster, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube),
+If you do not have a cluster already, you can create one by using [Minikube](https://kubernetes.io/docs/setup/minikube),
or you can choose any other available [Kubernetes cluster deployment solutions](https://kubernetes.io/docs/setup/pick-right-solution/).
### Enable ingress addon
-By default ingress addon is disable in the Minikube, and available only in cluster providers.
-To enable ingress, please execute next command:
+By default ingress addon is disabled in the Minikube, and available only in cluster providers.
+To enable ingress, please execute the following command:
`
$ minikube addons enable ingress
@@ -21,21 +21,21 @@ $ minikube addons enable ingress
## Installation
Before performing initial installation you can configure the type of database to be used with ThingsBoard and the type of deployment.
-In order to set database type change the value of `DATABASE` variable in `.env` file to one of the following:
+To set database type change the value of `DATABASE` variable in `.env` file to one of the following:
- `postgres` - use PostgreSQL database;
- `hybrid` - use PostgreSQL for entities database and Cassandra for timeseries database;
**NOTE**: According to the database type corresponding kubernetes resources will be deployed (see `postgres.yml`, `cassandra.yml` for details).
-In order to set deployment type change the value of `DEPLOYMENT_TYPE` variable in `.env` file to one of the following:
+To set deployment type change the value of `DEPLOYMENT_TYPE` variable in `.env` file to one of the following:
-- `basic` - start up with single instance of Zookeeper, Kafka and Redis;
-- `high-availability` - start up with Zookeeper, Kafka and Redis in cluster modes;
+- `basic` - startup with a single instance of Zookeeper, Kafka and Redis;
+- `high-availability` - startup with Zookeeper, Kafka, and Redis in cluster modes;
-**NOTE**: According to the deployment type corresponding kubernetes resources will be deployed (see content of the directories `./basic` and `./high-availability` for details).
+**NOTE**: According to the deployment type corresponding kubernetes resources will be deployed (see the content of the directories `./basic` and `./high-availability` for details).
-Execute the following command to run installation:
+Execute the following command to run the installation:
`
$ ./k8s-install-tb.sh --loadDemo
@@ -47,7 +47,7 @@ Where:
## Running
-Execute the following command to deploy thirdparty resources:
+Execute the following command to deploy third-party resources:
`
$ ./k8s-deploy-thirdparty.sh
@@ -61,8 +61,8 @@ Execute the following command to deploy resources:
$ ./k8s-deploy-resources.sh
`
-After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in you browser (for ex. `http://192.168.99.101`).
-You should see ThingsBoard login page.
+After a while when all resources will be successfully started you can open `http://{your-cluster-ip}` in your browser (for ex. `http://192.168.99.101`).
+You should see the ThingsBoard login page.
Use the following default credentials:
@@ -73,16 +73,16 @@ If you installed DataBase with demo data (using `--loadDemo` flag) you can also
- **Tenant Administrator**: tenant@thingsboard.org / tenant
- **Customer User**: customer@thingsboard.org / customer
-In case of any issues you can examine service logs for errors.
+In case of any issues, you can examine service logs for errors.
For example to see ThingsBoard node logs execute the following commands:
-1) Get list of the running tb-node pods:
+1) Get the list of the running tb-node pods:
`
$ kubectl get pods -l app=tb-node
`
-2) Fetch logs of tb-node pod:
+2) Fetch logs of the tb-node pod:
`
$ kubectl logs -f [tb-node-pod-name]
@@ -103,7 +103,7 @@ Execute the following command to delete all ThingsBoard microservices:
$ ./k8s-delete-resources.sh
`
-Execute the following command to delete all thirdparty microservices:
+Execute the following command to delete all third-party microservices:
`
$ ./k8s-delete-thirdparty.sh
diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml
index f60afff08d..73aa03968d 100644
--- a/msa/black-box-tests/pom.xml
+++ b/msa/black-box-tests/pom.xml
@@ -21,7 +21,7 @@
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
msa
org.thingsboard.msa
diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml
index 16a0bb7570..a3d0bb77cc 100644
--- a/msa/js-executor/pom.xml
+++ b/msa/js-executor/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
msa
org.thingsboard.msa
diff --git a/msa/pom.xml b/msa/pom.xml
index e37ecf0af8..68d7ca52e9 100644
--- a/msa/pom.xml
+++ b/msa/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
msa
diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml
index d1a67a891a..10a3c9533b 100644
--- a/msa/tb-node/pom.xml
+++ b/msa/tb-node/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
msa
org.thingsboard.msa
diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml
index 3a48db9ae3..8dcbaebec2 100644
--- a/msa/tb/pom.xml
+++ b/msa/tb/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
msa
org.thingsboard.msa
diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml
index c611578819..efcf2f8723 100644
--- a/msa/transport/coap/pom.xml
+++ b/msa/transport/coap/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.msa
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.msa.transport
diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml
index 561106a50e..7b6a5bda10 100644
--- a/msa/transport/http/pom.xml
+++ b/msa/transport/http/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.msa
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.msa.transport
diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml
index 9412dd422e..e113402b77 100644
--- a/msa/transport/mqtt/pom.xml
+++ b/msa/transport/mqtt/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard.msa
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.msa.transport
diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml
index cc2b196f2c..1137506fa0 100644
--- a/msa/transport/pom.xml
+++ b/msa/transport/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
msa
org.thingsboard.msa
diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml
index 119ff7b24e..e12e26c551 100644
--- a/msa/web-ui/pom.xml
+++ b/msa/web-ui/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
msa
org.thingsboard.msa
diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml
index 00f5a9ef4f..b3de2f5fd7 100644
--- a/netty-mqtt/pom.xml
+++ b/netty-mqtt/pom.xml
@@ -19,11 +19,11 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
netty-mqtt
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
jar
Netty MQTT Client
diff --git a/pom.xml b/pom.xml
index 2ae25dbfb9..2b4471f493 100755
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
pom
Thingsboard
diff --git a/rest-client/pom.xml b/rest-client/pom.xml
index b2a9ecd668..331a5c5926 100644
--- a/rest-client/pom.xml
+++ b/rest-client/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
rest-client
diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml
index c7a1e8eb79..410c339153 100644
--- a/rule-engine/pom.xml
+++ b/rule-engine/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
rule-engine
diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml
index 74b546b930..5acf0332b9 100644
--- a/rule-engine/rule-engine-api/pom.xml
+++ b/rule-engine/rule-engine-api/pom.xml
@@ -22,7 +22,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
rule-engine
org.thingsboard.rule-engine
diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml
index 11b1860022..621dcaa1da 100644
--- a/rule-engine/rule-engine-components/pom.xml
+++ b/rule-engine/rule-engine-components/pom.xml
@@ -22,7 +22,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
rule-engine
org.thingsboard.rule-engine
diff --git a/tools/pom.xml b/tools/pom.xml
index 464610edfd..264221797e 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
tools
diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml
index a4f24ed547..776a4d938d 100644
--- a/transport/coap/pom.xml
+++ b/transport/coap/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.transport
diff --git a/transport/http/pom.xml b/transport/http/pom.xml
index 86e952822a..f769f0185e 100644
--- a/transport/http/pom.xml
+++ b/transport/http/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.transport
diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml
index 5caea325da..4975694c34 100644
--- a/transport/mqtt/pom.xml
+++ b/transport/mqtt/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
transport
org.thingsboard.transport
diff --git a/transport/pom.xml b/transport/pom.xml
index 20d4f188b2..ed4ca7b44c 100644
--- a/transport/pom.xml
+++ b/transport/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
transport
diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml
index fb403fba01..8a0e60aac4 100644
--- a/ui-ngx/pom.xml
+++ b/ui-ngx/pom.xml
@@ -20,7 +20,7 @@
4.0.0
org.thingsboard
- 2.5.2-SNAPSHOT
+ 3.0.1-SNAPSHOT
thingsboard
org.thingsboard
diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss
index a23f8f3626..afb804612a 100644
--- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss
+++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.scss
@@ -86,6 +86,11 @@ tb-widget-editor {
height: 100%;
}
}
+
+ .container{
+ width: 100%;
+ height: 100%;
+ }
}
.tb-split-vertical {