/*****************************************************************************
*
* Copyright (C) Zenoss, Inc. 2010-2011, all rights reserved.
*
* This content is made available according to terms specified in
* License.zenoss under the directory where your Zenoss product is installed.
*
****************************************************************************/
package org.zenoss.zep.dao.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.simple.SimpleJdbcOperations;
import org.zenoss.protobufs.zep.Zep.EventTrigger;
import org.zenoss.protobufs.zep.Zep.EventTriggerSubscription;
import org.zenoss.protobufs.zep.Zep.Rule;
import org.zenoss.protobufs.zep.Zep.RuleType;
import org.zenoss.zep.ZepException;
import org.zenoss.zep.annotations.TransactionalReadOnly;
import org.zenoss.zep.annotations.TransactionalRollbackAllExceptions;
import org.zenoss.zep.dao.EventSignalSpoolDao;
import org.zenoss.zep.dao.EventTriggerDao;
import org.zenoss.zep.dao.impl.compat.DatabaseCompatibility;
import org.zenoss.zep.dao.impl.compat.TypeConverter;
import org.zenoss.zep.dao.impl.SimpleJdbcTemplateProxy;
import java.lang.reflect.Proxy;
import javax.sql.DataSource;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class EventTriggerDaoImpl implements EventTriggerDao {
private static final String COLUMN_UUID = "uuid";
private static final String COLUMN_NAME = "name";
private static final String COLUMN_ENABLED = "enabled";
private static final String COLUMN_RULE_API_VERSION = "rule_api_version";
private static final String COLUMN_RULE_TYPE_ID = "rule_type_id";
private static final String COLUMN_RULE_SOURCE = "rule_source";
private static final Logger logger = LoggerFactory
.getLogger(EventTriggerDaoImpl.class);
private final SimpleJdbcOperations template;
private EventSignalSpoolDao eventSignalSpoolDao;
private TypeConverter<String> uuidConverter;
public EventTriggerDaoImpl(DataSource dataSource) {
this.template = (SimpleJdbcOperations) Proxy.newProxyInstance(SimpleJdbcOperations.class.getClassLoader(),
new Class<?>[] {SimpleJdbcOperations.class}, new SimpleJdbcTemplateProxy(dataSource));
}
public void setEventSignalSpoolDao(EventSignalSpoolDao eventSignalSpoolDao) {
this.eventSignalSpoolDao = eventSignalSpoolDao;
}
public void setDatabaseCompatibility(DatabaseCompatibility databaseCompatibility) {
this.uuidConverter = databaseCompatibility.getUUIDConverter();
}
@Override
@TransactionalRollbackAllExceptions
public void create(EventTrigger trigger) throws ZepException {
final Map<String, Object> fields = triggerToFields(trigger);
final StringBuilder names = new StringBuilder();
final StringBuilder values = new StringBuilder();
for (String key : fields.keySet()) {
if (names.length() > 0) {
names.append(',');
values.append(',');
}
names.append(key);
values.append(':').append(key);
}
this.template.update(String.format("INSERT INTO event_trigger (%s) VALUES (%s)", names, values), fields);
}
@Override
@TransactionalRollbackAllExceptions
public int delete(String uuidStr) throws ZepException {
final Map<String,Object> fields = Collections.singletonMap(COLUMN_UUID, uuidConverter.toDatabaseType(uuidStr));
return this.template.update("DELETE FROM event_trigger WHERE uuid=:uuid", fields);
}
@Override
@TransactionalReadOnly
public EventTrigger findByUuid(String uuidStr) throws ZepException {
final Object uuid = uuidConverter.toDatabaseType(uuidStr);
final Map<String,Object> fields = Collections.singletonMap(COLUMN_UUID, uuid);
String sql = "SELECT event_trigger.*,sub.uuid AS event_sub_uuid,sub.subscriber_uuid,sub.delay_seconds,"
+ "sub.repeat_seconds,sub.send_initial_occurrence FROM event_trigger "
+ "LEFT JOIN event_trigger_subscription AS sub ON event_trigger.uuid = sub.event_trigger_uuid "
+ "WHERE event_trigger.uuid=:uuid";
List<EventTrigger> triggers = this.template.getNamedParameterJdbcOperations().query(
sql, fields, new EventTriggerExtractor());
EventTrigger trigger = null;
if (!triggers.isEmpty()) {
trigger = triggers.get(0);
}
return trigger;
}
@Override
@TransactionalReadOnly
public List<EventTrigger> findAll() throws ZepException {
String sql = "SELECT event_trigger.*,sub.uuid AS event_sub_uuid,sub.subscriber_uuid,sub.delay_seconds,"
+ "sub.repeat_seconds,sub.send_initial_occurrence FROM event_trigger "
+ "LEFT JOIN event_trigger_subscription AS sub ON event_trigger.uuid = sub.event_trigger_uuid";
return this.template.getJdbcOperations().query(sql, new EventTriggerExtractor());
}
@Override
@TransactionalReadOnly
public List<EventTrigger> findAllEnabled() throws ZepException {
String sql = "SELECT event_trigger.*,sub.uuid AS event_sub_uuid,sub.subscriber_uuid,sub.delay_seconds,"
+ "sub.repeat_seconds,sub.send_initial_occurrence FROM event_trigger "
+ "LEFT JOIN event_trigger_subscription AS sub ON event_trigger.uuid = sub.event_trigger_uuid "
+ "WHERE event_trigger.enabled <> ?";
return this.template.getJdbcOperations().query(sql, new EventTriggerExtractor(), Boolean.FALSE);
}
@Override
@TransactionalRollbackAllExceptions
public int modify(EventTrigger trigger) throws ZepException {
final Map<String, Object> fields = triggerToFields(trigger);
final StringBuilder fieldsSql = new StringBuilder();
for (String key : fields.keySet()) {
if (!COLUMN_UUID.equals(key)) {
if (fieldsSql.length() > 0) {
fieldsSql.append(",");
}
fieldsSql.append(key).append("=:").append(key);
}
}
if (fieldsSql.length() == 0) {
logger.warn("No fields to modify in trigger: {}", trigger);
return 0;
}
String sql = String.format("UPDATE event_trigger SET %s WHERE uuid=:uuid", fieldsSql.toString());
int numRows = template.update(sql, fields);
/* If trigger is now disabled, remove any spooled signals */
if (trigger.hasEnabled() && !trigger.getEnabled()) {
this.eventSignalSpoolDao.deleteByTriggerUuid(trigger.getUuid());
}
return numRows;
}
private Map<String, Object> triggerToFields(EventTrigger trigger) {
final Map<String, Object> fields = new LinkedHashMap<String, Object>();
fields.put(COLUMN_UUID, uuidConverter.toDatabaseType(trigger.getUuid()));
fields.put(COLUMN_NAME, trigger.hasName() ? trigger.getName() : null);
fields.put(COLUMN_ENABLED, trigger.getEnabled());
Rule rule = trigger.getRule();
fields.put(COLUMN_RULE_API_VERSION, rule.getApiVersion());
fields.put(COLUMN_RULE_SOURCE, rule.getSource());
fields.put(COLUMN_RULE_TYPE_ID, rule.getType().getNumber());
return fields;
}
private class EventTriggerExtractor implements ResultSetExtractor<List<EventTrigger>> {
@Override
public List<EventTrigger> extractData(ResultSet rs)
throws SQLException, DataAccessException {
Map<String, EventTrigger.Builder> triggersByUuid = new HashMap<String, EventTrigger.Builder>();
while (rs.next()) {
String uuid = uuidConverter.fromDatabaseType(rs, COLUMN_UUID);
EventTrigger.Builder triggerBuilder = triggersByUuid.get(uuid);
if (triggerBuilder == null) {
triggerBuilder = EventTrigger.newBuilder();
triggerBuilder.setUuid(uuid);
String name = rs.getString(COLUMN_NAME);
if (name != null) {
triggerBuilder.setName(name);
}
triggerBuilder.setEnabled(rs.getBoolean(COLUMN_ENABLED));
Rule.Builder ruleBuilder = Rule.newBuilder();
ruleBuilder.setApiVersion(rs.getInt(COLUMN_RULE_API_VERSION));
ruleBuilder.setType(RuleType.valueOf(rs.getInt(COLUMN_RULE_TYPE_ID)));
ruleBuilder.setSource(rs.getString(COLUMN_RULE_SOURCE));
triggerBuilder.setRule(ruleBuilder.build());
triggersByUuid.put(uuid, triggerBuilder);
}
/* Add subscriptions (LEFT JOINED table) */
String subUuid = uuidConverter.fromDatabaseType(rs, "event_sub_uuid");
if (subUuid != null) {
EventTriggerSubscription.Builder subBuilder = EventTriggerSubscription.newBuilder();
subBuilder.setUuid(subUuid);
subBuilder.setSubscriberUuid(uuidConverter.fromDatabaseType(rs,
EventTriggerSubscriptionDaoImpl.COLUMN_SUBSCRIBER_UUID));
subBuilder.setDelaySeconds(rs.getInt(EventTriggerSubscriptionDaoImpl.COLUMN_DELAY_SECONDS));
subBuilder.setRepeatSeconds(rs.getInt(EventTriggerSubscriptionDaoImpl.COLUMN_REPEAT_SECONDS));
subBuilder.setTriggerUuid(uuid);
subBuilder.setSendInitialOccurrence(rs.getBoolean(
EventTriggerSubscriptionDaoImpl.COLUMN_SEND_INITIAL_OCCURRENCE));
triggerBuilder.addSubscriptions(subBuilder.build());
}
}
List<EventTrigger> triggers = new ArrayList<EventTrigger>(triggersByUuid.size());
for (EventTrigger.Builder eventTriggerBuilder : triggersByUuid.values()) {
triggers.add(eventTriggerBuilder.build());
}
return triggers;
}
}
}