Skip to content

Commit

Permalink
Merge pull request #57 from jshaughn/hwkalerts-56
Browse files Browse the repository at this point in the history
HWKALERTS-56 : Need a way to fetch Alerts without the evaluations

Lucas, I broke out the fetchAlerts testing into another test method, and added more tests.  Also, found a bug which I fixed.  As we discussed I'll now merge this PR. Thanks!
  • Loading branch information
jshaughn committed Jun 5, 2015
2 parents d16d512 + 79b66bb commit 8dee6bc
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
*/
package org.hawkular.alerts.api.model.condition;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import java.util.Set;

Expand All @@ -30,6 +34,14 @@
*/
public class Alert {

/**
* Used to annotate fields that should be thinned in order to return/deserialize a lightweight Alert
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Thin {
}

public enum Status {
OPEN, ACKNOWLEDGED, RESOLVED
};
Expand All @@ -48,6 +60,7 @@ public enum Status {
private long ctime;

@JsonInclude(Include.NON_EMPTY)
@Thin
private List<Set<ConditionEval>> evalSets;

@JsonInclude
Expand All @@ -72,6 +85,7 @@ public enum Status {
private String resolvedNotes;

@JsonInclude(Include.NON_EMPTY)
@Thin
private List<Set<ConditionEval>> resolvedEvalSets;

public Alert() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class AlertsCriteria {
Collection<String> triggerIds = null;
Tag tag = null;
Collection<Tag> tags = null;
boolean thin = false;

public AlertsCriteria() {
super();
Expand Down Expand Up @@ -141,6 +142,14 @@ public void setTags(Collection<Tag> tags) {
this.tags = tags;
}

public boolean isThin() {
return thin;
}

public void setThin(boolean thin) {
this.thin = thin;
}

public boolean hasCriteria() {
return null != startTime || //
null != endTime || //
Expand All @@ -156,9 +165,9 @@ public boolean hasCriteria() {

@Override
public String toString() {
return "AlertsCriteria [startTime=" + startTime + ", endTime=" + endTime + ", triggerId=" + triggerId
+ ", triggerIds=" + triggerIds + ", tag=" + tag + ", tags=" + tags + ", status=" + status + ", " +
"statusSet=" + statusSet + "]";
return "AlertsCriteria [startTime=" + startTime + ", endTime=" + endTime + ", alertId=" + alertId
+ ", alertIds=" + alertIds + ", status=" + status + ", statusSet=" + statusSet + ", triggerId="
+ triggerId + ", triggerIds=" + triggerIds + ", tag=" + tag + ", tags=" + tags + ", thin=" + thin
+ "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.google.common.util.concurrent.Futures;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

Expand All @@ -56,12 +58,14 @@
*/
@Stateless
public class CassAlertsServiceImpl implements AlertsService {

private final MsgLogger msgLog = MsgLogger.LOGGER;
private final Logger log = Logger.getLogger(CassAlertsServiceImpl.class);

private Session session;

private Gson gson;
private Gson gsonThin;

@EJB
AlertsEngine alertsEngine;
Expand All @@ -80,6 +84,22 @@ public void initServices() {
gsonBuilder.registerTypeHierarchyAdapter(ConditionEval.class, new GsonAdapter<ConditionEval>());
gson = gsonBuilder.create();

GsonBuilder gsonBuilderThin = new GsonBuilder();
gsonBuilderThin.registerTypeHierarchyAdapter(ConditionEval.class, new GsonAdapter<ConditionEval>());
gsonBuilderThin.addDeserializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
final Alert.Thin thin = f.getAnnotation(Alert.Thin.class);
return thin != null;
}

@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
});
gsonThin = gsonBuilderThin.create();

} catch (Throwable t) {
if (log.isDebugEnabled()) {
t.printStackTrace();
Expand Down Expand Up @@ -134,6 +154,7 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex
throw new RuntimeException("Cassandra session is null");
}
boolean filter = (null != criteria && criteria.hasCriteria());
boolean thin = (null != criteria && criteria.isThin());

if (filter) {
log.debugf("getAlerts criteria: %s", criteria.toString());
Expand All @@ -144,59 +165,60 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex

try {
if (filter) {
/*
Get alertsIds explicitly added into the criteria. Start with these as there is no query involved
*/
Set<String> alertIdsFilteredByAlerts = new HashSet<>();
boolean filterByAlerts = filterByAlerts(alertIdsFilteredByAlerts, criteria);
if (filterByAlerts) {
alertIds.addAll(alertIdsFilteredByAlerts);
}

/*
Get alertIds filtered by triggerIds clause
*/
Set<String> alertIdsFilteredByTriggers = new HashSet<>();
boolean filterByTriggers = filterByTriggers(tenantId, alertIdsFilteredByTriggers, criteria);
if (filterByTriggers) {
if (alertIds.isEmpty()) {
alertIds.addAll(alertIdsFilteredByTriggers);
} else {
alertIds.retainAll(alertIdsFilteredByTriggers);
}
if (alertIds.isEmpty()) {
return alerts;
}
}

/*
Get alertsIds filtered by ctime clause
*/
Set<String> alertIdsFilteredByCtime = new HashSet<>();
boolean filterByCtime = filterByCtime(tenantId, alertIdsFilteredByCtime, criteria);

/*
Get alertsIds filtered by statutes clause
*/
Set<String> alertIdsFilteredByStatus = new HashSet<>();
boolean filterByStatus = filterByStatuses(tenantId, alertIdsFilteredByStatus, criteria);

/*
Get alertsIds explicitly added into the criteria
*/
Set<String> alertIdsFilteredByAlerts = new HashSet<>();
boolean filterByAlerts = filterByAlerts(alertIdsFilteredByAlerts, criteria);

/*
Join of all filters
*/
boolean firstJoin = true;
if (filterByTriggers) {
alertIds.addAll(alertIdsFilteredByTriggers);
firstJoin = false;
}
if (filterByCtime) {
if (firstJoin) {
if (alertIds.isEmpty()) {
alertIds.addAll(alertIdsFilteredByCtime);
} else {
alertIds.retainAll(alertIdsFilteredByCtime);
}
firstJoin = false;
if (alertIds.isEmpty()) {
return alerts;
}
}

/*
Get alertsIds filtered by statuses clause
*/
Set<String> alertIdsFilteredByStatus = new HashSet<>();
boolean filterByStatus = filterByStatuses(tenantId, alertIdsFilteredByStatus, criteria);
if (filterByStatus) {
if (firstJoin) {
if (alertIds.isEmpty()) {
alertIds.addAll(alertIdsFilteredByStatus);
} else {
alertIds.retainAll(alertIdsFilteredByStatus);
}
firstJoin = false;
}
if (filterByAlerts) {
if (firstJoin) {
alertIds.addAll(alertIdsFilteredByAlerts);
} else {
alertIds.retainAll(alertIdsFilteredByAlerts);
if (alertIds.isEmpty()) {
return alerts;
}
}
}
Expand All @@ -210,7 +232,7 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex
ResultSet rsAlerts = session.execute(selectAlertsByTenant.bind(tenantId));
for (Row row : rsAlerts) {
String payload = row.getString("payload");
Alert alert = fromJson(payload, Alert.class);
Alert alert = fromJson(payload, Alert.class, thin);
alerts.add(alert);
}
} else {
Expand All @@ -226,7 +248,7 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex
rsAlerts.stream().forEach(r -> {
for (Row row : r) {
String payload = row.getString("payload");
Alert alert = fromJson(payload, Alert.class);
Alert alert = fromJson(payload, Alert.class, thin);
alerts.add(alert);
}
});
Expand All @@ -243,13 +265,21 @@ public List<Alert> getAlerts(String tenantId, AlertsCriteria criteria) throws Ex
/*
Trigger ids can be passed explicitly in the criteria or indirectly via tags.
This helper method extracts the list of triggers id and populates the set passed as argument.
**Note** currently explicitTriggerIds and triggerIds determined via tags are joined together (treated as one
triggerId filter). I'm not sure this is right but it seems to make the most sense.
*/
private void extractTriggersId(Set<String> triggerIds, AlertsCriteria criteria) throws Exception {
private boolean extractTriggerIds(Set<String> triggerIds, AlertsCriteria criteria) throws Exception {
boolean hasTriggerId = !isEmpty(criteria.getTriggerId());
boolean hasTriggerIds = !isEmpty(criteria.getTriggerIds());
boolean hasTag = null != criteria.getTag();
boolean hasTags = !isEmpty(criteria.getTags());

/*
Explicit trigger ids
*/
if (isEmpty(criteria.getTriggerIds())) {
if (!isEmpty(criteria.getTriggerId())) {
if (!hasTriggerIds) {
if (hasTriggerId) {
triggerIds.add(criteria.getTriggerId());
}
} else {
Expand All @@ -264,28 +294,28 @@ private void extractTriggersId(Set<String> triggerIds, AlertsCriteria criteria)
/*
Indirect trigger ids by tags
*/
if (!isEmpty(criteria.getTags()) || criteria.getTag() != null) {
if (hasTag || hasTags) {
Set<Tag> tags = new HashSet<>();
if (criteria.getTags() != null) {
if (hasTags) {
tags.addAll(criteria.getTags());
}
Tag tag = criteria.getTag();
if (tag != null) {
tags.add(tag);
if (hasTag) {
tags.add(criteria.getTag());
}
triggerIds.addAll(getTriggersIdByTags(tags));
}

// Return true if any trigger or tag criteria was specified, regardless of whether it results in any
// triggerIds, because tags may not actually result in triggerIds but that does not mean the filter was
// not specified. In that case the overall fetch of alerts should return no alerts.
return hasTriggerId || hasTriggerIds || hasTag || hasTags;
}

private boolean filterByTriggers(String tenantId, Set<String> alertsId, AlertsCriteria criteria) throws Exception {
Set<String> triggerIds = new HashSet<>();
extractTriggersId(triggerIds, criteria);

boolean filterByTriggers = false;
boolean filterByTriggers = extractTriggerIds(triggerIds, criteria);

if (triggerIds.size() > 0) {
filterByTriggers = true;
List<ResultSetFuture> futures = new ArrayList<>();
PreparedStatement selectAlertsTriggers = CassStatement.get(session, CassStatement.SELECT_ALERTS_TRIGGERS);

Expand Down Expand Up @@ -560,14 +590,14 @@ public void sendData(Collection<Data> data) throws Exception {

private String toJson(Object resource) {

log.debugf(gson.toJson(resource));
return gson.toJson(resource);

String result = gson.toJson(resource);
log.debugf(result);
return result;
}

private <T> T fromJson(String json, Class<T> clazz) {
private <T> T fromJson(String json, Class<T> clazz, boolean thin) {

return gson.fromJson(json, clazz);
return thin ? gsonThin.fromJson(json, clazz) : gson.fromJson(json, clazz);
}

private boolean isEmpty(Collection<?> c) {
Expand Down

0 comments on commit 8dee6bc

Please sign in to comment.