/*
* 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.Map;
import java.util.Set;
import net.jcip.annotations.NotThreadSafe;
import com.enea.jcarder.common.contexts.ContextReaderIfc;
/**
* A LockNode instance represents a lock in a graph.
*/
@NotThreadSafe
class LockNode {
enum CycleType { NO_CYCLE, SINGLE_THREADED_CYCLE, CYCLE };
private final int mLockId;
private Map<LockEdge, LockEdge> mOutgoingEdges;
private CycleType mCycleType = CycleType.NO_CYCLE;
LockNode(final int lockId) {
mLockId = lockId;
mOutgoingEdges = new HashMap<LockEdge, LockEdge>();
}
int getLockId() {
return mLockId;
}
CycleType getCycleType() {
return mCycleType;
}
void raiseCycleType(CycleType newCycleType) {
if (newCycleType.compareTo(mCycleType) > 0) {
mCycleType = newCycleType;
}
}
void addOutgoingEdge(LockEdge newEdge) {
LockEdge existingEdge = mOutgoingEdges.get(newEdge);
if (existingEdge == null) {
mOutgoingEdges.put(newEdge, newEdge);
} else {
existingEdge.merge(newEdge);
}
}
void populateContextIdTranslationMap(Map<Integer, Integer> translationMap) {
for (LockEdge edge : mOutgoingEdges.values()) {
translationMap.put(edge.getSourceLockingContextId(),
edge.getSourceLockingContextId());
translationMap.put(edge.getTargetLockingContextId(),
edge.getTargetLockingContextId());
}
}
void translateContextIds(Map<Integer, Integer> translation) {
Map<LockEdge, LockEdge> oldEdges = mOutgoingEdges;
mOutgoingEdges = new HashMap<LockEdge, LockEdge>(oldEdges.size());
for (LockEdge edge : oldEdges.values()) {
edge.translateContextIds(translation);
addOutgoingEdge(edge);
}
}
Set<LockEdge> getOutgoingEdges() {
return mOutgoingEdges.keySet();
}
public String toString() {
return "L_" + mLockId;
}
long numberOfUniqueEdges() {
return mOutgoingEdges.size();
}
long numberOfDuplicatedEdges() {
long numberOfDuplicatedEdges = 0;
for (LockEdge edge : mOutgoingEdges.values()) {
numberOfDuplicatedEdges += edge.getDuplicates();
}
return numberOfDuplicatedEdges;
}
boolean alike(LockNode other, ContextReaderIfc reader) {
// TODO Maybe introduce some kind of cache to improve performance?
String thisClassName = reader.readLock(mLockId).getClassName();
String otherClassName = reader.readLock(other.mLockId).getClassName();
return thisClassName.equals(otherClassName);
}
}