21 changed files with 434 additions and 51 deletions
@ -0,0 +1,49 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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.service.cf; |
||||
|
|
||||
|
import lombok.Builder; |
||||
|
import lombok.Data; |
||||
|
import org.thingsboard.server.common.data.id.CalculatedFieldId; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.util.CollectionsUtil; |
||||
|
import org.thingsboard.server.common.msg.TbMsg; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
@Builder |
||||
|
public final class PropagationCalculatedFieldResult implements CalculatedFieldResult { |
||||
|
|
||||
|
private final List<EntityId> propagationEntityIds; |
||||
|
private final TelemetryCalculatedFieldResult result; |
||||
|
|
||||
|
@Override |
||||
|
public TbMsg toTbMsg(EntityId entityId, List<CalculatedFieldId> cfIds) { |
||||
|
return result.toTbMsg(entityId, cfIds); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String stringValue() { |
||||
|
return result.stringValue(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isEmpty() { |
||||
|
return CollectionsUtil.isEmpty(propagationEntityIds) || result.isEmpty(); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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.service.cf.ctx.state.propagation; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.thingsboard.script.api.tbel.TbelCfArg; |
||||
|
import org.thingsboard.script.api.tbel.TbelCfPropagationArg; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.common.data.util.CollectionsUtil; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntryType; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
public class PropagationArgumentEntry implements ArgumentEntry { |
||||
|
|
||||
|
private List<EntityId> propagationEntityIds; |
||||
|
|
||||
|
private boolean forceResetPrevious; |
||||
|
|
||||
|
public PropagationArgumentEntry(List<EntityId> propagationEntityIds) { |
||||
|
this.propagationEntityIds = propagationEntityIds; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ArgumentEntryType getType() { |
||||
|
return ArgumentEntryType.PROPAGATION; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Object getValue() { |
||||
|
return propagationEntityIds; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean updateEntry(ArgumentEntry entry) { |
||||
|
if (!(entry instanceof PropagationArgumentEntry propagationArgumentEntry)) { |
||||
|
throw new IllegalArgumentException("Unsupported argument entry type for propagation argument entry: " + entry.getType()); |
||||
|
} |
||||
|
if (propagationArgumentEntry.isEmpty()) { |
||||
|
propagationEntityIds.clear(); |
||||
|
} else { |
||||
|
propagationEntityIds = propagationArgumentEntry.getPropagationEntityIds(); |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isEmpty() { |
||||
|
return CollectionsUtil.isEmpty(propagationEntityIds); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public TbelCfArg toTbelCfArg() { |
||||
|
return new TbelCfPropagationArg(propagationEntityIds); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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.service.cf.ctx.state.propagation; |
||||
|
|
||||
|
import com.google.common.util.concurrent.Futures; |
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import com.google.common.util.concurrent.MoreExecutors; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedFieldType; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.service.cf.CalculatedFieldResult; |
||||
|
import org.thingsboard.server.service.cf.PropagationCalculatedFieldResult; |
||||
|
import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.ScriptCalculatedFieldState; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
import static org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration.PROPAGATION_CONFIG_ARGUMENT; |
||||
|
|
||||
|
public class PropagationCalculatedFieldState extends ScriptCalculatedFieldState { |
||||
|
|
||||
|
public PropagationCalculatedFieldState(EntityId entityId) { |
||||
|
super(entityId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public CalculatedFieldType getType() { |
||||
|
return CalculatedFieldType.PROPAGATION; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<CalculatedFieldResult> performCalculation(Map<String, ArgumentEntry> updatedArgs, CalculatedFieldCtx ctx) { |
||||
|
ArgumentEntry argumentEntry = arguments.get(PROPAGATION_CONFIG_ARGUMENT); |
||||
|
if (!(argumentEntry instanceof PropagationArgumentEntry propagationArgumentEntry) || propagationArgumentEntry.isEmpty()) { |
||||
|
return Futures.immediateFuture(PropagationCalculatedFieldResult.builder().build()); |
||||
|
} |
||||
|
return Futures.transform(super.performCalculation(updatedArgs, ctx), telemetryCfResult -> |
||||
|
PropagationCalculatedFieldResult.builder() |
||||
|
.propagationEntityIds(propagationArgumentEntry.getPropagationEntityIds()) |
||||
|
.result((TelemetryCalculatedFieldResult) telemetryCfResult) |
||||
|
.build(), |
||||
|
MoreExecutors.directExecutor()); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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.common.data.cf.configuration; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
import lombok.EqualsAndHashCode; |
||||
|
import org.thingsboard.server.common.data.StringUtils; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedFieldType; |
||||
|
import org.thingsboard.server.common.data.relation.EntitySearchDirection; |
||||
|
import org.thingsboard.server.common.data.relation.RelationPathLevel; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
@Data |
||||
|
@EqualsAndHashCode(callSuper = true) |
||||
|
public class PropagationCalculatedFieldConfiguration extends BaseCalculatedFieldConfiguration { |
||||
|
|
||||
|
public static final String PROPAGATION_CONFIG_ARGUMENT = "propagationCtx"; |
||||
|
|
||||
|
private EntitySearchDirection direction; |
||||
|
private String relationType; |
||||
|
|
||||
|
@Override |
||||
|
public CalculatedFieldType getType() { |
||||
|
return CalculatedFieldType.PROPAGATION; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void validate() { |
||||
|
baseCalculatedFieldRestriction(); |
||||
|
propagationRestriction(); |
||||
|
if (direction == null) { |
||||
|
throw new IllegalArgumentException("Propagation calculated field direction must be specified!"); |
||||
|
} |
||||
|
if (StringUtils.isBlank(relationType)) { |
||||
|
throw new IllegalArgumentException("Propagation calculated field relation type must be specified!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public Argument toPropagationArgument() { |
||||
|
var refDynamicSourceConfiguration = new RelationPathQueryDynamicSourceConfiguration(); |
||||
|
refDynamicSourceConfiguration.setLevels(List.of(new RelationPathLevel(direction, relationType))); |
||||
|
var propagationArgument = new Argument(); |
||||
|
propagationArgument.setRefDynamicSourceConfiguration(refDynamicSourceConfiguration); |
||||
|
return propagationArgument; |
||||
|
} |
||||
|
|
||||
|
private void propagationRestriction() { |
||||
|
if (arguments.entrySet().stream().anyMatch(entry -> entry.getKey().equals(PROPAGATION_CONFIG_ARGUMENT))) { |
||||
|
throw new IllegalArgumentException("Argument name '" + PROPAGATION_CONFIG_ARGUMENT + "' is reserved and cannot be used."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 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.script.api.tbel; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonCreator; |
||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class TbelCfPropagationArg implements TbelCfArg { |
||||
|
|
||||
|
private final Object value; |
||||
|
|
||||
|
@JsonCreator |
||||
|
public TbelCfPropagationArg(@JsonProperty("value") Object value) { |
||||
|
this.value = value; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public String getType() { |
||||
|
return "PROPAGATION_CF_ARGUMENT_VALUE"; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public long memorySize() { |
||||
|
return OBJ_SIZE; |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue