/*****************************************************************************
*
* Copyright (C) Zenoss, Inc. 2010-2011, 2014 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 com.codahale.metrics.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.simple.SimpleJdbcOperations;
import org.zenoss.protobufs.zep.Zep.Event;
import org.zenoss.protobufs.zep.Zep.EventDetailSet;
import org.zenoss.protobufs.zep.Zep.EventNote;
import org.zenoss.protobufs.zep.Zep.EventSummary;
import org.zenoss.utils.dao.RangePartitioner;
import org.zenoss.zep.UUIDGenerator;
import org.zenoss.zep.ZepConstants;
import org.zenoss.zep.ZepException;
import org.zenoss.zep.annotations.TransactionalReadOnly;
import org.zenoss.zep.annotations.TransactionalRollbackAllExceptions;
import org.zenoss.zep.dao.EventArchiveDao;
import org.zenoss.zep.dao.EventBatch;
import org.zenoss.zep.dao.EventBatchParams;
import org.zenoss.zep.dao.impl.compat.DatabaseCompatibility;
import org.zenoss.zep.dao.impl.compat.TypeConverter;
import org.zenoss.zep.dao.impl.compat.TypeConverterUtils;
import org.zenoss.zep.plugins.EventPreCreateContext;
import java.lang.reflect.Proxy;
import javax.sql.DataSource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static org.zenoss.zep.dao.impl.EventConstants.*;
public class EventArchiveDaoImpl implements EventArchiveDao {
@SuppressWarnings("unused")
private static Logger logger = LoggerFactory.getLogger(EventArchiveDaoImpl.class);
private final SimpleJdbcOperations template;
private EventDaoHelper eventDaoHelper;
private UUIDGenerator uuidGenerator;
private final DatabaseCompatibility databaseCompatibility;
private final TypeConverter<String> uuidConverter;
private final PartitionTableConfig partitionTableConfig;
private final RangePartitioner partitioner;
public EventArchiveDaoImpl(DataSource dataSource, PartitionConfig partitionConfig,
DatabaseCompatibility databaseCompatibility) {
this.template = (SimpleJdbcOperations) Proxy.newProxyInstance(SimpleJdbcOperations.class.getClassLoader(),
new Class<?>[] {SimpleJdbcOperations.class}, new SimpleJdbcTemplateProxy(dataSource));
this.partitionTableConfig = partitionConfig
.getConfig(TABLE_EVENT_ARCHIVE);
this.databaseCompatibility = databaseCompatibility;
this.uuidConverter = databaseCompatibility.getUUIDConverter();
this.partitioner = databaseCompatibility.getRangePartitioner(dataSource,
TABLE_EVENT_ARCHIVE, COLUMN_LAST_SEEN,
partitionTableConfig.getPartitionDuration(),
partitionTableConfig.getPartitionUnit());
}
public void setEventDaoHelper(EventDaoHelper eventDaoHelper) {
this.eventDaoHelper = eventDaoHelper;
}
public void setUuidGenerator(UUIDGenerator uuidGenerator) {
this.uuidGenerator = uuidGenerator;
}
@Override
@TransactionalRollbackAllExceptions
@Timed
public String create(Event event, EventPreCreateContext context) throws ZepException {
if (!ZepConstants.CLOSED_STATUSES.contains(event.getStatus())) {
throw new ZepException("Invalid status for event in event archive: " + event.getStatus());
}
TypeConverter<Long> timestampConverter = databaseCompatibility.getTimestampConverter();
Map<String, Object> occurrenceFields = eventDaoHelper.createOccurrenceFields(event);
Map<String, Object> fields = new HashMap<String,Object>(occurrenceFields);
final long created = event.getCreatedTime();
final long firstSeen = (event.hasFirstSeenTime()) ? event.getFirstSeenTime() : created;
long updateTime = System.currentTimeMillis();
final String uuid = this.uuidGenerator.generate().toString();
fields.put(COLUMN_UUID, uuidConverter.toDatabaseType(uuid));
fields.put(COLUMN_STATUS_ID, event.getStatus().getNumber());
fields.put(COLUMN_FIRST_SEEN, timestampConverter.toDatabaseType(firstSeen));
fields.put(COLUMN_STATUS_CHANGE, timestampConverter.toDatabaseType(created));
fields.put(COLUMN_LAST_SEEN, timestampConverter.toDatabaseType(created));
fields.put(COLUMN_EVENT_COUNT, event.getCount());
fields.put(COLUMN_UPDATE_TIME, timestampConverter.toDatabaseType(updateTime));
this.template.update(DaoUtils.createNamedInsert(TABLE_EVENT_ARCHIVE, fields.keySet()), fields);
return uuid;
}
@Override
@TransactionalReadOnly
@Timed
public EventSummary findByUuid(String uuid) throws ZepException {
final Map<String,Object> fields = Collections.singletonMap(COLUMN_UUID, uuidConverter.toDatabaseType(uuid));
List<EventSummary> summaries = this.template.query("SELECT * FROM event_archive WHERE uuid=:uuid",
new EventArchiveRowMapper(this.eventDaoHelper, databaseCompatibility), fields);
return (summaries.size() > 0) ? summaries.get(0) : null;
}
@Override
@TransactionalReadOnly
@Deprecated
@Timed
/** @deprecated use {@link #findByKey(Collection) instead}. */
public List<EventSummary> findByUuids(List<String> uuids)
throws ZepException {
Map<String, List<Object>> fields = Collections.singletonMap("uuids",
TypeConverterUtils.batchToDatabaseType(uuidConverter, uuids));
return this.template.query(
"SELECT * FROM event_archive WHERE uuid IN(:uuids)",
new EventArchiveRowMapper(this.eventDaoHelper, databaseCompatibility), fields);
}
@Override
@TransactionalReadOnly
@Timed
public List<EventSummary> findByKey(Collection<EventSummary> toLookup) throws ZepException {
ArrayList<Object> fields = new ArrayList<Object>(toLookup.size() * 2);
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM event_archive WHERE (");
int i = 0;
for (EventSummary event : toLookup) {
if (i++ > 0)
sql.append(" OR ");
sql.append("(uuid = ? AND last_seen = ?)");
fields.add(uuidConverter.toDatabaseType(event.getUuid()));
fields.add(event.getLastSeenTime());
}
sql.append(")");
return this.template.query(sql.toString(),
new EventArchiveRowMapper(this.eventDaoHelper, databaseCompatibility), fields.toArray());
}
@Override
@TransactionalReadOnly
@Timed
public EventBatch listBatch(EventBatchParams batchParams, long maxUpdateTime, int limit) throws ZepException {
return this.eventDaoHelper.listBatch(this.template, TABLE_EVENT_ARCHIVE, this.partitioner, batchParams, maxUpdateTime, limit,
new EventArchiveRowMapper(eventDaoHelper, databaseCompatibility));
}
@Override
@TransactionalRollbackAllExceptions
@Timed
public void initializePartitions() throws ZepException {
this.partitioner.createPartitions(
this.partitionTableConfig.getInitialPastPartitions(),
this.partitionTableConfig.getFuturePartitions());
}
@Override
@Timed
public long getPartitionIntervalInMs() {
return this.partitionTableConfig.getPartitionUnit().toMillis(
this.partitionTableConfig.getPartitionDuration());
}
@Override
@TransactionalRollbackAllExceptions
@Timed
public int addNote(String uuid, EventNote note) throws ZepException {
return this.eventDaoHelper.addNote(TABLE_EVENT_ARCHIVE, uuid, note, template);
}
@Override
@TransactionalRollbackAllExceptions
@Timed
public int updateDetails(String uuid, EventDetailSet details)
throws ZepException {
return this.eventDaoHelper.updateDetails(TABLE_EVENT_ARCHIVE, uuid, details.getDetailsList(), template);
}
@Override
@TransactionalRollbackAllExceptions
@Timed
public void purge(int duration, TimeUnit unit) throws ZepException {
this.partitioner.pruneAndCreatePartitions(duration,
unit,
this.partitionTableConfig.getInitialPastPartitions(),
this.partitionTableConfig.getFuturePartitions());
}
@Override
@TransactionalRollbackAllExceptions
@Timed
public void importEvent(EventSummary eventSummary) throws ZepException {
if (!ZepConstants.CLOSED_STATUSES.contains(eventSummary.getStatus())) {
throw new ZepException("Invalid status for event in event archive: " + eventSummary.getStatus());
}
final long updateTime = System.currentTimeMillis();
final EventSummary.Builder summaryBuilder = EventSummary.newBuilder(eventSummary);
final Event.Builder eventBuilder = summaryBuilder.getOccurrenceBuilder(0);
summaryBuilder.setUpdateTime(updateTime);
EventDaoHelper.addMigrateUpdateTimeDetail(eventBuilder, updateTime);
final EventSummary summary = summaryBuilder.build();
final Map<String,Object> fields = this.eventDaoHelper.createImportedSummaryFields(summary);
this.template.update(DaoUtils.createNamedInsert(TABLE_EVENT_ARCHIVE, fields.keySet()), fields);
}
}