/*******************************************************************************
* 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 java.util.Set;
import fr.inria.soctrace.lib.model.AnalysisResultData;
import fr.inria.soctrace.lib.model.AnalysisResultGroupData;
import fr.inria.soctrace.lib.model.Event;
import fr.inria.soctrace.lib.model.EventParamType;
import fr.inria.soctrace.lib.model.EventType;
import fr.inria.soctrace.lib.model.Group;
import fr.inria.soctrace.lib.model.IGroupable;
import fr.inria.soctrace.lib.model.OrderedGroup;
import fr.inria.soctrace.lib.model.UnorderedGroup;
import fr.inria.soctrace.lib.model.utils.ModelConstants.ModelEntity;
import fr.inria.soctrace.lib.model.utils.SoCTraceException;
import fr.inria.soctrace.lib.query.conditions.ConditionsConstants.ComparisonOperation;
import fr.inria.soctrace.lib.query.conditions.SimpleCondition;
import fr.inria.soctrace.lib.storage.TraceDBObject;
import fr.inria.soctrace.lib.storage.utils.SQLConstants.FramesocTable;
/**
* Query class for Group analysis results.
*
* @author "Generoso Pagano <generoso.pagano@inria.fr>"
*
*/
public class AnalysisResultGroupDataQuery extends AnalysisResultDataQuery {
/**
* Utility class to store Target Entity ID
* and Sequence number.
*/
private class Entity {
public int mapping; // leaf mapping id
public int id; // entity id
public int seq; // sequence number
public Entity(int mapping, int id, int seq) {
this.mapping = mapping;
this.id = id;
this.seq = seq;
}
}
/* --------------------------- */
/* Three hierarchy management */
/**
* Map: GID - Group
*/
Map<Integer, Group> gidGroupMap = new HashMap<Integer, Group>();
/**
* Map: Parent GID - List of son GID
*/
Map<Integer, List<Integer>> pidGidMap = new HashMap<Integer, List<Integer>>();
/* Leaf entity management */
/**
* Map: GID - List of Entity son id with sequence number
*/
Map<Integer, List<Entity>> gidEntityListMap = new HashMap<Integer, List<Entity>>();
/**
* Map: Entity Class - Entity ID - Entity object
*/
Map<Class<? extends IGroupable>, Map<Integer, IGroupable>> eidEntityMap =
new HashMap<Class<? extends IGroupable>, Map<Integer, IGroupable>>();
/* --------------------------- */
/**
* The constructor.
*
* @param traceDB trace DB containing the result
*/
public AnalysisResultGroupDataQuery(TraceDBObject traceDB) {
super(traceDB);
}
@Override
public AnalysisResultData getAnalysisResultData(int analysisResultId) throws SoCTraceException {
try {
loadGroupMaps(analysisResultId);
loadEntityMaps(analysisResultId);
Integer rootId = pidGidMap.get(-1).iterator().next();
Group root = gidGroupMap.get(rootId);
getSons(root);
buildMapping();
clear();
return new AnalysisResultGroupData(root);
} catch (SQLException e) {
throw new SoCTraceException(e);
}
}
/**
* Load maps used to rebuild the tree structure.
*
* @param analysisResultId analysis result ID
* @throws SQLException
* @throws SoCTraceException
*/
private void loadGroupMaps(int analysisResultId) throws SQLException, SoCTraceException {
String query = "SELECT * FROM " + FramesocTable.ENTITY_GROUP +
" WHERE ANALYSIS_RESULT_ID = " + analysisResultId;
debug(query);
Statement stm = traceDB.getConnection().createStatement();
ResultSet rs = stm.executeQuery(query);
while (rs.next()) {
Group g = buildGroup(rs);
gidGroupMap.put(g.getId(), g);
if (!pidGidMap.containsKey(g.getParentId()))
pidGidMap.put(g.getParentId(), new LinkedList<Integer>());
pidGidMap.get(g.getParentId()).add(g.getId());
}
stm.close();
}
/**
* Load all the maps used for Entity management.
*
* @param analysisResultId analysis result ID
* @throws SQLException
* @throws SoCTraceException
*/
private void loadEntityMaps(int analysisResultId) throws SQLException, SoCTraceException {
// Entity Class - Value List String for Entity IDs
Map<Class<? extends IGroupable>, ValueListString> classVlsMap =
new HashMap<Class<? extends IGroupable>, ValueListString>();
String query = "SELECT * FROM " + FramesocTable.GROUP_MAPPING +
" WHERE ANALYSIS_RESULT_ID = " + analysisResultId;
debug(query);
Statement stm = traceDB.getConnection().createStatement();
ResultSet rs = stm.executeQuery(query);
while (rs.next()) {
int mid = rs.getInt(2); // mapping id
int gid = rs.getInt(3);
int eid = rs.getInt(4);
int seq = rs.getInt(5);
if (!gidEntityListMap.containsKey(gid))
gidEntityListMap.put(gid, new LinkedList<Entity>());
gidEntityListMap.get(gid).add(new Entity(mid, eid, seq));
Group g = gidGroupMap.get(gid);
Class<? extends IGroupable> c = g.getTargetClass();
if (!classVlsMap.containsKey(c))
classVlsMap.put(c, new ValueListString());
classVlsMap.get(c).addValue(String.valueOf(eid));
}
if (classVlsMap.containsKey(Event.class)) {
EventQuery eventQuery = new EventQuery(traceDB);
ValueListString vls = classVlsMap.get(Event.class);
eventQuery.setElementWhere(new SimpleCondition("ID", ComparisonOperation.IN, vls.getValueString()));
List<Event> elist = eventQuery.getList();
eidEntityMap.put(Event.class, new HashMap<Integer, IGroupable>());
Map<Integer, IGroupable> tmp = eidEntityMap.get(Event.class);
for (Event e: elist) {
tmp.put(e.getId(), e);
}
}
if (classVlsMap.containsKey(EventType.class)) {
EventTypeQuery eventTypeQuery = new EventTypeQuery(traceDB);
ValueListString vls = classVlsMap.get(EventType.class);
eventTypeQuery.setElementWhere(new SimpleCondition("ID", ComparisonOperation.IN, vls.getValueString()));
List<EventType> tlist = eventTypeQuery.getList();
eidEntityMap.put(EventType.class, new HashMap<Integer, IGroupable>());
Map<Integer, IGroupable> tmp = eidEntityMap.get(EventType.class);
for (EventType t: tlist) {
tmp.put(t.getId(), t);
}
}
if (classVlsMap.containsKey(EventParamType.class)) {
EventParamTypeQuery eventParamTypeQuery = new EventParamTypeQuery(traceDB);
ValueListString vls = classVlsMap.get(EventParamType.class);
eventParamTypeQuery.setElementWhere(new SimpleCondition("ID", ComparisonOperation.IN, vls.getValueString()));
List<EventParamType> tlist = eventParamTypeQuery.getList();
eidEntityMap.put(EventParamType.class, new HashMap<Integer, IGroupable>());
Map<Integer, IGroupable> tmp = eidEntityMap.get(EventParamType.class);
for (EventParamType t: tlist) {
tmp.put(t.getId(), t);
}
}
}
/**
* Build the tree hierarchy that follows a given node.
* This is a recursive function.
*
* @param g base of the three
* @throws SoCTraceException
*/
private void getSons(Group g) throws SoCTraceException {
// base case: group without son groups
if (!pidGidMap.containsKey(g.getId()))
return;
// general case: group with son groups
boolean ordered = (g instanceof OrderedGroup);
List<Integer> sons = pidGidMap.get(g.getId());
for (Integer sonId: sons) {
Group son = gidGroupMap.get(sonId);
if ( ordered )
((OrderedGroup) g).addSon(son, son.getSequenceNumber());
else
((UnorderedGroup) g).addSon(son);
getSons(son);
}
}
/**
* Put the leaf entities in the respective parent groups.
*
* @throws SoCTraceException
*/
private void buildMapping() throws SoCTraceException {
Set<Integer> gidSet = gidEntityListMap.keySet();
for (Integer gid: gidSet) {
Group g = gidGroupMap.get(gid);
boolean ordered = g.isOrdered();
Map<Integer, IGroupable> tmp = eidEntityMap.get(g.getTargetClass());
List<Entity> elist = gidEntityListMap.get(gid);
for (Entity entity: elist) {
if ( ordered )
((OrderedGroup) g).addSon(tmp.get(entity.id), entity.seq, entity.mapping);
else
((UnorderedGroup) g).addSon(tmp.get(entity.id), entity.mapping);
}
}
}
/**
* Build a group object, given the ResultSet row.
*
* @param rs table row
* @return the Group object
* @throws SQLException
* @throws SoCTraceException
*/
private Group buildGroup(ResultSet rs) throws SQLException, SoCTraceException {
Group group = null;
int id = rs.getInt(2);
String targetEntity = rs.getString(5);
boolean ordered = rs.getBoolean(7);
if (ordered)
group = new OrderedGroup(id, getTargetClass(targetEntity));
else
group = new UnorderedGroup(id, getTargetClass(targetEntity));
group.setParentId(rs.getInt(3));
group.setName(rs.getString(4));
group.setGroupingOperator(rs.getString(6));
group.setSequenceNumber(rs.getInt(8));
return group;
}
/**
* Get Target Entity class from its string label.
*
* @param targetEntity string containing the class label
* @return the class object
*/
private Class<? extends IGroupable> getTargetClass(String targetEntity) {
if (targetEntity.equals(ModelEntity.EVENT.name()))
return Event.class;
else if (targetEntity.equals(ModelEntity.EVENT_TYPE.name()))
return EventType.class;
else if (targetEntity.equals(ModelEntity.EVENT_PARAM_TYPE.name()))
return EventParamType.class;
return null;
}
/**
* Clear maps
*/
private void clear() {
gidGroupMap.clear();
pidGidMap.clear();
gidEntityListMap.clear();
eidEntityMap.clear();
}
}