/*
* JCarder -- cards Java programs to keep threads disentangled
*
* Copyright (C) 2006-2007 Enea AB
* Copyright (C) 2007 Ulrik Svensson
* Copyright (C) 2007 Joel Rosdahl
*
* This program is made available under the GNU GPL version 2, with a special
* exception for linking with JUnit. See the accompanying file LICENSE.txt for
* details.
*
* 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.
*/
package com.enea.jcarder.analyzer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeSet;
import com.enea.jcarder.common.LockingContext;
import com.enea.jcarder.common.contexts.ContextReaderIfc;
/**
* This class contains functionality for merging edges that have the same source
* and target nodes and identical thread IDs and locking contexts content, but
* different locking context IDs.
*
* Such a merge might be desirable since the producer of the context file is not
* required to guarantee that identical locking contexts always get the same
* IDs.
*
* @TODO Add basic tests for this class.
*/
public final class DuplicatedEdgesHandler {
private final Iterable<LockNode> mLockNodes;
private final Map<Integer, Integer> mContextIdTranslation;
private final Map<LockingContext, TreeSet<Integer>> mContextToIdMap;
/**
* The constructor is made private to prevent that someone creates an
* instance of this class and then forgets to release the reference to it.
* That would be undesirable since the mContextToIdMap structure in this
* class might be very large and should be garbage collected as soon as
* possible.
*
* @see DuplicatedEdgesHandler.mergeDuplicatedEdges() instead.
*/
private DuplicatedEdgesHandler(Iterable<LockNode> lockNodes,
ContextReaderIfc reader) {
mLockNodes = lockNodes;
mContextIdTranslation = populateTranslationMap();
mContextToIdMap = createContextToIdMap(reader);
}
public static void mergeDuplicatedEdges(Iterable<LockNode> lockNodes,
ContextReaderIfc reader) {
DuplicatedEdgesHandler handler = new DuplicatedEdgesHandler(lockNodes,
reader);
handler.updateContextIdTranslationMap();
handler.updateEdgesWithTranslationMap();
}
private void updateEdgesWithTranslationMap() {
for (LockNode node : mLockNodes) {
node.translateContextIds(mContextIdTranslation);
}
}
private Map<Integer, Integer> populateTranslationMap() {
final HashMap<Integer, Integer> contextIds =
new HashMap<Integer, Integer>();
for (LockNode node : mLockNodes) {
node.populateContextIdTranslationMap(contextIds);
}
return contextIds;
}
private Map<LockingContext, TreeSet<Integer>>
createContextToIdMap(ContextReaderIfc reader) {
final Map<LockingContext, TreeSet<Integer>> contextToId =
new HashMap<LockingContext, TreeSet<Integer>>();
for (Integer id : mContextIdTranslation.values()) {
LockingContext context = reader.readContext(id);
TreeSet<Integer> ids = contextToId.get(context);
if (ids == null) {
ids = new TreeSet<Integer>();
contextToId.put(context, ids);
}
ids.add(id);
}
return contextToId;
}
private void updateContextIdTranslationMap() {
for (TreeSet<Integer> ids : mContextToIdMap.values()) {
if (ids.size() > 1) {
Iterator<Integer> iter = ids.iterator();
Integer firstId = iter.next();
while (iter.hasNext()) {
mContextIdTranslation.put(iter.next(), firstId);
}
}
}
}
}