38 changed files with 1262 additions and 122 deletions
@ -0,0 +1,59 @@ |
|||
/** |
|||
* 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.service.subscription; |
|||
|
|||
import lombok.Data; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.query.AbstractDataQuery; |
|||
import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; |
|||
import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; |
|||
|
|||
@Slf4j |
|||
@Data |
|||
public abstract class TbAbstractDataSubCtx<T extends AbstractDataQuery> { |
|||
|
|||
protected final String serviceId; |
|||
protected final TelemetryWebSocketService wsService; |
|||
protected final TelemetryWebSocketSessionRef sessionRef; |
|||
protected final int cmdId; |
|||
@Getter |
|||
@Setter |
|||
protected T query; |
|||
|
|||
public TbAbstractDataSubCtx(String serviceId, TelemetryWebSocketService wsService, TelemetryWebSocketSessionRef sessionRef, int cmdId) { |
|||
this.serviceId = serviceId; |
|||
this.wsService = wsService; |
|||
this.sessionRef = sessionRef; |
|||
this.cmdId = cmdId; |
|||
} |
|||
|
|||
public String getSessionId() { |
|||
return sessionRef.getSessionId(); |
|||
} |
|||
|
|||
public TenantId getTenantId() { |
|||
return sessionRef.getSecurityCtx().getTenantId(); |
|||
} |
|||
|
|||
public CustomerId getCustomerId() { |
|||
return sessionRef.getSecurityCtx().getCustomerId(); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
/** |
|||
* 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.service.subscription; |
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.AlarmData; |
|||
import org.thingsboard.server.common.data.query.AlarmDataQuery; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.service.telemetry.TelemetryWebSocketService; |
|||
import org.thingsboard.server.service.telemetry.TelemetryWebSocketSessionRef; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.LinkedHashMap; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public class TbAlarmDataSubCtx extends TbAbstractDataSubCtx<AlarmDataQuery> { |
|||
|
|||
@Getter |
|||
@Setter |
|||
private final LinkedHashMap<EntityId, EntityData> entitiesMap; |
|||
@Getter |
|||
@Setter |
|||
private boolean tooManyEntities; |
|||
|
|||
public TbAlarmDataSubCtx(String serviceId, TelemetryWebSocketService wsService, TelemetryWebSocketSessionRef sessionRef, int cmdId) { |
|||
super(serviceId, wsService, sessionRef, cmdId); |
|||
this.entitiesMap = new LinkedHashMap<>(); |
|||
} |
|||
|
|||
public void setEntitiesData(PageData<EntityData> entitiesData) { |
|||
entitiesMap.clear(); |
|||
tooManyEntities = entitiesData.hasNext(); |
|||
for (EntityData entityData : entitiesData.getData()) { |
|||
entitiesMap.put(entityData.getEntityId(), entityData); |
|||
} |
|||
} |
|||
|
|||
public Collection<EntityId> getOrderedEntityIds() { |
|||
return entitiesMap.keySet(); |
|||
} |
|||
|
|||
public void setAlarmsData(PageData<AlarmData> alarms) { |
|||
// TODO: implement
|
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
/** |
|||
* 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.service.telemetry.cmd.v2; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.query.AlarmDataQuery; |
|||
|
|||
public class AlarmDataCmd extends DataCmd { |
|||
|
|||
@Getter |
|||
private final AlarmDataQuery query; |
|||
|
|||
@JsonCreator |
|||
public AlarmDataCmd(@JsonProperty("cmdId") int cmdId, @JsonProperty("query") AlarmDataQuery query) { |
|||
super(cmdId); |
|||
this.query = query; |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* 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.service.telemetry.cmd.v2; |
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class AlarmDataUnsubscribeCmd { |
|||
|
|||
private final int cmdId; |
|||
|
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
/** |
|||
* 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.service.telemetry.cmd.v2; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import lombok.NoArgsConstructor; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.AlarmData; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
public class AlarmDataUpdate extends DataUpdate<AlarmData> { |
|||
|
|||
public AlarmDataUpdate(int cmdId, PageData<AlarmData> data, List<AlarmData> update) { |
|||
super(cmdId, data, update, SubscriptionErrorCode.NO_ERROR.getCode(), null); |
|||
} |
|||
|
|||
public AlarmDataUpdate(int cmdId, int errorCode, String errorMsg) { |
|||
super(cmdId, null, null, errorCode, errorMsg); |
|||
} |
|||
|
|||
@JsonCreator |
|||
public AlarmDataUpdate(@JsonProperty("cmdId") int cmdId, |
|||
@JsonProperty("data") PageData<AlarmData> data, |
|||
@JsonProperty("update") List<AlarmData> update, |
|||
@JsonProperty("errorCode") int errorCode, |
|||
@JsonProperty("errorMsg") String errorMsg) { |
|||
super(cmdId, data, update, errorCode, errorMsg); |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* 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.service.telemetry.cmd.v2; |
|||
|
|||
import lombok.Data; |
|||
import lombok.Getter; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
@Data |
|||
public class DataCmd { |
|||
|
|||
@Getter |
|||
private final int cmdId; |
|||
|
|||
public DataCmd(int cmdId) { |
|||
this.cmdId = cmdId; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
/** |
|||
* 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.service.telemetry.cmd.v2; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.service.telemetry.sub.SubscriptionErrorCode; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public abstract class DataUpdate<T> { |
|||
|
|||
private final int cmdId; |
|||
private final PageData<T> data; |
|||
private final List<T> update; |
|||
private final int errorCode; |
|||
private final String errorMsg; |
|||
|
|||
public DataUpdate(int cmdId, PageData<T> data, List<T> update) { |
|||
this(cmdId, data, update, SubscriptionErrorCode.NO_ERROR.getCode(), null); |
|||
} |
|||
|
|||
public DataUpdate(int cmdId, int errorCode, String errorMsg) { |
|||
this(cmdId, null, null, errorCode, errorMsg); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
/** |
|||
* 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.common.data.query; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import lombok.Getter; |
|||
import lombok.ToString; |
|||
|
|||
import java.util.List; |
|||
|
|||
@ToString |
|||
public abstract class AbstractDataQuery<T extends EntityDataPageLink> extends EntityCountQuery { |
|||
|
|||
@Getter |
|||
protected T pageLink; |
|||
@Getter |
|||
protected List<EntityKey> entityFields; |
|||
@Getter |
|||
protected List<EntityKey> latestValues; |
|||
@Getter |
|||
protected List<KeyFilter> keyFilters; |
|||
|
|||
public AbstractDataQuery() { |
|||
super(); |
|||
} |
|||
|
|||
public AbstractDataQuery(EntityFilter entityFilter) { |
|||
super(entityFilter); |
|||
} |
|||
|
|||
public AbstractDataQuery(EntityFilter entityFilter, |
|||
T pageLink, |
|||
List<EntityKey> entityFields, |
|||
List<EntityKey> latestValues, |
|||
List<KeyFilter> keyFilters) { |
|||
super(entityFilter); |
|||
this.pageLink = pageLink; |
|||
this.entityFields = entityFields; |
|||
this.latestValues = latestValues; |
|||
this.keyFilters = keyFilters; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
/** |
|||
* 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.common.data.query; |
|||
|
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.alarm.AlarmInfo; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
|
|||
public class AlarmData extends AlarmInfo { |
|||
|
|||
private final UUID entityId; |
|||
private final Map<EntityKeyType, Map<String, TsValue>> latest; |
|||
|
|||
public AlarmData(Alarm alarm, String originatorName, UUID entityId) { |
|||
super(alarm, originatorName); |
|||
this.entityId = entityId; |
|||
this.latest = new HashMap<>(); |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
/** |
|||
* 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.common.data.query; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.Getter; |
|||
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
|||
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
|||
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class AlarmDataPageLink extends EntityDataPageLink { |
|||
|
|||
private long startTs; |
|||
private long endTs; |
|||
//TODO: handle this;
|
|||
private long timeWindow; |
|||
private List<String> typeList; |
|||
private List<AlarmSearchStatus> statusList; |
|||
private List<AlarmSeverity> severityList; |
|||
private boolean searchPropagatedAlarms; |
|||
|
|||
public AlarmDataPageLink() { |
|||
super(); |
|||
} |
|||
|
|||
public AlarmDataPageLink(int pageSize, int page, String textSearch, EntityDataSortOrder sortOrder, boolean dynamic, |
|||
boolean searchPropagatedAlarms, |
|||
long startTs, long endTs, long timeWindow, |
|||
List<String> typeList, List<AlarmSearchStatus> statusList, List<AlarmSeverity> severityList) { |
|||
super(pageSize, page, textSearch, sortOrder, dynamic); |
|||
this.searchPropagatedAlarms = searchPropagatedAlarms; |
|||
this.startTs = startTs; |
|||
this.endTs = endTs; |
|||
this.timeWindow = timeWindow; |
|||
this.typeList = typeList; |
|||
this.statusList = statusList; |
|||
this.severityList = severityList; |
|||
} |
|||
|
|||
@JsonIgnore |
|||
public AlarmDataPageLink nextPageLink() { |
|||
return new AlarmDataPageLink(this.getPageSize(), this.getPage() + 1, this.getTextSearch(), this.getSortOrder(), this.isDynamic(), |
|||
this.searchPropagatedAlarms, |
|||
this.startTs, this.endTs, this.timeWindow, |
|||
this.typeList, this.statusList, this.severityList |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
/** |
|||
* 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.common.data.query; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import lombok.Getter; |
|||
import lombok.ToString; |
|||
|
|||
import java.util.List; |
|||
|
|||
@ToString |
|||
public class AlarmDataQuery extends AbstractDataQuery<AlarmDataPageLink> { |
|||
|
|||
public AlarmDataQuery() { |
|||
} |
|||
|
|||
public AlarmDataQuery(EntityFilter entityFilter) { |
|||
super(entityFilter); |
|||
} |
|||
|
|||
public AlarmDataQuery(EntityFilter entityFilter, AlarmDataPageLink pageLink, List<EntityKey> entityFields, List<EntityKey> latestValues, List<KeyFilter> keyFilters) { |
|||
super(entityFilter, pageLink, entityFields, latestValues, keyFilters); |
|||
} |
|||
|
|||
@JsonIgnore |
|||
public AlarmDataQuery next() { |
|||
return new AlarmDataQuery(getEntityFilter(), getPageLink().nextPageLink(), entityFields, latestValues, keyFilters); |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
/** |
|||
* 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.dao.sql.query; |
|||
|
|||
import com.fasterxml.jackson.core.JsonProcessingException; |
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.util.StringUtils; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.alarm.Alarm; |
|||
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
|||
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|||
import org.thingsboard.server.common.data.id.AlarmId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.AlarmData; |
|||
import org.thingsboard.server.common.data.query.EntityDataPageLink; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.UUID; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Slf4j |
|||
public class AlarmDataAdapter { |
|||
|
|||
private final static ObjectMapper mapper = new ObjectMapper(); |
|||
|
|||
public static PageData<AlarmData> createAlarmData(EntityDataPageLink pageLink, |
|||
List<Map<String, Object>> rows, |
|||
int totalElements) { |
|||
int totalPages = pageLink.getPageSize() > 0 ? (int) Math.ceil((float) totalElements / pageLink.getPageSize()) : 1; |
|||
int startIndex = pageLink.getPageSize() * pageLink.getPage(); |
|||
boolean hasNext = pageLink.getPageSize() > 0 && totalElements > startIndex + rows.size(); |
|||
List<AlarmData> entitiesData = convertListToAlarmData(rows); |
|||
return new PageData<>(entitiesData, totalPages, totalElements, hasNext); |
|||
} |
|||
|
|||
private static List<AlarmData> convertListToAlarmData(List<Map<String, Object>> result) { |
|||
return result.stream().map(AlarmDataAdapter::toEntityData).collect(Collectors.toList()); |
|||
} |
|||
|
|||
private static AlarmData toEntityData(Map<String, Object> row) { |
|||
Alarm alarm = new Alarm(); |
|||
alarm.setId(new AlarmId((UUID) row.get(ModelConstants.ID_PROPERTY))); |
|||
alarm.setCreatedTime((long) row.get(ModelConstants.CREATED_TIME_PROPERTY)); |
|||
alarm.setAckTs((long) row.get(ModelConstants.ALARM_ACK_TS_PROPERTY)); |
|||
alarm.setClearTs((long) row.get(ModelConstants.ALARM_CLEAR_TS_PROPERTY)); |
|||
alarm.setStartTs((long) row.get(ModelConstants.ALARM_START_TS_PROPERTY)); |
|||
alarm.setEndTs((long) row.get(ModelConstants.ALARM_END_TS_PROPERTY)); |
|||
Object additionalInfo = row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY); |
|||
if (additionalInfo != null) { |
|||
try { |
|||
alarm.setDetails(mapper.readTree(additionalInfo.toString())); |
|||
} catch (JsonProcessingException e) { |
|||
log.warn("Failed to parse json: {}", row.get(ModelConstants.ADDITIONAL_INFO_PROPERTY), e); |
|||
} |
|||
} |
|||
EntityType originatorType = EntityType.values()[(int) row.get(ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY)]; |
|||
UUID originatorId = (UUID) row.get(ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); |
|||
alarm.setOriginator(EntityIdFactory.getByTypeAndUuid(originatorType, originatorId)); |
|||
alarm.setPropagate((boolean) row.get(ModelConstants.ALARM_PROPAGATE_PROPERTY)); |
|||
alarm.setType(row.get(ModelConstants.ALARM_TYPE_PROPERTY).toString()); |
|||
alarm.setSeverity(AlarmSeverity.valueOf(row.get(ModelConstants.ALARM_SEVERITY_PROPERTY).toString())); |
|||
alarm.setStatus(AlarmStatus.valueOf(row.get(ModelConstants.ALARM_STATUS_PROPERTY).toString())); |
|||
alarm.setTenantId(new TenantId((UUID) row.get(ModelConstants.TENANT_ID_PROPERTY))); |
|||
if (row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES) != null) { |
|||
String propagateRelationTypes = row.get(ModelConstants.ALARM_PROPAGATE_RELATION_TYPES).toString(); |
|||
if (!StringUtils.isEmpty(propagateRelationTypes)) { |
|||
alarm.setPropagateRelationTypes(Arrays.asList(propagateRelationTypes.split(","))); |
|||
} else { |
|||
alarm.setPropagateRelationTypes(Collections.emptyList()); |
|||
} |
|||
} else { |
|||
alarm.setPropagateRelationTypes(Collections.emptyList()); |
|||
} |
|||
UUID entityId = (UUID) row.get(ModelConstants.ENTITY_ID_COLUMN); |
|||
Object originatorNameObj = row.get(ModelConstants.ALARM_ORIGINATOR_NAME_PROPERTY); |
|||
String originatorName = originatorNameObj != null ? originatorNameObj.toString() : null; |
|||
return new AlarmData(alarm, originatorName, entityId); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
/** |
|||
* 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.dao.sql.query; |
|||
|
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.AlarmData; |
|||
import org.thingsboard.server.common.data.query.AlarmDataPageLink; |
|||
|
|||
import java.util.Collection; |
|||
|
|||
public interface AlarmQueryRepository { |
|||
|
|||
PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, |
|||
AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds); |
|||
|
|||
} |
|||
@ -0,0 +1,241 @@ |
|||
/** |
|||
* 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.dao.sql.query; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; |
|||
import org.springframework.stereotype.Repository; |
|||
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; |
|||
import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
|||
import org.thingsboard.server.common.data.alarm.AlarmStatus; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.AlarmData; |
|||
import org.thingsboard.server.common.data.query.AlarmDataPageLink; |
|||
import org.thingsboard.server.common.data.query.EntityDataSortOrder; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.dao.model.ModelConstants; |
|||
import org.thingsboard.server.dao.util.SqlDao; |
|||
|
|||
import java.util.Collection; |
|||
import java.util.HashMap; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@SqlDao |
|||
@Repository |
|||
@Slf4j |
|||
public class DefaultAlarmQueryRepository implements AlarmQueryRepository { |
|||
|
|||
private static final Map<String, String> alarmFieldColumnMap = new HashMap<>(); |
|||
|
|||
static { |
|||
alarmFieldColumnMap.put("createdTime", ModelConstants.CREATED_TIME_PROPERTY); |
|||
alarmFieldColumnMap.put("ackTs", ModelConstants.ALARM_ACK_TS_PROPERTY); |
|||
alarmFieldColumnMap.put("clearTs", ModelConstants.ALARM_CLEAR_TS_PROPERTY); |
|||
alarmFieldColumnMap.put("details", ModelConstants.ADDITIONAL_INFO_PROPERTY); |
|||
alarmFieldColumnMap.put("endTs", ModelConstants.ALARM_END_TS_PROPERTY); |
|||
alarmFieldColumnMap.put("startTs", ModelConstants.ALARM_START_TS_PROPERTY); |
|||
alarmFieldColumnMap.put("status", ModelConstants.ALARM_STATUS_PROPERTY); |
|||
alarmFieldColumnMap.put("type", ModelConstants.ALARM_TYPE_PROPERTY); |
|||
alarmFieldColumnMap.put("severity", ModelConstants.ALARM_SEVERITY_PROPERTY); |
|||
alarmFieldColumnMap.put("originator_id", ModelConstants.ALARM_ORIGINATOR_ID_PROPERTY); |
|||
alarmFieldColumnMap.put("originator_type", ModelConstants.ALARM_ORIGINATOR_TYPE_PROPERTY); |
|||
} |
|||
|
|||
public static final String SELECT_ORIGINATOR_NAME = " CASE" + |
|||
" WHEN a.originator_type = 0" + |
|||
" THEN (select title from tenant where id = a.originator_id)" + |
|||
" WHEN a.originator_type = 1 " + |
|||
" THEN (select title from customer where id = a.originator_id)" + |
|||
" WHEN a.originator_type = 2" + |
|||
" THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = a.originator_id)" + |
|||
" WHEN a.originator_type = 3" + |
|||
" THEN (select title from dashboard where id = a.originator_id)" + |
|||
" WHEN a.originator_type = 4" + |
|||
" THEN (select name from asset where id = a.originator_id)" + |
|||
" WHEN a.originator_type = 5" + |
|||
" THEN (select name from device where id = a.originator_id)" + |
|||
" WHEN a.originator_type = 9" + |
|||
" THEN (select name from entity_view where id = a.originator_id)" + |
|||
" END as originator_name"; |
|||
|
|||
public static final String FIELDS_SELECTION = "select a.id as id," + |
|||
" a.created_time as created_time," + |
|||
" a.ack_ts as ack_ts," + |
|||
" a.clear_ts as clear_ts," + |
|||
" a.additional_info as additional_info," + |
|||
" a.end_ts as end_ts," + |
|||
" a.originator_id as originator_id," + |
|||
" a.originator_type as originator_type," + |
|||
" a.propagate as propagate," + |
|||
" a.severity as severity," + |
|||
" a.start_ts as start_ts," + |
|||
" a.status as status, " + |
|||
" a.tenant_id as tenant_id, " + |
|||
" a.propagate_relation_types as propagate_relation_types, " + |
|||
" a.type as type," + SELECT_ORIGINATOR_NAME + ", "; |
|||
|
|||
public static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ALARM_ANY' and a.id = r.to_id"; |
|||
|
|||
@Autowired |
|||
protected NamedParameterJdbcTemplate jdbcTemplate; |
|||
|
|||
|
|||
@Override |
|||
public PageData<AlarmData> findAlarmDataByQueryForEntities(TenantId tenantId, CustomerId customerId, |
|||
AlarmDataPageLink pageLink, Collection<EntityId> orderedEntityIds) { |
|||
QueryContext ctx = new QueryContext(); |
|||
|
|||
StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION); |
|||
StringBuilder fromPart = new StringBuilder(" from alarm a "); |
|||
StringBuilder wherePart = new StringBuilder(" where "); |
|||
StringBuilder sortPart = new StringBuilder(" order by "); |
|||
boolean addAnd = false; |
|||
if (pageLink.isSearchPropagatedAlarms()) { |
|||
selectPart.append(" r.from_id as entity_id "); |
|||
fromPart.append(JOIN_RELATIONS); |
|||
} else { |
|||
selectPart.append(" a.originator_id as entity_id "); |
|||
} |
|||
EntityDataSortOrder sortOrder = pageLink.getSortOrder(); |
|||
if (sortOrder != null && sortOrder.getKey().getType().equals(EntityKeyType.ALARM_FIELD)) { |
|||
String sortOrderKey = sortOrder.getKey().getKey(); |
|||
sortPart.append("a.").append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey)) |
|||
.append(" ").append(sortOrder.getDirection().name()); |
|||
ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList())); |
|||
if (pageLink.isSearchPropagatedAlarms()) { |
|||
fromPart.append(" and r.from_id in (:entity_ids)"); |
|||
} else { |
|||
wherePart.append(" a.originator_id in (:entity_ids)"); |
|||
addAnd = true; |
|||
} |
|||
} else { |
|||
fromPart.append(" left join (select * from (VALUES"); |
|||
int entityIdIdx = 0; |
|||
int lastEntityIdIdx = orderedEntityIds.size() - 1; |
|||
for (EntityId entityId : orderedEntityIds) { |
|||
fromPart.append("(uuid('").append(entityId.getId().toString()).append("'), ").append(entityIdIdx).append(")"); |
|||
if (entityIdIdx != lastEntityIdIdx) { |
|||
fromPart.append(","); |
|||
} else { |
|||
fromPart.append(")"); |
|||
} |
|||
entityIdIdx++; |
|||
} |
|||
fromPart.append(" as e(id, priority)) e "); |
|||
if (pageLink.isSearchPropagatedAlarms()) { |
|||
fromPart.append("on r.from_id = e.id"); |
|||
} else { |
|||
fromPart.append("on a.originator_id = e.id"); |
|||
} |
|||
sortPart.append("e.priority"); |
|||
} |
|||
|
|||
if (pageLink.getStartTs() > 0) { |
|||
addAndIfNeeded(wherePart, addAnd); |
|||
addAnd = true; |
|||
ctx.addLongParameter("startTime", pageLink.getStartTs()); |
|||
wherePart.append("a.created_time >= :startTime"); |
|||
} |
|||
|
|||
if (pageLink.getEndTs() > 0) { |
|||
addAndIfNeeded(wherePart, addAnd); |
|||
addAnd = true; |
|||
ctx.addLongParameter("endTime", pageLink.getEndTs()); |
|||
wherePart.append("a.created_time <= :endTime"); |
|||
} |
|||
|
|||
if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) { |
|||
addAndIfNeeded(wherePart, addAnd); |
|||
addAnd = true; |
|||
ctx.addStringListParameter("alarmTypes", pageLink.getTypeList()); |
|||
wherePart.append("a.type in (:alarmTypes)"); |
|||
} |
|||
|
|||
if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) { |
|||
addAndIfNeeded(wherePart, addAnd); |
|||
addAnd = true; |
|||
ctx.addStringListParameter("alarmSeverities", pageLink.getSeverityList().stream().map(AlarmSeverity::name).collect(Collectors.toList())); |
|||
wherePart.append("a.severity in (:alarmSeverities)"); |
|||
} |
|||
|
|||
if (pageLink.getStatusList() != null && !pageLink.getStatusList().isEmpty()) { |
|||
Set<AlarmStatus> statusSet = toStatusSet(pageLink.getStatusList()); |
|||
if (!statusSet.isEmpty()) { |
|||
addAndIfNeeded(wherePart, addAnd); |
|||
addAnd = true; |
|||
ctx.addStringListParameter("alarmStatuses", statusSet.stream().map(AlarmStatus::name).collect(Collectors.toList())); |
|||
wherePart.append(" a.status in (:alarmStatuses)"); |
|||
} |
|||
} |
|||
|
|||
String countQuery = fromPart.toString() + wherePart.toString(); |
|||
int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) %s", countQuery), ctx, Integer.class); |
|||
|
|||
String dataQuery = selectPart.toString() + countQuery + sortPart; |
|||
|
|||
int startIndex = pageLink.getPageSize() * pageLink.getPage(); |
|||
if (pageLink.getPageSize() > 0) { |
|||
dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex); |
|||
} |
|||
List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx); |
|||
return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements); |
|||
} |
|||
|
|||
private Set<AlarmStatus> toStatusSet(List<AlarmSearchStatus> statusList) { |
|||
Set<AlarmStatus> result = new HashSet<>(); |
|||
for (AlarmSearchStatus searchStatus : statusList) { |
|||
switch (searchStatus) { |
|||
case ACK: |
|||
result.add(AlarmStatus.ACTIVE_ACK); |
|||
result.add(AlarmStatus.CLEARED_ACK); |
|||
break; |
|||
case UNACK: |
|||
result.add(AlarmStatus.ACTIVE_UNACK); |
|||
result.add(AlarmStatus.CLEARED_UNACK); |
|||
break; |
|||
case CLEARED: |
|||
result.add(AlarmStatus.CLEARED_ACK); |
|||
result.add(AlarmStatus.CLEARED_UNACK); |
|||
break; |
|||
case ACTIVE: |
|||
result.add(AlarmStatus.ACTIVE_ACK); |
|||
result.add(AlarmStatus.ACTIVE_UNACK); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
if (searchStatus == AlarmSearchStatus.ANY || result.size() == AlarmStatus.values().length) { |
|||
result.clear(); |
|||
return result; |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
private void addAndIfNeeded(StringBuilder wherePart, boolean addAnd) { |
|||
if (addAnd) { |
|||
wherePart.append(" and "); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue