/* * NOTE: This copyright does *not* cover user programs that use Hyperic * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004-2011], VMware, Inc. * This file is part of Hyperic. * * Hyperic is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.hq.events.server.session; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.hyperic.hibernate.PageInfo; import org.hyperic.hq.authz.server.session.Resource; import org.hyperic.hq.authz.shared.AuthzConstants; import org.hyperic.hq.authz.shared.PermissionManager; import org.hyperic.hq.authz.shared.PermissionManagerFactory; import org.hyperic.hq.dao.HibernateDAO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @Repository public class AlertDAO extends HibernateDAO<Alert> { private AlertActionLogDAO alertActionLogDAO; private PermissionManager permissionManager; @Autowired public AlertDAO(SessionFactory f, AlertActionLogDAO alertActionLogDAO, PermissionManager permissionManager) { super(Alert.class, f); this.alertActionLogDAO = alertActionLogDAO; this.permissionManager = permissionManager; } int deleteByIds(Integer[] ids) { String sql = "delete Alert where id in (:ids)"; return getSession().createQuery(sql).setParameterList("ids", ids).executeUpdate(); } public Alert get(Integer id) { return (Alert) super.get(id); } /** * @param before (in ms) - deletes all alerts with ctime < before * @param maxDeletes - max number of rows to delete. if maxDeletes <= 0, 0 is returned * @return number of rows deleted */ @SuppressWarnings("unchecked") int deleteAlertsByCreateTime(long before, int maxDeletes) { if (maxDeletes <= 0) { return 0; } // don't want to thrash the Alert cache, so select and do an explicit // remove() on each Object final String hql = new StringBuilder(64) .append("from Alert where ") .append("ctime < :before and ") .append("not id in (select alertId from EscalationState es ") .append("where alertTypeEnum = :type)") .toString(); List<Alert> list = null; int count = 0; // due to // http://opensource.atlassian.com/projects/hibernate/browse/HHH-1985 // need to batch this while (list == null || count < maxDeletes) { int batchSize = (BATCH_SIZE + count > maxDeletes) ? (maxDeletes - count) : BATCH_SIZE; list = getSession().createQuery(hql) .setLong("before", before) .setInteger("type", ClassicEscalationAlertType.CLASSIC.getCode()) .setMaxResults(batchSize) .list(); if (list.size() == 0) { break; } alertActionLogDAO.deleteAlertActions(list); for (Alert alert : list) { count++; remove(alert); } // need to flush or else the removed alerts won't be reflected in the next hql getSession().flush(); if (count >= maxDeletes) { break; } } return count; } public List<Alert> findByResource(Resource res) { return findByResource(res, "a.ctime DESC"); } @SuppressWarnings("unchecked") List<Alert> findEscalatables() { String sql = "from Alert a"; return getSession().createQuery(sql).list(); } /** * @return {@link List} of {@link Alert}s XXX scottmf [HQ-1785] this leads * bloating the session when it queries too many alerts and causes * an OOM. To fix we'd have to do something along the lines of only * querying alertIds and then the caller would have to do a * findById(alertId), process it, then immediately evict from the * session */ @SuppressWarnings("unchecked") List<Alert> findByCreateTimeAndPriority(Integer subj, long begin, long end, int priority, boolean inEsc, boolean notFixed, Integer groupId, Integer alertDefId, PageInfo pageInfo) { AlertSortField sort = (AlertSortField) pageInfo.getSort(); String sql = PermissionManagerFactory.getInstance().getAlertsHQL(inEsc, notFixed, groupId, null, alertDefId, false) + " order by " + sort.getSortString("a", "d", "r") + (pageInfo.isAscending() ? "" : " DESC"); // If sorting by something other than date, do a secondary sort by // date, descending if (!sort.equals(AlertSortField.DATE)) { sql += ", " + AlertSortField.DATE.getSortString("a", "d", "r") + " DESC"; } Query q = getSession().createQuery(sql).setLong("begin", begin).setLong("end", end).setInteger( "priority", priority); // HHQ-2781: acknowledgeable state is stale from query cache // .setCacheable(true) // .setCacheRegion("Alert.findByCreateTime"); if (sql.indexOf("subj") > 0) { q.setInteger("subj", subj.intValue()).setParameterList("ops", AuthzConstants.VIEW_ALERTS_OPS); } return pageInfo.pageResults(q).list(); } Map<Integer,List<Alert>> getUnfixedByResource(Integer subj, long begin, long end, int priority, boolean inEsc, boolean notFixed) { String sql = PermissionManagerFactory.getInstance().getAlertsHQL(inEsc, notFixed, null, null, null, false); Query q = getSession().createQuery(sql) .setLong("begin", begin) .setLong("end", end) .setInteger("priority", priority); if (sql.indexOf("subj") > 0) { q.setInteger("subj", subj.intValue()).setParameterList("ops", AuthzConstants.VIEW_ALERTS_OPS); } List<Alert> alerts = q.list(); Map<Integer,List<Alert>> lastAlerts = new HashMap<Integer,List<Alert>>(); for (Alert a : alerts ) { List<Alert> alertsByResource = lastAlerts.get(a.getAlertDefinition().getResource().getId()); if (alertsByResource == null) { alertsByResource = new ArrayList<Alert>(); lastAlerts.put(a.getAlertDefinition().getResource().getId(), alertsByResource); } alertsByResource.add(a); } return lastAlerts; } @SuppressWarnings("unchecked") public List<Alert> findByAppdefEntityInRange(Resource res, long begin, long end, boolean nameSort, boolean asc) { String sql = "from Alert a where a.alertDefinition.resource = :res " + "and a.ctime between :begin and :end order by " + (nameSort ? "a.alertDefinition.name" : "a.ctime") + (asc ? " asc" : " desc"); return getSession().createQuery(sql).setParameter("res", res).setLong("begin", begin) .setLong("end", end).list(); } @SuppressWarnings("unchecked") private List<Alert> findByResource(Resource res, String orderBy) { String sql = "from Alert a WHERE a.alertDefinition.resource = :res " + "ORDER BY " + orderBy; return getSession().createQuery(sql).setParameter("res", res).setCacheable(true) .setCacheRegion("Alert.findByEntity").list(); } public List<Alert> findByResourceSortByAlertDef(Resource res) { return findByResource(res, "a.alertDefinition.name DESC"); } public Alert findByAlertDefinitionAndCtime(AlertDefinition def, long ctime) { String sql = "from Alert a WHERE a.alertDefinition = :alertDef " + "and a.ctime = :ctime"; return (Alert) getSession().createQuery(sql).setParameter("alertDef", def).setLong("ctime", ctime).uniqueResult(); } @SuppressWarnings("unchecked") public List<Alert> findByAlertDefinition(AlertDefinition def) { String sql = "from Alert a WHERE a.alertDefinition = :alertDef"; return getSession().createQuery(sql).setParameter("alertDef", def).list(); } public Alert findLastByDefinition(AlertDefinition def, boolean fixed) { try { return (Alert) createCriteria().add(Restrictions.eq("alertDefinition", def)).add( Restrictions.eq("fixed", new Boolean(fixed))).addOrder(Order.desc("ctime")) .setMaxResults(1).uniqueResult(); } catch (Exception e) { return null; } } public Alert findLastByDefinition(AlertDefinition def) { try { return (Alert) createCriteria() .add(Restrictions.eq("alertDefinition", def)) .addOrder(Order.desc("ctime")) .setMaxResults(1) .uniqueResult(); } catch (Exception e) { return null; } } /** * Return all last unfixed alerts * * @return */ @SuppressWarnings("unchecked") public Map<Integer,Alert> findAllLastUnfixed() { String hql = new StringBuilder() .append("select a ") .append("from Alert a ") .append("join a.alertDefinition ad ") .append("where ad.deleted = false ") .append("and a.fixed = false ") .append("order by a.ctime ") .toString(); List<Alert> alerts = createQuery(hql).list(); Map<Integer,Alert> lastAlerts = new HashMap<Integer,Alert>(alerts.size()); for (Alert a : alerts ) { // since it is ordered by ctime in ascending order, the // last alert will eventually be put into the map lastAlerts.put(a.getAlertDefinition().getId(), a); } return lastAlerts; } /** * Return all last fixed alerts for the given resource * * @param subject The HQ user * @param r The root resource * @param fixed Boolean to indicate whether to get fixed or unfixed alerts * @return */ @SuppressWarnings("unchecked") public Map<Integer,Alert> findLastByResource(Collection<Resource> resources, boolean fixed) { final String hql = new StringBuilder(256) .append("select max(a.ctime), a ") .append("from Alert a ") .append("join a.alertDefinition ad ") .append("where ad.resource in (:resources) ") .append("and ad.deleted = false ") .append("and a.fixed = :fixed ") .append("group by a") .toString(); final List<Object[]> alerts = createQuery(hql) .setBoolean("fixed", fixed) .setParameterList("resources", resources) .list(); final Map<Integer,Alert> lastAlerts = new HashMap<Integer,Alert>(); for (final Object[] o : alerts ) { final Alert a = (Alert) o[1]; lastAlerts.put(a.getAlertDefinition().getId(), a); } return lastAlerts; } /** * @param {@link List} of {@link AlertDefinition}s * Deletes all {@link Alert}s associated with the {@link AlertDefinition}s */ int deleteByAlertDefinitions(List<AlertDefinition> alertDefs) { String sql = "DELETE FROM Alert WHERE alertDefinition in (:alertDefs)"; int rtn = 0; for (int i=0; i<alertDefs.size(); i+=BATCH_SIZE) { int end = Math.min(i+BATCH_SIZE, alertDefs.size()); rtn += getSession().createQuery(sql) .setParameterList("alertDefs", alertDefs.subList(i, end)) .executeUpdate(); } return rtn; } /** * Deletes all {@link Alert}s associated with the {@link AlertDefinition} */ int deleteByAlertDefinition(AlertDefinition def) { String sql = "DELETE FROM Alert WHERE alertDefinition = :alertDef"; return getSession().createQuery(sql).setParameter("alertDef", def).executeUpdate(); } public Integer countAlerts(AlertDefinition def) { return (Integer) createCriteria().add(Restrictions.eq("alertDefinition", def)) .setProjection(Projections.rowCount()).uniqueResult(); } public Integer countAlerts(Resource res) { return (Integer) createCriteria().createAlias("alertDefinition", "d").add( Restrictions.eq("d.resource", res)).setProjection(Projections.rowCount()) .uniqueResult(); } public void save(Alert alert) { super.save(alert); AlertDefinition def = alert.getAlertDefinition(); // Update the last fired time if (def.getLastFired() < alert.getCtime()) def.setLastFired(alert.getCtime()); } }