package de.uniAugsburg.MAF.dfa.jwt.analysis.token.macros.validation;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import de.uniAugsburg.MAF.core.util.model.EMFDynamicUtils;
import de.uniAugsburg.MAF.dfa.jwt.metamodel.JWTConstants;
import de.uniAugsburg.MAF.dfa.jwt.metamodel.tokenflow.Component;
import de.uniAugsburg.MAF.dfa.jwt.metamodel.tokenflow.componentType;
import de.uniAugsburg.MAF.dfa.jwt.metamodel.tokenflow.validationClassification;
import de.uniAugsburg.MAF.dfa.jwt.metamodel.tokenflow.validationResult;
public class ComponentValidator
{
/**
* Recursively validates a component according to IBM's fast heuristics
* algorithm.
*/
public void validateComponent(Component component)
{
// RECURSIVE: validate subcomponents and check their type
boolean unsoundChild = false;
boolean unknownChild = false;
for (Component subComponent : component.getSubComponents())
{
// recursively validate subcomponent
validateComponent(subComponent);
// store child type info
if (subComponent.getValidResult().equals(validationResult.UNSOUND))
unsoundChild = true;
else if (subComponent.getValidResult().equals(validationResult.UNKNOWN))
unknownChild = true;
}
// classify component type
classifyComponent(component);
// determine result status of component
// a) child overwrites local status
if (unsoundChild)
component.setValidResult(validationResult.UNSOUND);
else if (unknownChild)
component.setValidResult(validationResult.UNKNOWN);
else
{
// b) set local status according to classification result
if (component.getValidClassification().equals(
validationClassification.COMPLEXUNSOUNDDEADLOCK)
|| component.getValidClassification().equals(
validationClassification.COMPLEXUNSOUNDLACKOFSYNC))
component.setValidResult(validationResult.UNSOUND);
else if (component.getValidClassification().equals(
validationClassification.COMPLEXUNKNOWN))
component.setValidResult(validationResult.UNKNOWN);
else
component.setValidResult(validationResult.SOUND);
}
System.out.println(component.toString());
}
/**
* Determines the type of a component.
*/
public static void classifyComponent(Component component)
{
// get all child nodes
Set<EObject> childNodes = new HashSet<EObject>(component.getTrivialNodes());
childNodes.addAll(component.getSccInputPorts());
childNodes.addAll(component.getSccOutputPorts());
// collect information from child nodes
Set<EObject> decisionNodes = new HashSet<EObject>();
Set<EObject> mergeNodes = new HashSet<EObject>();
Set<EObject> forkNodes = new HashSet<EObject>();
Set<EObject> joinNodes = new HashSet<EObject>();
for (EObject childNode : childNodes)
if (childNode.eClass().getName().equals(JWTConstants.EC_DECISIONNODE))
decisionNodes.add(childNode);
else if (childNode.eClass().getName().equals(JWTConstants.EC_MERGENODE))
mergeNodes.add(childNode);
else if (childNode.eClass().getName().equals(JWTConstants.EC_JOINNODE))
joinNodes.add(childNode);
else if (childNode.eClass().getName().equals(JWTConstants.EC_FORKNODE))
forkNodes.add(childNode);
// contains cycle
boolean containsSCC = false;
for (Component subComponent : component.getSubComponents())
if (componentType.SCC.equals(subComponent.getType()))
{
containsSCC = true;
break;
}
// input/output node information
EObject inEdge = component.getInputEdges().get(0);
EObject outEdge = component.getOutputEdges().get(0);
boolean entryIsIncomingOfDecision = decisionNodes.size() == 1
&& EMFDynamicUtils.getEReferenceValues(decisionNodes.iterator().next(), "in")
.contains(inEdge);
boolean exitIsOutgoingOfMerge = mergeNodes.size() == 1
&& EMFDynamicUtils.getEReferenceValues(mergeNodes.iterator().next(), "out")
.contains(outEdge);
boolean entryIsIncomingOfMerge = mergeNodes.size() == 1
&& EMFDynamicUtils.getEReferenceValues(mergeNodes.iterator().next(), "in")
.contains(inEdge);
boolean exitIsOutgoingOfDecision = decisionNodes.size() == 1
&& EMFDynamicUtils.getEReferenceValues(decisionNodes.iterator().next(), "out")
.contains(outEdge);
boolean entryIsIncomingOfFork = forkNodes.size() == 1
&& EMFDynamicUtils.getEReferenceValues(forkNodes.iterator().next(), "in").contains(
inEdge);
boolean exitIsOutgoingOfJoin = joinNodes.size() == 1
&& EMFDynamicUtils.getEReferenceValues(joinNodes.iterator().next(), "out")
.contains(outEdge);
// apply heuristics
// well-structured
if (decisionNodes.size() == 0 && mergeNodes.size() == 0 && forkNodes.size() == 0
&& joinNodes.size() == 0)
component.setValidClassification(validationClassification.WELLSTRUCTUREDSEQUENCE);
else if (decisionNodes.size() == 1 && mergeNodes.size() == 1 && forkNodes.size() == 0
&& joinNodes.size() == 0 && entryIsIncomingOfDecision && exitIsOutgoingOfMerge)
component
.setValidClassification(validationClassification.WELLSTRUCTUREDSEQUENTIALBRANCHING);
else if (decisionNodes.size() == 1 && mergeNodes.size() == 1 && forkNodes.size() == 0
&& joinNodes.size() == 0 && entryIsIncomingOfMerge && exitIsOutgoingOfDecision)
component.setValidClassification(validationClassification.WELLSTRUCTUREDCYCLE);
else if (decisionNodes.size() == 0 && mergeNodes.size() == 0 && forkNodes.size() == 1
&& joinNodes.size() == 1 && entryIsIncomingOfFork && exitIsOutgoingOfJoin)
component
.setValidClassification(validationClassification.WELLSTRUCTUREDCONCURRENTBRANCHING);
else
{
// not well-structured
if (decisionNodes.size() == 0 && mergeNodes.size() == 0 && !containsSCC)
component.setValidClassification(validationClassification.UNSTRUCTUREDCONCURRENT);
else if (forkNodes.size() == 0 && joinNodes.size() == 0)
component.setValidClassification(validationClassification.UNSTRUCTUREDSEQUENTIAL);
else
{
// complex
// at least one decision, but no merges
boolean case1a = !containsSCC && decisionNodes.size() > 0 && mergeNodes.size() == 0;
// at least one merge, but no decisions
boolean case1b = !containsSCC && mergeNodes.size() > 0 && decisionNodes.size() == 0;
// at least one fork, but no joins
boolean case2a = !containsSCC && forkNodes.size() > 0 && joinNodes.size() == 0;
// at least one join, but no forks
boolean case2b = !containsSCC && joinNodes.size() > 0 && forkNodes.size() == 0;
boolean case3a = containsSCC && decisionNodes.size() == 0 && mergeNodes.size() == 0;
boolean case3b = containsSCC && decisionNodes.size() > 0 && mergeNodes.size() == 0;
boolean case3c = containsSCC && decisionNodes.size() == 0 && mergeNodes.size() > 0;
if (case1a || case2b || case3a || case3b)
component
.setValidClassification(validationClassification.COMPLEXUNSOUNDDEADLOCK);
else if (case1b || case2a || case3c)
component
.setValidClassification(validationClassification.COMPLEXUNSOUNDLACKOFSYNC);
else
component.setValidClassification(validationClassification.COMPLEXUNKNOWN);
}
}
}
}
|