org.hyperic.hq.events.server.session.EventLogDAO.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.events.server.session.EventLogDAO.java

Source

/*
 * 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;
    }

}