/******************************************************************************* | |
* CHESS core plugin | |
* | |
* Copyright (C) 2011-2015 | |
* Mälardalen University, Sweden | |
* | |
* | |
* 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-v20.html | |
*******************************************************************************/ | |
package org.polarsys.chess.fla.flamm; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashSet; | |
import java.util.List; | |
import java.util.Set; | |
import org.eclipse.emf.common.notify.NotificationChain; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.ecore.EClass; | |
import org.eclipse.emf.ecore.InternalEObject; | |
import org.eclipse.emf.ecore.util.EObjectContainmentEList; | |
import org.eclipse.emf.ecore.util.InternalEList; | |
import org.polarsys.chess.fla.flamm.analysis.FlaSystem; | |
import com.google.common.collect.Sets; | |
/** | |
* <!-- begin-user-doc --> | |
* A representation of the model object '<em><b>Simple Component</b></em>'. | |
* <!-- end-user-doc --> | |
* | |
* <p> | |
* The following features are supported: | |
* </p> | |
* <ul> | |
* <li>{@link org.polarsys.chess.fla.flamm.SimpleComponent#getRules <em>Rules</em>}</li> | |
* </ul> | |
* | |
* @see org.polarsys.chess.fla.flamm.FlammPackage#getSimpleComponent() | |
* @model kind="class" | |
* @generated | |
*/ | |
public class SimpleComponent extends Component { | |
/** | |
* The cached value of the '{@link #getRules() <em>Rules</em>}' containment reference list. | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @see #getRules() | |
* @generated | |
* @ordered | |
*/ | |
protected EList<Rule> rules; | |
List<Set<PortFailureTuple>> propagatedInputPortFailures = null; | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
public SimpleComponent() { | |
super(); | |
} | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
@Override | |
protected EClass eStaticClass() { | |
return FlammPackage.Literals.SIMPLE_COMPONENT; | |
} | |
/** | |
* Returns the value of the '<em><b>Rules</b></em>' containment reference list. | |
* The list contents are of type {@link org.polarsys.chess.fla.flamm.Rule}. | |
* <!-- begin-user-doc --> | |
* <p> | |
* If the meaning of the '<em>Rules</em>' containment reference list isn't clear, | |
* there really should be more of a description here... | |
* </p> | |
* <!-- end-user-doc --> | |
* @return the value of the '<em>Rules</em>' containment reference list. | |
* @see org.polarsys.chess.fla.flamm.FlammPackage#getSimpleComponent_Rules() | |
* @model containment="true" | |
* @generated | |
*/ | |
public List<Rule> getRules() { | |
if (rules == null) { | |
rules = new EObjectContainmentEList<Rule>(Rule.class, this, FlammPackage.SIMPLE_COMPONENT__RULES); | |
} | |
return rules; | |
} | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
@Override | |
public NotificationChain eInverseRemove(InternalEObject otherEnd, int featureID, NotificationChain msgs) { | |
switch (featureID) { | |
case FlammPackage.SIMPLE_COMPONENT__RULES: | |
return ((InternalEList<?>)getRules()).basicRemove(otherEnd, msgs); | |
} | |
return super.eInverseRemove(otherEnd, featureID, msgs); | |
} | |
private List<Set<PortFailureTuple>> getPropagatedInputPortFailures() { | |
if (propagatedInputPortFailures == null) { | |
propagatedInputPortFailures = new ArrayList<Set<PortFailureTuple>>(); | |
for (int i = 0; i < getInputPorts().size(); i++) { | |
propagatedInputPortFailures.add(new HashSet<PortFailureTuple>()); | |
} | |
} | |
return propagatedInputPortFailures; | |
} | |
@Override | |
public void propagateFailures() { | |
propagateInputFailures(); | |
propagateOutputFailures(); | |
} | |
/** | |
* Calculates Cartesian product (cross product / all combinations) for the input ports failures.<br/> | |
* These combinations are used to match and fire transformation rules. | |
* <p>The combinations of propagated combinations are updated. | |
*/ | |
void propagateInputFailures() { | |
for (int i = 0; i < inputPorts.size(); i++) { | |
Port port = inputPorts.get(i); | |
Set<PortFailureTuple> newPortFailures = PortFailureTuple.fromCollection(port, port.getNewFailures()); | |
Set<PortFailureTuple> oldPortFailures = getPropagatedInputPortFailures().get(i); | |
propagatedInputPortFailures.set(i, newPortFailures); | |
Set<List<PortFailureTuple>> newFailureCombinations = getNewInputFailureCombinations(propagatedInputPortFailures); | |
for (List<PortFailureTuple> portFailureCombination : newFailureCombinations) { | |
propagateFailureCombination(portFailureCombination); | |
} | |
port.clearNewFailures(); | |
propagatedInputPortFailures.set(i, Sets.union(oldPortFailures, newPortFailures)); | |
} | |
} | |
/** | |
* New failures on output ports are propagated to all connected ports. | |
*/ | |
protected void propagateOutputFailures() { | |
for (Port port : outputPorts) { | |
for (Failure failure : port.getNewFailures()) { | |
for (Port connectedPort : port.getConnectedPorts()) { | |
if (connectedPort.addFailure(failure, failure)) { | |
FlaSystem.addUpdatedComponent(connectedPort.getOwner()); | |
} | |
} | |
} | |
port.clearNewFailures(); | |
} | |
} | |
Set<List<PortFailureTuple>> getNewInputFailureCombinations(List<Set<PortFailureTuple>> failures) { | |
Set<List<PortFailureTuple>> failureCombinations = Sets.cartesianProduct(failures); | |
return failureCombinations; | |
} | |
/** | |
* Propagates a list of port-failure combinations via transformation rules to corresponding output ports. | |
* <p>If no rule matches {@link #HandleUnmatchedFailureCombination} is called. | |
* @param failuresetToMatch | |
*/ | |
void propagateFailureCombination(List<PortFailureTuple> failuresetToMatch) { | |
List<Rule> rules = getMostSpecificMatchingRules(failuresetToMatch); | |
if (rules != null && !rules.isEmpty()) { | |
List<Failure> previousFailures = portfailuresToFailureList(failuresetToMatch); | |
for(Rule rule : rules) { | |
rule.fire(previousFailures); | |
} | |
} else { | |
HandleUnmatchedFailureCombination(failuresetToMatch); | |
} | |
} | |
List<Failure> portfailuresToFailureList(List<PortFailureTuple> failureSet) { | |
List<Failure> failures = new ArrayList<Failure>(); | |
for (PortFailureTuple portFailure : failureSet) { | |
failures.add(portFailure.getFailure()); | |
} | |
return failures; | |
} | |
protected void HandleUnmatchedFailureCombination(List<PortFailureTuple> failuresetToMatch) { | |
if (FlaSystem.propagateUnmatchedFailures()) { | |
for (Port port : outputPorts) { | |
for (PortFailureTuple portFailure : failuresetToMatch) { | |
port.addFailure(portFailure.getFailure(), portFailure.getFailure()); | |
} | |
} | |
} else { | |
// TODO: alert user | |
log("Unmatched failure set: " + failuresetToMatch); | |
} | |
} | |
List<Rule> getMostSpecificMatchingRules(List<PortFailureTuple> failuresetToMatch) { | |
List<Rule> matchingRules = getAllMatchingRules(failuresetToMatch); | |
if (matchingRules == null || matchingRules.isEmpty()) { | |
return null; | |
} | |
int highestSpecificity = matchingRules.get(0).getSpecificity(); | |
for (Rule matchingRule : matchingRules) { | |
if (matchingRule.getSpecificity() > highestSpecificity) { | |
highestSpecificity = matchingRule.getSpecificity(); | |
} | |
} | |
List<Rule> mostSpecificRules = new ArrayList<Rule>(); | |
for (Rule matchingRule : matchingRules) { | |
if (matchingRule.getSpecificity() == highestSpecificity) { | |
mostSpecificRules.add(matchingRule); | |
} | |
} | |
return mostSpecificRules; | |
} | |
List<Rule> getAllMatchingRules(List<PortFailureTuple> failuresetToMatch) { | |
List<Rule> matchingRules = new ArrayList<Rule>(); | |
if (this.rules != null) { | |
for (Rule rule : rules) { | |
if (rule.matchFailure(failuresetToMatch)) { | |
matchingRules.add(rule); | |
} | |
} | |
} | |
return matchingRules; | |
} | |
protected void log(String message) { | |
// TODO: implement | |
// if (logger != null) { | |
// logger.logWarning(message); | |
// } | |
} | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
@Override | |
public Object eGet(int featureID, boolean resolve, boolean coreType) { | |
switch (featureID) { | |
case FlammPackage.SIMPLE_COMPONENT__RULES: | |
return getRules(); | |
} | |
return super.eGet(featureID, resolve, coreType); | |
} | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
@SuppressWarnings("unchecked") | |
@Override | |
public void eSet(int featureID, Object newValue) { | |
switch (featureID) { | |
case FlammPackage.SIMPLE_COMPONENT__RULES: | |
getRules().clear(); | |
getRules().addAll((Collection<? extends Rule>)newValue); | |
return; | |
} | |
super.eSet(featureID, newValue); | |
} | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
@Override | |
public void eUnset(int featureID) { | |
switch (featureID) { | |
case FlammPackage.SIMPLE_COMPONENT__RULES: | |
getRules().clear(); | |
return; | |
} | |
super.eUnset(featureID); | |
} | |
/** | |
* <!-- begin-user-doc --> | |
* <!-- end-user-doc --> | |
* @generated | |
*/ | |
@Override | |
public boolean eIsSet(int featureID) { | |
switch (featureID) { | |
case FlammPackage.SIMPLE_COMPONENT__RULES: | |
return rules != null && !rules.isEmpty(); | |
} | |
return super.eIsSet(featureID); | |
} | |
} // SimpleComponent |