/******************************************************************************* * Copyright (c) 2012-2015 INRIA. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Generoso Pagano - initial API and implementation ******************************************************************************/ package fr.inria.soctrace.lib.query; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.inria.soctrace.lib.model.Event; import fr.inria.soctrace.lib.model.EventParam; import fr.inria.soctrace.lib.model.EventParamType; import fr.inria.soctrace.lib.model.EventProducer; import fr.inria.soctrace.lib.model.EventType; import fr.inria.soctrace.lib.model.Link; import fr.inria.soctrace.lib.model.utils.ModelConstants.EventCategory; import fr.inria.soctrace.lib.model.utils.SoCTraceException; import fr.inria.soctrace.lib.query.conditions.ICondition; import fr.inria.soctrace.lib.storage.DBObject; import fr.inria.soctrace.lib.storage.TraceDBObject; import fr.inria.soctrace.lib.storage.utils.ModelElementCache; import fr.inria.soctrace.lib.storage.utils.SQLConstants.FramesocTable; import fr.inria.soctrace.lib.utils.DeltaManager; /** * Query class for Event self-defining-pattern tables. * * @author "Generoso Pagano <generoso.pagano@inria.fr>" * */ public class EventQuery extends SelfDefiningElementQuery { /** * Logger */ private final static Logger logger = LoggerFactory.getLogger(EventQuery.class); protected ICondition typeWhere; protected ICondition eventProducerWhere; private ModelElementCache eventProducerCache; protected boolean loadParameters; /** * The constructor * @param traceDB Trace DB object where the query is performed. */ public EventQuery(TraceDBObject traceDB) { super(traceDB); clear(); } /** * Clear query: removes all the conditions. * EventProducer cache is not cleared, since we are not changing trace DB. */ @Override public void clear() { super.clear(); this.typeWhere = null; this.eventProducerWhere = null; if (eventProducerCache != null) eventProducerCache.clear(); this.eventProducerCache = null; this.loadParameters = true; } @Override public String getElementTableName() { return FramesocTable.EVENT.toString(); } @Override public ParamType getParamType(String typeName, int typeId) throws SoCTraceException { return getEventParamType(typeName, typeId); } @Override public int getTypeId(String typeName) throws SoCTraceException { return getEventTypeId(typeName); } @Override public DBObject getDBObject() { return dbObj; } /** * @return the loadParameters */ public boolean isLoadParameters() { return loadParameters; } /** * @param loadParameters the loadParameters to set */ public void setLoadParameters(boolean loadParameters) { this.loadParameters = loadParameters; } /** * Set the condition to be put in the WHERE clause of EVENT_TYPE table. * @param typeCondition condition to be applied to the event type table */ public void setTypeWhere(ICondition typeCondition) { where = true; this.typeWhere = typeCondition; } /** * Set the condition to be put in the WHERE clause of EVENT_PRODUCER table. * @param eventProducerCondition condition to be applied to the event producer table */ public void setEventProducerWhere(ICondition eventProducerCondition) { where = true; this.eventProducerWhere = eventProducerCondition; } /** * Builds a list of Event respecting the condition specified by * elementWhere AND typeWhere AND eventProducerWhere AND parametersConditions. * The different parameter conditions are evaluated in OR, * since they refer to different event types so it makes no sense * having an AND. * @return the event list. * @throws SoCTraceException */ @Override public List<Event> getList() throws SoCTraceException { try { DeltaManager dm = new DeltaManager(); dm.start(); boolean first = true; StringBuilder eventQuery = null; eventQuery = new StringBuilder("SELECT * FROM " + FramesocTable.EVENT + " "); if (where) { eventQuery.append(" WHERE "); } if (elementWhere != null) { first = false; eventQuery.append(elementWhere.getSQLString()); } if (typeWhere != null) { if (!first) eventQuery.append(" AND "); else first = false; eventQuery.append("( EVENT_TYPE_ID IN ( SELECT ID FROM " + FramesocTable.EVENT_TYPE + " WHERE " + typeWhere.getSQLString() + " ) )"); } if (eventProducerWhere != null) { if (!first) eventQuery.append(" AND "); else first = false; eventQuery.append("( EVENT_PRODUCER_ID IN ( SELECT ID FROM " + FramesocTable.EVENT_PRODUCER + " WHERE " + eventProducerWhere.getSQLString() + " ) )"); } if (parametersConditions.size()>0) { if (!first) eventQuery.append(" AND "); else first = false; eventQuery.append(getParamConditionsString()); } if (orderBy) { eventQuery.append(" ORDER BY " + orderByColumn + " " + orderByCriterium); } if (isLimitSet()) { eventQuery.append(" LIMIT " + getLimit()); } String query = eventQuery.toString(); logger.debug(query); Statement stm = dbObj.getConnection().createStatement(); DeltaManager steps = new DeltaManager(); steps.start(); ResultSet rs = stm.executeQuery(query); logger.debug(steps.endMessage("Execute query")); List<Event> elist = null; steps.start(); elist = rebuildEvents(rs); logger.debug(steps.endMessage("Rebuilds events")); logger.debug(dm.endMessage("EventQuery.getList()")); logger.debug("Results: {}", elist.size()); stm.close(); return elist; } catch (SQLException e) { throw new SoCTraceException(e); } } /** * Load the parameters in the passed events. * The events must have no parameters, otherwise * an exception is thrown. * The events must have the event type with all the * parameter types properly set. * * @param elist list of events without parameters * @throws SoCTraceException */ public void loadParams(List<Event> elist) throws SoCTraceException { try { ValueListString vls = new ValueListString(); Map<Integer, Event> tmp = new HashMap<Integer, Event>(); for (Event e: elist) { tmp.put(e.getId(), e); vls.addValue(String.valueOf(e.getId())); } if (vls.size()==0) return; Statement stm = dbObj.getConnection().createStatement(); ResultSet prs = stm.executeQuery("SELECT * FROM " + FramesocTable.EVENT_PARAM + " WHERE EVENT_ID IN " + vls.getValueString()); while (prs.next()) { rebuildEventParam(prs, tmp); } stm.close(); } catch(SQLException e) { throw new SoCTraceException(e); } } /* * U t i l i t i e s */ /** * Get the event type id, given the event type name. * * TODO: this can be optimized with the type cache * @param name event type name * @return the corresponding event type ID * @throws SoCTraceException */ private int getEventTypeId(String name) throws SoCTraceException { try { Statement stm = dbObj.getConnection().createStatement(); ResultSet rs = stm.executeQuery("SELECT * FROM " + FramesocTable.EVENT_TYPE + " WHERE NAME='" + name + "'"); if (rs.next()) { return rs.getInt("ID"); } return -1; } catch (SQLException e) { throw new SoCTraceException(e); } } /** * Get the event param type with the given name, for the event type * whose ID is passed. * * TODO: this can be optimized with the type cache * @param name the event param type name * @param eventTypeId the event type ID * @return the corresponding event param type * @throws SoCTraceException */ private ParamType getEventParamType(String name, int eventTypeId) throws SoCTraceException { try { Statement stm = dbObj.getConnection().createStatement(); ResultSet rs = stm.executeQuery("SELECT * FROM " + FramesocTable.EVENT_PARAM_TYPE + " WHERE NAME='" + name + "' AND EVENT_TYPE_ID="+eventTypeId); if (rs.next()) { return new ParamType(rs.getInt("ID"), name, rs.getString("TYPE")); } return null; } catch (SQLException e) { throw new SoCTraceException(e); } } /** * Build the EventProducer object corresponding to the passed ID * @param id event producer ID * @return a EventProducer * @throws SoCTraceException */ protected EventProducer getEventProducer(int id) throws SoCTraceException { if (eventProducerCache==null) { eventProducerCache = new ModelElementCache(); eventProducerCache.addElementMap(EventProducer.class); } EventProducer eventProducer; if (( eventProducer = eventProducerCache.get(EventProducer.class, id)) != null) return eventProducer; try { Statement stm = dbObj.getConnection().createStatement(); ResultSet rs = stm.executeQuery("SELECT * FROM " + FramesocTable.EVENT_PRODUCER + " WHERE ID="+id); if (rs.next()) { eventProducer = new EventProducer(id); eventProducer.setType(rs.getString("TYPE")); eventProducer.setLocalId(rs.getString("LOCAL_ID")); eventProducer.setName(rs.getString("NAME")); eventProducer.setParentId(rs.getInt("PARENT_ID")); eventProducerCache.put(eventProducer); stm.close(); return eventProducer; } stm.close(); return null; } catch (SQLException e) { throw new SoCTraceException(e); } } /** * Rebuilds the events corresponding to the result set. * @param rs Result set corresponding to a SELECT * FROM EVENT ... * @return a list of Event * @throws SoCTraceException */ private List<Event> rebuildEvents(ResultSet rs) throws SoCTraceException { ValueListString vls = new ValueListString(); List<Event> list = new LinkedList<Event>(); Map<Integer, Event> tmp = new HashMap<Integer, Event>(); try { while (rs.next()) { Event e = rebuildEvent(rs); list.add(e); if (loadParameters) { // to rebuild all params tmp.put(e.getId(), e); vls.addValue(String.valueOf(e.getId())); } } if (vls.size()==0) return list; if (loadParameters) { DeltaManager dm = new DeltaManager(); dm.start(); Statement stm = dbObj.getConnection().createStatement(); ResultSet prs = stm.executeQuery("SELECT * FROM " + FramesocTable.EVENT_PARAM + " WHERE EVENT_ID IN " + vls.getValueString()); while (prs.next()) { rebuildEventParam(prs, tmp); } logger.debug(dm.endMessage("Rebuild parameters and link to events")); stm.close(); } return list; } catch (SQLException e) { throw new SoCTraceException(e); } } /** * Rebuild an Event, given the corresponding EVENT table row. * * @param rs EVENT table row * @param epVls * @return the Event * @throws SQLException * @throws SoCTraceException */ private Event rebuildEvent(ResultSet rs) throws SQLException, SoCTraceException { int category = rs.getInt(7); Event e = Event.createCategorizedEvent(category, rs.getInt(1)); TraceDBObject traceDB = (TraceDBObject)dbObj; EventType et = traceDB.getEventTypeCache().get(EventType.class, rs.getInt(2)); EventProducer s = getEventProducer(rs.getInt(3)); e.setEventProducer(s); e.setCategory(rs.getInt(7)); e.setType(et); e.setTimestamp(rs.getLong(4)); e.setCpu(rs.getInt(5)); e.setPage(rs.getInt(6)); e.setLongPar(rs.getLong(8)); e.setDoublePar(rs.getDouble(9)); if (e.getCategory() == EventCategory.LINK){ ((Link)e).setEndProducer(getEventProducer(((Double)e.getDoublePar()).intValue())); } return e; } /** * Rebuild an EventParam, given the corresponding EVENT_PARAM table row. * @param prs EVENT_PARAM table row * @param tmp map containing the Events returned by the query * @return the EventParam * @throws SQLException * @throws SoCTraceException */ private EventParam rebuildEventParam(ResultSet prs, Map<Integer, Event> tmp) throws SQLException, SoCTraceException { EventParam ep = new EventParam(prs.getInt(1)); ep.setEvent(tmp.get(prs.getInt(2))); TraceDBObject traceDB = (TraceDBObject)dbObj; ep.setEventParamType(traceDB.getEventTypeCache().get(EventParamType.class, prs.getInt(3))); ep.setValue(prs.getString(4)); return ep; } }