package org.openstack.atlas.service.domain.repository; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.ejb.criteria.OrderImpl; import org.openstack.atlas.service.domain.entities.AccountUsage; import org.openstack.atlas.service.domain.entities.AccountUsage_; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import javax.persistence.TemporalType; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.List; @Repository @Transactional public class AccountUsageRepository { final Log LOG = LogFactory.getLog(AccountUsageRepository.class); @PersistenceContext(unitName = "loadbalancing") private EntityManager entityManager; private final Integer NUM_DAYS_RETENTION = 120; public void save(AccountUsage accountUsage) { entityManager.persist(accountUsage); } public void updatePushedRecord(AccountUsage usageRecord) { LOG.info(String.format("updateEntryRecord called")); entityManager.merge(usageRecord); } public void batchUpdate(List<AccountUsage> usages) { LOG.info(String.format("batchUpdate() called with %d records", usages.size())); String query = generateBatchUpdateQuery(usages); // LOG.info("QUERY: " + query); entityManager.createNativeQuery(query).executeUpdate(); } private String generateBatchUpdateQuery(List<AccountUsage> usages) { final StringBuilder sb = new StringBuilder(); sb.append("REPLACE INTO account_usage(id, account_id, num_loadbalancers, num_public_vips, num_servicenet_vips, start_time, needs_pushed) values"); sb.append(generateFormattedValues(usages)); return sb.toString(); } private String generateFormattedValues(List<AccountUsage> usages) { StringBuilder sb = new StringBuilder(); for (AccountUsage usage : usages) { sb.append(generateBaseFormattedValue(usage)); } if (sb.toString().endsWith(",")) { sb.deleteCharAt(sb.lastIndexOf(",")); } return sb.toString(); } private String generateBaseFormattedValue(AccountUsage usage) { StringBuilder sb = new StringBuilder(); sb.append("("); if (usage.getId() != null) { sb.append(usage.getId()).append(","); } sb.append(usage.getAccountId()).append(","); sb.append(usage.getNumLoadBalancers()).append(","); sb.append(usage.getNumPublicVips()).append(","); sb.append(usage.getNumServicenetVips()).append(","); DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String startTime = formatter.format(usage.getStartTime().getTime()); sb.append("'").append(startTime).append("',"); sb.append(usage.isNeedsPushed()); sb.append("),"); return sb.toString(); } public void deleteAllRecordsBefore(Calendar time) { Query query = entityManager.createQuery("DELETE AccountUsage u WHERE u.endTime < :timestamp") .setParameter("timestamp", time, TemporalType.TIMESTAMP); int numRowsDeleted = query.executeUpdate(); LOG.info(String.format("Deleted %d rows with endTime before %s", numRowsDeleted, time.getTime())); } public void deleteOldRecords() { Calendar deletePoint = Calendar.getInstance(); deletePoint.add(Calendar.DATE, -NUM_DAYS_RETENTION); deleteAllRecordsBefore(deletePoint); } public List<AccountUsage> getAccountUsageRecords(Calendar startTime, Calendar endTime, Integer offset, Integer limit) { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<AccountUsage> criteria = builder.createQuery(AccountUsage.class); Root<AccountUsage> lbRoot = criteria.from(AccountUsage.class); Predicate betweenDates = builder.between(lbRoot.get(AccountUsage_.startTime), startTime, endTime); criteria.select(lbRoot); criteria.where(betweenDates); criteria.orderBy(new OrderImpl(lbRoot.get(AccountUsage_.accountId), true), new OrderImpl(lbRoot.get(AccountUsage_.startTime), true)); return entityManager.createQuery(criteria).setFirstResult(offset).setMaxResults(limit + 1).getResultList(); } }