/***************************************************************************** * * Copyright (C) Zenoss, Inc. 2010, 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.jdbc.core.RowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcInsert; import org.springframework.jdbc.core.simple.SimpleJdbcOperations; import org.zenoss.protobufs.zep.Zep.EventTriggerSubscription; import org.zenoss.zep.UUIDGenerator; import org.zenoss.zep.ZepException; import org.zenoss.zep.annotations.TransactionalReadOnly; import org.zenoss.zep.annotations.TransactionalRollbackAllExceptions; import org.zenoss.zep.dao.EventTriggerSubscriptionDao; import org.zenoss.zep.dao.impl.compat.DatabaseCompatibility; import org.zenoss.zep.dao.impl.compat.NestedTransactionService; 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.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; public class EventTriggerSubscriptionDaoImpl implements EventTriggerSubscriptionDao { public static final String TABLE_EVENT_TRIGGER_SUBSCRIPTION = "event_trigger_subscription"; public static final String COLUMN_UUID = "uuid"; public static final String COLUMN_EVENT_TRIGGER_UUID = "event_trigger_uuid"; public static final String COLUMN_SUBSCRIBER_UUID = "subscriber_uuid"; public static final String COLUMN_DELAY_SECONDS = "delay_seconds"; public static final String COLUMN_REPEAT_SECONDS = "repeat_seconds"; public static final String COLUMN_SEND_INITIAL_OCCURRENCE = "send_initial_occurrence"; private class EventTriggerSubscriptionMapper implements RowMapper<EventTriggerSubscription> { @Override public EventTriggerSubscription mapRow(ResultSet rs, int rowNum) throws SQLException { EventTriggerSubscription.Builder evtTriggerSub = EventTriggerSubscription.newBuilder(); evtTriggerSub.setUuid(uuidConverter.fromDatabaseType(rs, COLUMN_UUID)); evtTriggerSub.setDelaySeconds(rs.getInt(COLUMN_DELAY_SECONDS)); evtTriggerSub.setRepeatSeconds(rs.getInt(COLUMN_REPEAT_SECONDS)); evtTriggerSub.setTriggerUuid(uuidConverter.fromDatabaseType(rs, COLUMN_EVENT_TRIGGER_UUID)); evtTriggerSub.setSubscriberUuid(uuidConverter.fromDatabaseType(rs, COLUMN_SUBSCRIBER_UUID)); evtTriggerSub.setSendInitialOccurrence(rs.getBoolean(COLUMN_SEND_INITIAL_OCCURRENCE)); return evtTriggerSub.build(); } } @SuppressWarnings("unused") private static Logger logger = LoggerFactory.getLogger(EventTriggerSubscriptionDaoImpl.class); private final SimpleJdbcOperations template; private final SimpleJdbcInsert insert; private UUIDGenerator uuidGenerator; private TypeConverter<String> uuidConverter; private NestedTransactionService nestedTransactionService; public EventTriggerSubscriptionDaoImpl(DataSource dataSource) { this.template = (SimpleJdbcOperations) Proxy.newProxyInstance(SimpleJdbcOperations.class.getClassLoader(), new Class<?>[] {SimpleJdbcOperations.class}, new SimpleJdbcTemplateProxy(dataSource)); this.insert = new SimpleJdbcInsert(dataSource).withTableName(TABLE_EVENT_TRIGGER_SUBSCRIPTION); } public void setUuidGenerator(UUIDGenerator uuidGenerator) { this.uuidGenerator = uuidGenerator; } public void setDatabaseCompatibility(DatabaseCompatibility databaseCompatibility) { this.uuidConverter = databaseCompatibility.getUUIDConverter(); } public void setNestedTransactionService(NestedTransactionService nestedTransactionService) { this.nestedTransactionService = nestedTransactionService; } private Map<String, Object> subscriptionToFields(EventTriggerSubscription evtTriggerSub) { final Map<String, Object> fields = new LinkedHashMap<String, Object>(); fields.put(COLUMN_EVENT_TRIGGER_UUID, uuidConverter.toDatabaseType(evtTriggerSub.getTriggerUuid())); fields.put(COLUMN_SUBSCRIBER_UUID, uuidConverter.toDatabaseType(evtTriggerSub.getSubscriberUuid())); fields.put(COLUMN_DELAY_SECONDS, evtTriggerSub.getDelaySeconds()); fields.put(COLUMN_REPEAT_SECONDS, evtTriggerSub.getRepeatSeconds()); fields.put(COLUMN_SEND_INITIAL_OCCURRENCE, evtTriggerSub.getSendInitialOccurrence()); return fields; } @Override @TransactionalRollbackAllExceptions public String create(EventTriggerSubscription evtTriggerSubscription) throws ZepException { if (evtTriggerSubscription.getDelaySeconds() < 0 || evtTriggerSubscription.getRepeatSeconds() < 0) { throw new ZepException("Delay seconds or repeat seconds cannot be negative"); } final Map<String, Object> fields = subscriptionToFields(evtTriggerSubscription); String uuid = evtTriggerSubscription.getUuid(); if (uuid == null || uuid.isEmpty()) { uuid = this.uuidGenerator.generate().toString(); } fields.put(COLUMN_UUID, uuidConverter.toDatabaseType(uuid)); this.insert.execute(fields); return uuid; } @Override @TransactionalRollbackAllExceptions public int delete(String uuid) throws ZepException { final String sql = "DELETE FROM event_trigger_subscription WHERE uuid=?"; return this.template.update(sql, uuidConverter.toDatabaseType(uuid)); } @Override @TransactionalReadOnly public List<EventTriggerSubscription> findAll() throws ZepException { final String sql = "SELECT * FROM event_trigger_subscription"; return this.template.query(sql, new EventTriggerSubscriptionMapper()); } @Override @TransactionalReadOnly public EventTriggerSubscription findByUuid(String uuid) throws ZepException { final String sql = "SELECT * FROM event_trigger_subscription WHERE uuid=?"; List<EventTriggerSubscription> subs = this.template.query(sql, new EventTriggerSubscriptionMapper(), uuidConverter.toDatabaseType(uuid)); return (subs.size() > 0) ? subs.get(0) : null; } @Override @TransactionalReadOnly public List<EventTriggerSubscription> findBySubscriberUuid(String subscriberUuid) throws ZepException { final String sql = "SELECT * FROM event_trigger_subscription WHERE subscriber_uuid=?"; return this.template.query(sql, new EventTriggerSubscriptionMapper(), uuidConverter.toDatabaseType(subscriberUuid)); } @Override @TransactionalRollbackAllExceptions public int updateSubscriptions(String subscriberUuid, List<EventTriggerSubscription> subscriptions) throws ZepException { final Object subscriberUuidBytes = uuidConverter.toDatabaseType(subscriberUuid); int numRows = 0; if (subscriptions.isEmpty()) { String sql = "DELETE FROM event_trigger_subscription WHERE subscriber_uuid=?"; numRows += this.template.update(sql, subscriberUuidBytes); } else { List<Map<String, Object>> subscriptionFields = new ArrayList<Map<String, Object>>(subscriptions.size()); List<Object> eventTriggerUuids = new ArrayList<Object>(subscriptions.size()); for (EventTriggerSubscription eventTriggerSubscription : subscriptions) { if (!subscriberUuid.equals(eventTriggerSubscription.getSubscriberUuid())) { throw new ZepException("Subscriber id mismatch in subscriptions update"); } eventTriggerUuids.add(uuidConverter.toDatabaseType(eventTriggerSubscription.getTriggerUuid())); Map<String, Object> fields = subscriptionToFields(eventTriggerSubscription); String uuid = eventTriggerSubscription.getUuid(); if (uuid == null || uuid.isEmpty()) { uuid = this.uuidGenerator.generate().toString(); } fields.put(COLUMN_UUID, uuidConverter.toDatabaseType(uuid)); subscriptionFields.add(fields); } Map<String,Object> deleteFields = new HashMap<String, Object>(2); deleteFields.put(COLUMN_SUBSCRIBER_UUID, subscriberUuidBytes); deleteFields.put("_event_trigger_uuids", eventTriggerUuids); String deleteSql = "DELETE FROM event_trigger_subscription WHERE subscriber_uuid=:subscriber_uuid" + " AND event_trigger_uuid NOT IN (:_event_trigger_uuids)"; numRows += this.template.update(deleteSql, deleteFields); final String insertSql = "INSERT INTO event_trigger_subscription (uuid, event_trigger_uuid, " + "subscriber_uuid, delay_seconds, repeat_seconds, send_initial_occurrence)" + " VALUES(:uuid,:event_trigger_uuid,:subscriber_uuid,:delay_seconds,:repeat_seconds," + ":send_initial_occurrence)"; final String updateSql = "UPDATE event_trigger_subscription SET delay_seconds=:delay_seconds, " + "repeat_seconds=:repeat_seconds, send_initial_occurrence=:send_initial_occurrence" + " WHERE event_trigger_uuid=:event_trigger_uuid AND subscriber_uuid=:subscriber_uuid"; for (final Map<String, Object> fields : subscriptionFields) { numRows += DaoUtils.insertOrUpdate(this.nestedTransactionService, template, insertSql, updateSql, fields); } } return numRows; } }