Refactor saveAndNotify with returned future
This commit is contained in:
		
							parent
							
								
									e8cf3179c5
								
							
						
					
					
						commit
						3db304e021
					
				@ -19,7 +19,6 @@ import com.google.common.util.concurrent.FutureCallback;
 | 
			
		||||
import com.google.common.util.concurrent.Futures;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import com.google.common.util.concurrent.MoreExecutors;
 | 
			
		||||
import com.google.common.util.concurrent.SettableFuture;
 | 
			
		||||
import jakarta.annotation.Nullable;
 | 
			
		||||
import jakarta.annotation.PostConstruct;
 | 
			
		||||
import jakarta.annotation.PreDestroy;
 | 
			
		||||
@ -127,14 +126,6 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Void> saveAndNotify(TimeseriesSaveRequest request) {
 | 
			
		||||
        SettableFuture<Void> future = SettableFuture.create();
 | 
			
		||||
        request.setCallback(new VoidFutureCallback(future));
 | 
			
		||||
        save(request);
 | 
			
		||||
        return future;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Integer> saveInternal(TimeseriesSaveRequest request) {
 | 
			
		||||
        TenantId tenantId = request.getTenantId();
 | 
			
		||||
@ -242,14 +233,6 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
 | 
			
		||||
        addWsCallback(deleteFuture, list -> onTimeSeriesDelete(tenantId, entityId, keys, list));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public ListenableFuture<Void> saveAttrAndNotify(AttributesSaveRequest request) {
 | 
			
		||||
        SettableFuture<Void> future = SettableFuture.create();
 | 
			
		||||
        request.setCallback(new VoidFutureCallback(future));
 | 
			
		||||
        save(request);
 | 
			
		||||
        return future;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addEntityViewCallback(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts) {
 | 
			
		||||
        if (EntityType.DEVICE.equals(entityId.getEntityType()) || EntityType.ASSET.equals(entityId.getEntityType())) {
 | 
			
		||||
            Futures.addCallback(this.tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId),
 | 
			
		||||
@ -397,23 +380,4 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class VoidFutureCallback implements FutureCallback<Void> {
 | 
			
		||||
        private final SettableFuture<Void> future;
 | 
			
		||||
 | 
			
		||||
        public VoidFutureCallback(SettableFuture<Void> future) {
 | 
			
		||||
            this.future = future;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onSuccess(Void result) {
 | 
			
		||||
            future.set(null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public void onFailure(Throwable t) {
 | 
			
		||||
            future.setException(t);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,10 @@
 | 
			
		||||
package org.thingsboard.rule.engine.api;
 | 
			
		||||
 | 
			
		||||
import com.google.common.util.concurrent.FutureCallback;
 | 
			
		||||
import com.google.common.util.concurrent.SettableFuture;
 | 
			
		||||
import lombok.AccessLevel;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
import lombok.ToString;
 | 
			
		||||
import org.thingsboard.server.common.data.AttributeScope;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
@ -38,10 +38,9 @@ public class AttributesSaveRequest {
 | 
			
		||||
    private final TenantId tenantId;
 | 
			
		||||
    private final EntityId entityId;
 | 
			
		||||
    private final AttributeScope scope;
 | 
			
		||||
    private final List<AttributeKvEntry> entries; // todo: rename to attributes? same with timeseries
 | 
			
		||||
    private final List<AttributeKvEntry> entries;
 | 
			
		||||
    private final boolean notifyDevice;
 | 
			
		||||
    @Setter
 | 
			
		||||
    private FutureCallback<Void> callback;
 | 
			
		||||
    private final FutureCallback<Void> callback;
 | 
			
		||||
 | 
			
		||||
    public static Builder builder() {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
@ -106,6 +105,20 @@ public class AttributesSaveRequest {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder future(SettableFuture<Void> future) {
 | 
			
		||||
            return callback(new FutureCallback<>() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onSuccess(Void result) {
 | 
			
		||||
                    future.set(result);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onFailure(Throwable t) {
 | 
			
		||||
                    future.setException(t);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public AttributesSaveRequest build() {
 | 
			
		||||
            return new AttributesSaveRequest(tenantId, entityId, scope, entries, notifyDevice, callback);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,6 @@
 | 
			
		||||
package org.thingsboard.rule.engine.api;
 | 
			
		||||
 | 
			
		||||
import com.google.common.util.concurrent.FutureCallback;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import org.thingsboard.server.common.data.AttributeScope;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
@ -33,14 +32,10 @@ public interface RuleEngineTelemetryService {
 | 
			
		||||
 | 
			
		||||
    void save(TimeseriesSaveRequest request);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Void> saveAndNotify(TimeseriesSaveRequest request);
 | 
			
		||||
 | 
			
		||||
    void save(AttributesSaveRequest request);
 | 
			
		||||
 | 
			
		||||
    void saveLatestAndNotify(TenantId tenantId, EntityId entityId, List<TsKvEntry> ts, FutureCallback<Void> callback);
 | 
			
		||||
 | 
			
		||||
    ListenableFuture<Void> saveAttrAndNotify(AttributesSaveRequest request);
 | 
			
		||||
 | 
			
		||||
    void deleteAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List<String> keys, FutureCallback<Void> callback);
 | 
			
		||||
 | 
			
		||||
    void deleteAndNotify(TenantId tenantId, EntityId entityId, AttributeScope scope, List<String> keys, boolean notifyDevice, FutureCallback<Void> callback);
 | 
			
		||||
 | 
			
		||||
@ -16,10 +16,10 @@
 | 
			
		||||
package org.thingsboard.rule.engine.api;
 | 
			
		||||
 | 
			
		||||
import com.google.common.util.concurrent.FutureCallback;
 | 
			
		||||
import com.google.common.util.concurrent.SettableFuture;
 | 
			
		||||
import lombok.AccessLevel;
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import lombok.Setter;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
@ -39,8 +39,7 @@ public class TimeseriesSaveRequest {
 | 
			
		||||
    private final List<TsKvEntry> entries;
 | 
			
		||||
    private final long ttl;
 | 
			
		||||
    private final boolean saveLatest;
 | 
			
		||||
    @Setter
 | 
			
		||||
    private FutureCallback<Void> callback;
 | 
			
		||||
    private final FutureCallback<Void> callback;
 | 
			
		||||
 | 
			
		||||
    public static Builder builder() {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
@ -101,6 +100,20 @@ public class TimeseriesSaveRequest {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder future(SettableFuture<Void> future) {
 | 
			
		||||
            return callback(new FutureCallback<>() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onSuccess(Void result) {
 | 
			
		||||
                    future.set(result);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                public void onFailure(Throwable t) {
 | 
			
		||||
                    future.setException(t);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public TimeseriesSaveRequest build() {
 | 
			
		||||
            return new TimeseriesSaveRequest(tenantId, customerId, entityId, entries, ttl, saveLatest, callback);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
 | 
			
		||||
import com.google.common.util.concurrent.Futures;
 | 
			
		||||
import com.google.common.util.concurrent.ListenableFuture;
 | 
			
		||||
import com.google.common.util.concurrent.MoreExecutors;
 | 
			
		||||
import com.google.common.util.concurrent.SettableFuture;
 | 
			
		||||
import lombok.extern.slf4j.Slf4j;
 | 
			
		||||
import net.objecthunter.exp4j.Expression;
 | 
			
		||||
import net.objecthunter.exp4j.ExpressionBuilder;
 | 
			
		||||
@ -143,11 +144,14 @@ public class TbMathNode implements TbNode {
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Void> saveTimeSeries(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) {
 | 
			
		||||
        final BasicTsKvEntry basicTsKvEntry = new BasicTsKvEntry(System.currentTimeMillis(), new DoubleDataEntry(mathResultDef.getKey(), result));
 | 
			
		||||
        return ctx.getTelemetryService().saveAndNotify(TimeseriesSaveRequest.builder()
 | 
			
		||||
        SettableFuture<Void> future = SettableFuture.create();
 | 
			
		||||
        ctx.getTelemetryService().save(TimeseriesSaveRequest.builder()
 | 
			
		||||
                .tenantId(ctx.getTenantId())
 | 
			
		||||
                .entityId(msg.getOriginator())
 | 
			
		||||
                .entry(basicTsKvEntry)
 | 
			
		||||
                .future(future)
 | 
			
		||||
                .build());
 | 
			
		||||
        return future;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ListenableFuture<Void> saveAttribute(TbContext ctx, TbMsg msg, double result, TbMathResult mathResultDef) {
 | 
			
		||||
@ -160,12 +164,15 @@ public class TbMathNode implements TbNode {
 | 
			
		||||
            var value = toDoubleValue(mathResultDef, result);
 | 
			
		||||
            kvEntry = new DoubleDataEntry(mathResultDef.getKey(), value);
 | 
			
		||||
        }
 | 
			
		||||
        return ctx.getTelemetryService().saveAttrAndNotify(AttributesSaveRequest.builder()
 | 
			
		||||
        SettableFuture<Void> future = SettableFuture.create();
 | 
			
		||||
        ctx.getTelemetryService().save(AttributesSaveRequest.builder()
 | 
			
		||||
                .tenantId(ctx.getTenantId())
 | 
			
		||||
                .entityId(msg.getOriginator())
 | 
			
		||||
                .scope(attributeScope)
 | 
			
		||||
                .entry(kvEntry)
 | 
			
		||||
                .future(future)
 | 
			
		||||
                .build());
 | 
			
		||||
        return future;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean isIntegerResult(TbMathResult mathResultDef, TbRuleNodeMathFunctionType function) {
 | 
			
		||||
 | 
			
		||||
@ -30,14 +30,17 @@ import org.junit.jupiter.params.provider.MethodSource;
 | 
			
		||||
import org.mockito.ArgumentCaptor;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.Mockito;
 | 
			
		||||
import org.mockito.ThrowingConsumer;
 | 
			
		||||
import org.mockito.junit.jupiter.MockitoExtension;
 | 
			
		||||
import org.mockito.verification.Timeout;
 | 
			
		||||
import org.thingsboard.common.util.AbstractListeningExecutor;
 | 
			
		||||
import org.thingsboard.common.util.JacksonUtil;
 | 
			
		||||
import org.thingsboard.rule.engine.api.AttributesSaveRequest;
 | 
			
		||||
import org.thingsboard.rule.engine.api.RuleEngineTelemetryService;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbContext;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNodeConfiguration;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TbNodeException;
 | 
			
		||||
import org.thingsboard.rule.engine.api.TimeseriesSaveRequest;
 | 
			
		||||
import org.thingsboard.server.common.data.AttributeScope;
 | 
			
		||||
import org.thingsboard.server.common.data.DataConstants;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceId;
 | 
			
		||||
@ -76,6 +79,7 @@ import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.BDDMockito.willAnswer;
 | 
			
		||||
import static org.mockito.BDDMockito.willReturn;
 | 
			
		||||
import static org.mockito.BDDMockito.willThrow;
 | 
			
		||||
import static org.mockito.Mockito.doAnswer;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.never;
 | 
			
		||||
import static org.mockito.Mockito.spy;
 | 
			
		||||
@ -433,15 +437,17 @@ public class TbMathNodeTest {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString());
 | 
			
		||||
 | 
			
		||||
        when(telemetryService.saveAttrAndNotify(any()))
 | 
			
		||||
                .thenReturn(Futures.immediateFuture(null));
 | 
			
		||||
        doAnswer(invocation -> {
 | 
			
		||||
            AttributesSaveRequest request = invocation.getArgument(0);
 | 
			
		||||
            request.getCallback().onSuccess(null);
 | 
			
		||||
            return null;
 | 
			
		||||
        }).when(telemetryService).save(any(AttributesSaveRequest.class));
 | 
			
		||||
 | 
			
		||||
        node.onMsg(ctx, msg);
 | 
			
		||||
 | 
			
		||||
        ArgumentCaptor<TbMsg> msgCaptor = ArgumentCaptor.forClass(TbMsg.class);
 | 
			
		||||
        verify(ctx, timeout(TIMEOUT)).tellSuccess(msgCaptor.capture());
 | 
			
		||||
        verify(telemetryService, times(1)).saveAttrAndNotify(assertArg(request -> {
 | 
			
		||||
        verify(telemetryService, times(1)).save(assertArg((ThrowingConsumer<AttributesSaveRequest>) request -> {
 | 
			
		||||
            assertThat(request.getEntries()).singleElement().extracting(KvEntry::getValue).isInstanceOf(Double.class);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
@ -461,13 +467,17 @@ public class TbMathNodeTest {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString());
 | 
			
		||||
        when(telemetryService.saveAndNotify(any())).thenReturn(Futures.immediateFuture(null));
 | 
			
		||||
        doAnswer(invocation -> {
 | 
			
		||||
            TimeseriesSaveRequest request = invocation.getArgument(0);
 | 
			
		||||
            request.getCallback().onSuccess(null);
 | 
			
		||||
            return null;
 | 
			
		||||
        }).when(telemetryService).save(any(TimeseriesSaveRequest.class));
 | 
			
		||||
 | 
			
		||||
        node.onMsg(ctx, msg);
 | 
			
		||||
 | 
			
		||||
        ArgumentCaptor<TbMsg> msgCaptor = ArgumentCaptor.forClass(TbMsg.class);
 | 
			
		||||
        verify(ctx, timeout(TIMEOUT)).tellSuccess(msgCaptor.capture());
 | 
			
		||||
        verify(telemetryService, times(1)).saveAndNotify(assertArg(request -> {
 | 
			
		||||
        verify(telemetryService, times(1)).save(assertArg((ThrowingConsumer<TimeseriesSaveRequest>) request -> {
 | 
			
		||||
            assertThat(request.getEntries()).size().isOne();
 | 
			
		||||
            assertThat(request.isSaveLatest()).isTrue();
 | 
			
		||||
        }));
 | 
			
		||||
@ -488,13 +498,17 @@ public class TbMathNodeTest {
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, originator, TbMsgMetaData.EMPTY, JacksonUtil.newObjectNode().put("a", 5).toString());
 | 
			
		||||
        when(telemetryService.saveAndNotify(any())).thenReturn(Futures.immediateFuture(null));
 | 
			
		||||
        doAnswer(invocation -> {
 | 
			
		||||
            TimeseriesSaveRequest request = invocation.getArgument(0);
 | 
			
		||||
            request.getCallback().onSuccess(null);
 | 
			
		||||
            return null;
 | 
			
		||||
        }).when(telemetryService).save(any(TimeseriesSaveRequest.class));
 | 
			
		||||
 | 
			
		||||
        node.onMsg(ctx, msg);
 | 
			
		||||
 | 
			
		||||
        ArgumentCaptor<TbMsg> msgCaptor = ArgumentCaptor.forClass(TbMsg.class);
 | 
			
		||||
        verify(ctx, timeout(TIMEOUT)).tellSuccess(msgCaptor.capture());
 | 
			
		||||
        verify(telemetryService, times(1)).saveAndNotify(assertArg(request -> {
 | 
			
		||||
        verify(telemetryService, times(1)).save(assertArg((ThrowingConsumer<TimeseriesSaveRequest>) request -> {
 | 
			
		||||
            assertThat(request.getEntries()).size().isOne();
 | 
			
		||||
            assertThat(request.isSaveLatest()).isTrue();
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user