blob: 578b57693edb3b8c452128d61b3db99a488e952c [file] [log] [blame]
/*******************************************************************************
* 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