Java tutorial
/* * NOTE: This copyright does *not* cover user programs that use HQ * 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-2007], Hyperic, Inc. * This file is part of HQ. * * HQ 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.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hyperic.hibernate.PageInfo; import org.hyperic.hibernate.dialect.HQDialect; import org.hyperic.hq.appdef.shared.AppdefUtil; import org.hyperic.hq.authz.server.session.AuthzSubject; import org.hyperic.hq.authz.server.session.Resource; import org.hyperic.hq.authz.server.session.ResourceGroup; import org.hyperic.hq.authz.shared.AuthzConstants; import org.hyperic.hq.authz.shared.EdgePermCheck; import org.hyperic.hq.authz.shared.PermissionManager; import org.hyperic.hq.authz.shared.PermissionManagerFactory; import org.hyperic.hq.authz.shared.PermissionManager.RolePermNativeSQL; import org.hyperic.hq.dao.HibernateDAO; import org.hyperic.hq.events.AlertFiredEvent; import org.hyperic.hq.events.EventLogStatus; import org.hyperic.hq.measurement.server.session.Number; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @Repository public class EventLogDAO extends HibernateDAO<EventLog> { private final String TABLE_EVENT_LOG = "EAM_EVENT_LOG"; private final String TABLE_EAM_NUMBERS = "EAM_NUMBERS"; private PermissionManager permissionManager; private final Log log = LogFactory.getLog(EventLogDAO.class.getName()); private static final List<String> VIEW_PERMISSIONS = Arrays .asList(new String[] { AuthzConstants.platformOpViewPlatform, AuthzConstants.serverOpViewServer, AuthzConstants.serviceOpViewService, AuthzConstants.groupOpViewResourceGroup, }); private static final List<String> MANAGE_ALERT_PERMISSIONS = Arrays .asList(new String[] { AuthzConstants.platformOpManageAlerts, AuthzConstants.serverOpManageAlerts, AuthzConstants.serviceOpManageAlerts, AuthzConstants.groupOpManageAlerts }); @Autowired public EventLogDAO(SessionFactory f, PermissionManager permissionManager) { super(EventLog.class, f); this.permissionManager = permissionManager; } EventLog create(EventLog res) { if (res.getResource() != null) save(res); return res; } public static class ResourceEventLog { private Resource _r; private EventLog _e; ResourceEventLog(Resource r, EventLog e) { _r = r; _e = e; } public Resource getResource() { return _r; } public EventLog getEventLog() { return _e; } } EventLog findLog(String typeClass, int instanceId, long timestamp) { String hql = "select l from EventLog l where l.timestamp = :ts " + "and l.instanceId = :instId and l.type = :type"; Query q = createQuery(hql).setLong("ts", timestamp).setInteger("instId", instanceId).setString("type", typeClass); List<EventLog> events = q.list(); if (events.isEmpty()) { return null; } if (events.size() > 1) { log.warn("Found multiple log entries matching the specified " + "criteria (typeClass=" + typeClass + ", instanceId=" + instanceId + ", timestamp=" + timestamp + "). Returning the first one."); } return (EventLog) events.iterator().next(); } /** * Gets a list of {@link ResourceEventLog}s. Most arguments are required. * pInfo is required to have a sort field of type {@link EventLogSortField} * * @param typeClass Not required. If specified, the results will all be of * this class (.org.hy...ResourceLogEvent) * @param inGroups Not required. If specified, a list of * {@link ResourceGroup}s which will contain the resulting logs */ List<ResourceEventLog> findLogs(AuthzSubject subject, long begin, long end, PageInfo pInfo, EventLogStatus maxStatus, String typeClass, Collection<ResourceGroup> inGroups) { EventLogSortField sort = (EventLogSortField) pInfo.getSort(); boolean doGroupFilter = false; String groupFilterSql; RolePermNativeSQL roleSql = PermissionManagerFactory.getInstance().getRolePermissionNativeSQL("r", "e", "subject", "opListVR", "opListMA"); if (inGroups == null || inGroups.isEmpty()) groupFilterSql = ""; else { doGroupFilter = true; groupFilterSql = " and exists ( " + "select rgm.resource_id from EAM_RES_GRP_RES_MAP rgm " + " join EAM_RESOURCE_GROUP g on rgm.resource_group_id = g.id " + " where rgm.resource_id = r.id and g.id in (:inGroups) " + "union all " + " select g2.resource_id from EAM_RESOURCE_GROUP g2 " + " where g2.resource_id = r.id and g2.id in (:inGroups) " + ") "; } String sql = "select {e.*}, r.* " + "from EAM_RESOURCE r " + " join EAM_RESOURCE_TYPE rt on r.resource_type_id = rt.id " + " join EAM_EVENT_LOG e on e.resource_id = r.id " + "where " + " e.timestamp between :begin and :end " + groupFilterSql + roleSql.getSQL() + " and " + " case " + " when e.status = 'ANY' then -1 " + " when e.status = 'ERR' then 3 " + " when e.status = 'WRN' then 4 " + " when e.status = 'INF' then 6 " + " when e.status = 'DBG' then 7 " + " else -1 " + " end <= :maxStatus "; if (typeClass != null) { sql += " and type = :type "; } sql += " order by " + sort.getSortString("r", "e") + (pInfo.isAscending() ? "" : " DESC"); if (!sort.equals(EventLogSortField.DATE)) { sql += ", " + EventLogSortField.DATE.getSortString("r", "e") + " DESC"; } Query q = getSession().createSQLQuery(sql).addEntity("e", EventLog.class).setLong("begin", begin) .setLong("end", end).setInteger("maxStatus", maxStatus.getCode()); roleSql.bindParams(q, subject, VIEW_PERMISSIONS, MANAGE_ALERT_PERMISSIONS); if (typeClass != null) { q.setString("type", typeClass); } if (doGroupFilter) { List<Integer> inGroupIds = new ArrayList<Integer>(inGroups.size()); for (ResourceGroup g : inGroups) { inGroupIds.add(g.getId()); } q.setParameterList("inGroups", inGroupIds); } List<EventLog> vals = pInfo.pageResults(q).list(); List<ResourceEventLog> res = new ArrayList<ResourceEventLog>(vals.size()); for (EventLog e : vals) { res.add(new ResourceEventLog(e.getResource(), e)); } return res; } /** * @return 0 if there are no unfixed alerts */ private final long getOldestUnfixedAlertTime() { Object o = getSession().createQuery("select min(ctime) from Alert where fixed = '0'").uniqueResult(); if (o == null) { return 0; } return ((Long) o).longValue(); } /** * @return {@link Map} of {@link Integer} = AlertDefitionId to * {@link Map} of <br> * key {@link AlertInfo} <br> * value {@link Integer} AlertId */ @SuppressWarnings("unchecked") private final Map<Integer, Map<AlertInfo, Integer>> getUnfixedAlertInfoAfter(long ctime) { final String hql = new StringBuilder(128).append("SELECT alertDefinition.id, id, ctime ") .append("FROM Alert WHERE ctime >= :ctime and fixed = '0' ").append("ORDER BY ctime").toString(); final List<Object[]> list = getSession().createQuery(hql).setLong("ctime", ctime).list(); final Map<Integer, Map<AlertInfo, Integer>> alerts = new HashMap<Integer, Map<AlertInfo, Integer>>( list.size()); for (Object[] obj : list) { Map<AlertInfo, Integer> tmp = alerts.get(obj[0]); if (tmp == null) { tmp = new HashMap<AlertInfo, Integer>(); alerts.put((Integer) obj[0], tmp); } final AlertInfo ai = new AlertInfo((Integer) obj[0], (Long) obj[2]); tmp.put(ai, (Integer) obj[1]); } return alerts; } private class AlertInfo { private final Integer _alertDefId; private final Long _ctime; AlertInfo(Integer alertDefId, Long ctime) { _alertDefId = alertDefId; _ctime = ctime; } AlertInfo(Integer alertDefId, long ctime) { _alertDefId = alertDefId; _ctime = new Long(ctime); } Integer getAlertDefId() { return _alertDefId; } Long getCtime() { return _ctime; } public boolean equals(Object rhs) { if (rhs == this) { return true; } if (rhs instanceof AlertInfo) { AlertInfo obj = (AlertInfo) rhs; return obj.getCtime().equals(_ctime) && obj.getAlertDefId().equals(_alertDefId); } return false; } public int hashCode() { return 17 * _alertDefId.hashCode() + _ctime.hashCode(); } } /** * Find unfixed AlertFiredEvent event logs for each alert definition in the list * * @param alertDefinitionIds The list of alert definition ids * * @return {@link Map} of {@link Integer} = AlertDefinitionId to * {@link AlertFiredEvent} */ @SuppressWarnings("unchecked") Map<Integer, AlertFiredEvent> findUnfixedAlertFiredEventLogs() { final Map<Integer, AlertFiredEvent> rtn = new HashMap<Integer, AlertFiredEvent>(); final long ctime = getOldestUnfixedAlertTime(); if (ctime == 0) { return new HashMap<Integer, AlertFiredEvent>(0, 1); } final Map<Integer, Map<AlertInfo, Integer>> alerts = getUnfixedAlertInfoAfter(ctime); final String hql = new StringBuilder(256).append("FROM EventLog ") .append("WHERE timestamp >= :ctime AND type = :type ").append("AND instanceId is not null") .toString(); final List<EventLog> list = getSession().createQuery(hql).setString("type", AlertFiredEvent.class.getName()) .setLong("ctime", ctime).list(); for (EventLog log : list) { if (log == null || log.getInstanceId() == null) { continue; } final Map<AlertInfo, Integer> objs = alerts.get(log.getInstanceId()); if (objs == null) { continue; } final Integer alertDefId = log.getInstanceId(); final long timestamp = log.getTimestamp(); final Integer alertId = objs.get(new AlertInfo(alertDefId, timestamp)); if (alertId == null) { continue; } if (log.getResource().isInAsyncDeleteState()) { continue; } AlertFiredEvent alertFired = createAlertFiredEvent(alertDefId, alertId, log); rtn.put(alertDefId, alertFired); } return rtn; } private final AlertFiredEvent createAlertFiredEvent(Integer alertDefId, Integer alertId, EventLog eventLog) { return new AlertFiredEvent(alertId, alertDefId, AppdefUtil.newAppdefEntityId(eventLog.getResource()), eventLog.getSubject(), eventLog.getTimestamp(), eventLog.getDetail()); } List<EventLog> findByEntityAndStatus(Resource r, AuthzSubject user, long begin, long end, String status) { EdgePermCheck wherePermCheck = permissionManager.makePermCheckHql("rez", false); String hql = "select l from EventLog l " + "join l.resource rez " + wherePermCheck + "and l.timestamp between :begin and :end " + "and l.status = :status " + "order by l.timestamp"; Query q = createQuery(hql).setParameter("status", status).setLong("begin", begin).setLong("end", end); return wherePermCheck.addQueryParameters(q, user, r, 0, VIEW_PERMISSIONS).list(); } List<EventLog> findByEntity(AuthzSubject subject, Resource r, long begin, long end, Collection<String> eventTypes) { EdgePermCheck wherePermCheck = permissionManager.makePermCheckHql("rez", false); String hql = " select l from EventLog l " + "join l.resource rez " + wherePermCheck + "and l.timestamp between :begin and :end "; if (!eventTypes.isEmpty()) hql += "and l.type in (:eventTypes) "; hql += "order by l.timestamp"; Query q = createQuery(hql).setLong("begin", begin).setLong("end", end); if (!eventTypes.isEmpty()) q.setParameterList("eventTypes", eventTypes); return wherePermCheck.addQueryParameters(q, subject, r, 0, VIEW_PERMISSIONS).list(); } List<EventLog> findByGroup(Resource g, long begin, long end, Collection<String> eventTypes) { String hql = "select l from EventLog l join l.resource res " + "left outer join res.groupBag gb " + "left outer join gb.group g " + "where (l.resource = :r or g.resource = :r) " + "and l.timestamp between :begin and :end "; if (!eventTypes.isEmpty()) hql += "and l.type in (:eventTypes) "; hql += "order by l.timestamp"; Query q = createQuery(hql).setParameter("r", g).setLong("begin", begin).setLong("end", end); if (!eventTypes.isEmpty()) q.setParameterList("eventTypes", eventTypes); return q.list(); } List<EventLog> findLastByType(Resource proto) { String hql = "select {ev.*} from EAM_EVENT_LOG ev, " + "(select resource_id, max(EAM_EVENT_LOG.timestamp) as maxt " + "from EAM_EVENT_LOG, EAM_RESOURCE res " + "where res.id = resource_id and " + "res.proto_id=:proto group by resource_id) l " + "where l.resource_id = ev.resource_id and l.maxt = ev.timestamp"; return getSession().createSQLQuery(hql).addEntity("ev", EventLog.class) .setInteger("proto", proto.getId().intValue()).list(); } List findBySubject(String subject) { String sql = "from EventLog e where e.subject = :subject"; return getSession().createQuery(sql).setParameter("subject", subject).list(); } /** * Retrieve the minimum timestamp amongst all event logs. * * @return The minimum timestamp or <code>-1</code> if there are no event * logs. */ long getMinimumTimeStamp() { String sql = "select min(l.timestamp) from EventLog l"; Long min = (Long) getSession().createQuery(sql).uniqueResult(); if (min == null) { return -1; } else { return min.longValue(); } } /** * Retrieve the total number of event logs. * * @return The total number of event logs. */ int getTotalNumberLogs() { String sql = "select count(*) from EventLog"; java.lang.Number result = (java.lang.Number) getSession().createQuery(sql).uniqueResult(); return result.intValue(); } /** * Delete event logs by resource. TODO: Chunking? * * @param r The resource in which to delete event logs * @return The number of entries deleted. */ int deleteLogs(Resource r) { String sql = "delete EventLog l where resource = :resource"; return getSession().createQuery(sql).setParameter("resource", r).executeUpdate(); } /** * Delete event logs in chunks. * * @param from The timestamp to delete from. * @param to The timestamp to delete to. * @param interval The timestamp interval (delta) by which the deletes are * chunked. * @return The number of event logs deleted. */ int deleteLogs(long from, long to, long interval) { String sql = "delete EventLog l where " + "l.timestamp >= :timeStart and l.timestamp <= :timeEnd"; int rowsDeleted = 0; Session session = getSession(); Query query = session.createQuery(sql); for (long cursor = from; cursor < to; cursor += interval) { long end = Math.min(to, cursor + interval); query.setLong("timeStart", cursor); query.setLong("timeEnd", end); rowsDeleted += query.executeUpdate(); session.flush(); } return rowsDeleted; } /** * Insert the event logs in batch, with batch size specified by the * <code>hibernate.jdbc.batch_size</code> configuration property. * * @param eventLogs The event logs to insert. */ void insertLogs(EventLog[] eventLogs) { Session session = getSession(); FlushMode flushMode = session.getFlushMode(); CacheMode cacheMode = session.getCacheMode(); try { session.setFlushMode(FlushMode.MANUAL); // We do not want to update the 2nd level cache with these event // logs session.setCacheMode(CacheMode.IGNORE); for (int i = 0; i < eventLogs.length; i++) { create(eventLogs[i]); } session.flush(); session.clear(); } finally { session.setFlushMode(flushMode); session.setCacheMode(cacheMode); } } private String getLogsExistSQL(Resource resource, long begin, long end, int intervals, EdgePermCheck wherePermCheck) { HQDialect dialect = getHQDialect(); StringBuilder sql = new StringBuilder(); String resVar = wherePermCheck.getResourceVar(); String permSql = wherePermCheck.getSql(); if (!dialect.useEamNumbers()) { for (int i = 0; i < intervals; i++) { sql.append("(SELECT ").append(i).append(" AS I FROM ").append(TABLE_EVENT_LOG).append(" evlog") .append(" JOIN EAM_RESOURCE ").append(resVar).append(" on ").append("evlog.resource_id = ") .append(resVar).append(".id").append(permSql) .append(" AND timestamp BETWEEN (:begin + (:interval * ").append(i) .append(")) AND ((:begin + (:interval * (").append(i).append(" + 1))) - 1)").append(" AND ") .append(resVar).append(".id = :resourceId ").append(dialect.getLimitString(1)).append(')'); if (i < intervals - 1) { sql.append(" UNION ALL "); } } } else { sql.append("SELECT i AS I FROM ").append(TABLE_EAM_NUMBERS).append(" WHERE i < ").append(intervals) .append(" AND EXISTS (").append("SELECT 1 FROM ").append(TABLE_EVENT_LOG).append(" evlog") .append(" JOIN EAM_RESOURCE ").append(resVar).append(" on ").append("evlog.resource_id = ") .append(resVar).append(".id").append(permSql) .append(" AND timestamp BETWEEN (:begin + (:interval") .append(" * i)) AND ((:begin + (:interval").append(" * (i + 1))) - 1)").append(" AND ") .append(resVar).append(".id = :resourceId ").append(dialect.getLimitString(1)).append(')'); } return sql.toString(); } boolean[] logsExistPerInterval(Resource resource, AuthzSubject subject, long begin, long end, int intervals) { long interval = (end - begin) / intervals; EdgePermCheck wherePermCheck = permissionManager.makePermCheckSql("rez", false); String sql = getLogsExistSQL(resource, begin, end, intervals, wherePermCheck); Query q = getSession().createSQLQuery(sql) .addEntity("I", org.hyperic.hq.measurement.server.session.Number.class) .setInteger("resourceId", resource.getId().intValue()).setLong("begin", begin) .setLong("interval", interval); List result = wherePermCheck.addQueryParameters(q, subject, resource, 0, VIEW_PERMISSIONS).list(); boolean[] eventLogsInIntervals = new boolean[intervals]; for (Iterator i = result.iterator(); i.hasNext();) { Number n = (Number) i.next(); eventLogsInIntervals[(int) n.getI()] = true; } return eventLogsInIntervals; } }