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