blob: b195d1a85d1e89b15a9819ec1627a3ae133e130e [file] [log] [blame]
-----------------------------------------------------------------------
-- Copyright (C) 2015-2016 --
-- University of Firenze, Italy --
-- --
-- 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 --
-- --
-- Contributors: --
-- Leonardo Montecchi lmontecchi@unifi.it --
-----------------------------------------------------------------------
-- @path IM=/org.polarsys.chess.statebased/metamodels/IM2.ecore
-- @path CHESS=/org.polarsys.chess.chessmlprofile/model/chessmlprofile.ecore
-- @nsURI MARTE=http://www.eclipse.org/papyrus/MARTE/1
-- @nsURI UML=http://www.eclipse.org/uml2/4.0.0/UML
-- @nsURI CHESS=http://CHESS
-- @nsURI SYSML=http://www.eclipse.org/papyrus/0.7.0/SysML
module CHESS2IM;
create OUT : IM from IN1 : CHESS, IN2 : UML, IN3 : MARTE, IN4 : SYSML;
helper def: umlInstancesAll : Sequence(UML!InstanceSpecification) = Sequence{}; --All the InstanceSpecification of the considered platform
helper def: umlInstancesConnectors : Set(UML!InstanceSpecification) = Set{}; --Instances of connectors
helper def: umlInstancesBlocks : Set(UML!InstanceSpecification) = Set{}; --Instances of components/blocks
helper def: umlInstancesStereo : Set(UML!InstanceSpecification) = Set{}; --Instances that have dependability information
helper def: umlInstancesRelevant : Set(UML!InstanceSpecification) = Set{}; --Instances that are relevant for the analysis
helper def: umlAllocations : Set(MARTE!Assign) = Set{};
--Stereotypes that can be used on Blocks/Components for state based analysis
helper def: sbaStereotypes : Sequence(OclAny) = Sequence{CHESS!SimpleStochasticBehavior, CHESS!FLABehavior, CHESS!ErrorModelBehavior,
CHESS!StatelessSoftware, CHESS!StatefulSoftware, CHESS!StatelessHardware, CHESS!StatefulHardware};
--Stereotypes that can be used on Transitions of an Error Model
helper def: sbaTransitions : Sequence(OclAny) = Sequence{CHESS!Failure, CHESS!InternalPropagation, CHESS!InternalFault};
helper def: flaNoFailure : String = 'noFailure';
helper def: flaWildcard : String = 'wildcard';
helper def: flaRules : Map(IM!Component, Map(String, IM!Error)) = Map{}; --Map to obtain the list of flarules for a component, and the corresponding IM!Error elements
helper def: errmodErrorMap : Map(TupleType(e: UML!Vertex, cc: IM!Component), IM!Error) = Map{};
--rule to transform the CHESS!StateBasedAnalysis into an IM!Sistema
rule SBA {
from
sba : CHESS!StateBasedAnalysis
do {
thisModule.System(sba.platform->first().base_Package);
--Handle metrics
if (sba.WhichMeasure = 'Reliability') {
thisModule.Reliability(sba);
}else if (sba.WhichMeasure = 'Availability') {
thisModule.Availability(sba);
}else if (sba.WhichMeasure = 'PFD') {
thisModule.PFD(sba);
}else{
---TODO: others?
}
}
}
unique lazy rule System {
from
platform : UML!Package
--sba : CHESS!StateBasedAnalysis
--at the moment is it implied that there is only a StateBasedAnalysis in the model
using {
--instances of interest are:
--> SET1: all the instances included in the target resource platform, plus
--> SET2: all the instances involved in allocations mentioned in the target resource platform, plus
--> SET3: all the instances in the same resource platform as those involved in allocations
instances : Set(UML!InstanceSpecification) =
UML!InstanceSpecification.allInstances()->select(i | i.refImmediateComposite() = platform) --SET1
->union(platform.getAllocationsInstances()) --SET2
->union(UML!InstanceSpecification.allInstances()
->select(i | platform.getAllocationsInstances()
->collect(ai | ai.refImmediateComposite())
->includes(i.refImmediateComposite())) --SET3
)->asSet(); --Removes duplicates
comments : Sequence(UML!Comment) = instances->collect(i | i.ownedComment)->flatten();
instSystem : UML!InstanceSpecification = platform.ownedElement->first();
}
to
s : IM!Sistema (
Name <- platform.name
)
do {
--Filter out and categorize relevant CHESS elements
thisModule.umlInstancesAll <- instances;
thisModule.umlInstancesConnectors <- instances->select(i | i.classifier.isEmpty());
thisModule.umlInstancesBlocks <- instances->select(i | not i.classifier.isEmpty());
thisModule.umlAllocations <- MARTE!Assign.allInstances()->select(a | comments.includes(a.base_Comment));
thisModule.umlInstancesBlocks <- thisModule.umlInstancesAll->select(i | thisModule.umlInstancesConnectors.excludes(i));
thisModule.umlInstancesStereo <- thisModule.umlInstancesBlocks->select(i | i.getSBAStereotype() <> OclUndefined);
--Instances that are relevant for the analysis are:
--> Those that are constituents of the instance representing the target platform, plus
--> Those that are constituents of the instances representing the platforms that own the instances involved in allocations
thisModule.umlInstancesRelevant <- instSystem.findSBAConstituents()
->union(platform.getAllocationsInstances()
->collect(ai | ai.refImmediateComposite())
->collect(im | im.ownedElement->first().findSBAConstituents()))->flatten();
--Generate IM!Component elements, failure modes, and what can be done immediately
for(i in thisModule.umlInstancesRelevant) {
s.components <- s.components->including(
thisModule.InstanceToComponent(i)
);
if(i.getSBAStereotype().oclType() = CHESS!SimpleStochasticBehavior) {
thisModule.SimpleStochasticBehaviorToComponent(i);
}else if(i.getSBAStereotype().oclType() = CHESS!FLABehavior){
thisModule.FLASpecificationToComponent(i);
}else if(i.getSBAStereotype().oclType() = CHESS!ErrorModelBehavior) {
thisModule.ErrorModelToComponent(i);
}
}
--Generate external faults
for(i in thisModule.umlInstancesRelevant) {
thisModule.PopulateExternalFaults(i);
}
--Generate FGE, i.e., connect external faults
for(i in thisModule.umlInstancesRelevant) {
if(i.getSBAStereotype().oclType() = CHESS!SimpleStochasticBehavior) {
thisModule.SimpleStochasticBehavior_FGE(i);
}else if(i.getSBAStereotype().oclType() = CHESS!FLABehavior){
thisModule.FLASpecification_FGE(i);
}else if(i.getSBAStereotype().oclType() = CHESS!ErrorModelBehavior) {
thisModule.ErrorModel_FGE(i);
}
}
--Process allocations
for(a in platform.getAllocations()) {
thisModule.Allocation(a);
}
--Set FGE Backlinks
for(fge in IM!FaultsGenerateErrors.allInstances()) {
thisModule.setFGEBackLinks(fge.PropagationLogic, fge);
}
--Set EPF Backlinks
for(epf in IM!ErrorsProducesFailures.allInstances()) {
thisModule.setEPFBackLinks(epf.PropagationLogic, epf);
}
--Set IP Backlinks
for(ip in IM!InternalPropagation.allInstances()) {
thisModule.setIPBackLinks(ip.PropagationLogic, ip);
}
--Process repair activities
for(r in CHESS!Repair.allInstances()) {
thisModule.RepairActivity(r);
}
}
}
unique lazy rule InstanceToComponent {
from
inst : UML!InstanceSpecification
to
c : IM!Component (
Name <- inst.name
)
}
--------------------------------------------------------------------
-- Rules to project component instances to IM!Component elements
--------------------------------------------------------------------
rule SimpleStochasticBehaviorToComponent(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
st : CHESS!SimpleStochasticBehavior = inst.getSBAStereotype();
tmpFailures : Set(TupleType(fm : String, p : Real)) = OclUndefined;
tmpError : IM!Error = OclUndefined;
tmpFailureMode : IM!FailureMode = OclUndefined;
myFailureModes : String = if st.failureModesDistribution.oclIsUndefined() then '' else st.failureModesDistribution endif;
eSeq : Sequence(IM!Error) = Sequence{};
tmpFGE : IM!FaultsGenerateErrors = OclUndefined;
}
to
fault : IM!InternalFault (
Component <- c,
Name <- inst.name + '_ift',
PermanentProbability <- 1,
Occurrence <- st.failureOccurrence.parseDistribution(),
TransientDuration <- thisModule.Deterministic(0)
)
do {
c.Faults = c.Faults.including(fault);
for(p in inst.getPortSlots()
->collect(sl | sl.definingFeature)
->union(inst.classifier->first().ownedAttribute->select(op | op.oclIsKindOf(UML!Port)))
->select(p | p.hasOutputFlow())->asSet()) {
tmpFailures <- myFailureModes.parseFailureModesForPort(p.name);
tmpError <- thisModule.AddError('e_' + p.name, c);
eSeq <- eSeq.including(tmpError);
for(fmSpec in tmpFailures) {
thisModule.AddEPF(
tmpError,
thisModule.AddFailureMode(p.name + '.' + fmSpec.fm, c),
thisModule.Deterministic(0),
1,
fmSpec.p
);
}
}
tmpFGE <- thisModule.AddFGE(Sequence{fault}, eSeq, thisModule.Deterministic(0), 1, 1);
tmpFGE.PropagationLogic <- thisModule.FEXP_Fault(fault);
tmpFGE.PropagationLogicStringFormat <- tmpFGE.PropagationLogic.toString();
c.FaultsGeneratesErrors = c.FaultsGeneratesErrors.including(tmpFGE);
if(not st.repairDelay.oclIsUndefined()) {
if(st.repairDelay.trim().size() > 0) {
thisModule.SimpleStochasticBehaviorRepair(inst);
}
}
}
}
--This is called only if repairDelay is not empty
lazy rule SimpleStochasticBehaviorRepair {
from
inst : UML!InstanceSpecification
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
}
to
repair : IM!RepairActivity (
Target <- c,
Name <- inst.name + '_repair',
Duration <- inst.getSBAStereotype().repairDelay.parseDistribution(),
SuccessProbability <- 1.0,
When <- se
),
se : IM!ScheduleExpression
(
T <- si
),
si : IM!ScheduleExpressionImmediately
do {
se.EX <- thisModule.SCHEXP_FailureModesCollection(c.FailureModes);
}
}
rule FLASpecificationToComponent(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
st : CHESS!FLABehavior = inst.getSBAStereotype();
flaRules : Sequence(String) = st.fptc.regexReplaceAll('FLA:', ' ').trim().split(';');
tmpLeft : String = OclUndefined;
tmpRight : String = OclUndefined;
tmpFailures : Sequence(String) = OclUndefined;
errorMap : Map(String,IM!Error) = Map{};
tmpError : IM!Error = OclUndefined;
tmpEPF : IM!ErrorsProducesFailures = OclUndefined;
fToPropagate : Sequence(IM!FailureMode) = Sequence{};
j : Integer = 0;
}
do {
--For every line of the FLA specification
for(spec in flaRules) {
j <- j+1;
tmpError <- thisModule.AddError('e_'+j,c);
tmpRight <- spec.trim().split('->')->last().trim(); --Get right hand side
tmpFailures <- tmpRight.split(','); --Get the different failures in the right hand side
--For every failure in the right side of the rule
fToPropagate <- Sequence{};
for(failure in tmpFailures) {
--If it is not the 'noFailure' element
if(failure.indexOf('.' + thisModule.flaNoFailure) = -1) {
--If the failure mode does not exist already
if(not c.hasFailureMode(failure)) {
thisModule.AddFailureMode(failure, c);
}
fToPropagate <- fToPropagate.including(
c.FailureModes->select(f | f.localName = failure)->first()
);
}
}
--If the set of failure modes to propagate for this rule
--is not empty, then create an EPF element
if(not fToPropagate.isEmpty()) {
tmpEPF <- thisModule.AddFLARuleEPF(tmpError);
tmpEPF.Destination <- fToPropagate;
}
}
}
}
rule ErrorModelToComponent(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
st : CHESS!ErrorModelBehavior = inst.getSBAStereotype();
errorModel : CHESS!ErrorModel = st.errorModel->first();
states : Sequence(UML!State) = errorModel.base_StateMachine.ownedElement->first().ownedElement->select(e | e.oclIsKindOf(UML!State));
pseudo : Sequence(CHESS!Pseudostate) = errorModel.base_StateMachine.ownedElement->first().ownedElement->select(e | e.oclIsKindOf(CHESS!Pseudostate));
transitions : Sequence(UML!Transition) = errorModel.base_StateMachine.ownedElement->first().ownedElement->select(e | e.oclIsKindOf(UML!Transition));
tmpStereotype : OclAny = OclUndefined;
tmpExternalFaults : String = OclUndefined;
}
do {
--Scan all CHESS!Failure elements in the error model,
--to create the needed IM!FailureMode elements
for(tr in transitions) {
tmpStereotype <- tr.getFailureStereotype();
if(not tmpStereotype.oclIsUndefined()) {
for(f in tmpStereotype.mode) {
--If it is not the 'noFailure' element
if(f.indexOf('.' + thisModule.flaNoFailure) = -1) {
--If the failure mode does not exist already
if(not c.hasFailureMode(f)) {
thisModule.AddFailureMode(f, c);
}
}
}
}
}
--Transform ErrorModel States
for(s in states) {
thisModule.ErrorModelStateToError(s,inst);
}
--Transform ErrorModel Pseudostates (choice)
for(s in pseudo->select(p | p.kind = #choice)) {
thisModule.ErrorModelStateToError(s,inst);
}
--Transform ErrorModel <<Failure>> Transitions
for(tr in transitions) {
tmpStereotype <- tr.getSBAStereotype();
if(tmpStereotype.oclIsTypeOf(CHESS!Failure)) {
thisModule.AddEPFFromErrorModelFailure(tmpStereotype,inst);
}
}
--<<InternalFault>> become IM!InternalFault
for(tr in transitions) {
tmpStereotype <- tr.getSBAStereotype();
if(tmpStereotype.oclIsTypeOf(CHESS!InternalFault)) {
thisModule.InternalFault(tmpStereotype,inst);
}
}
--Transform ErrorModel <<InternalPropagation>> Transitions,
--but only those for which the 'externalFaults' attribute is empty.
--(for the others all the external faults need to be in place)
for(tr in transitions) {
tmpStereotype <- tr.getSBAStereotype();
if(tmpStereotype.oclIsTypeOf(CHESS!InternalPropagation)) {
if(tmpStereotype.oclIsTypeOf(CHESS!InternalFault)) {
--Do nothing (processed elsewhere)
}else{
--Match <<InternalPropagation>> stereotype only
tmpExternalFaults <- tmpStereotype.externalFaults;
if(tmpExternalFaults.oclIsUndefined()) {
thisModule.InternalPropagation(tmpStereotype,inst);
}
}
}
}
}
}
--------------------------------------------------------------------
-- Rule to generate external faults for component instances
--------------------------------------------------------------------
rule PopulateExternalFaults(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
inPorts : Set(UML!Slot) = inst.getPortSlots()->select(p | p.hasInputFlow());
faultName : String = OclUndefined;
connPort : UML!Slot = OclUndefined;
connComp : IM!Component = OclUndefined;
tmpExternalFault : IM!ExternalFault = OclUndefined;
}
do {
for(p in inPorts) {
--Find connected port
connPort <- p.getSBAConnections()->first();
--Find connected component (slot owner)
if(not connPort.oclIsUndefined()) {
connComp <- thisModule.InstanceToComponent(connPort.refImmediateComposite());
for(f in connComp.FailureModes->select(fm | fm.getPortName() = connPort.name)) {
faultName <- f.Name.split('\\.')->last();
--If the external faults has not already been added then add it
if(c.Faults->select(ft | ft.Name = connComp.Name + '_' + f)->isEmpty()) {
tmpExternalFault <- thisModule.AddExternalFault(p.name + '.' + faultName, inst);
tmpExternalFault.Source <- f;
}
}
}
}
}
}
--------------------------------------------------------------------
-- Rule to generate FGE elements
--------------------------------------------------------------------
rule SimpleStochasticBehavior_FGE(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
fge : IM!FaultsGenerateErrors = OclUndefined;
externals : Sequence(IM!Fault) = c.Faults->select(ft | ft.oclIsTypeOf(IM!ExternalFault));
}
do {
--FGE for external faults
if(externals->size() > 0) {
fge <- thisModule.AddFGE(externals, c.Errors, 'det(0)'.parseDistribution(), 1, 1);
fge.PropagationLogic <- thisModule.FEXP_MultiOr(
externals->collect(f | thisModule.FEXP_Fault(f))
);
fge.PropagationLogicStringFormat <- fge.PropagationLogic.toString();
}
}
}
rule FLASpecification_FGE(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
st : CHESS!FLABehavior = inst.getSBAStereotype();
flaRules : Sequence(String) = st.fptc.regexReplaceAll('FLA:', ' ').trim().split(';');
tmpLeft : String = OclUndefined;
tmpRight : String = OclUndefined;
tmpFaults : Sequence(String) = OclUndefined;
tmpError : IM!Error = OclUndefined;
fExpression : IM!FaultsExpressionNode = OclUndefined;
fSources : Set(IM!Fault) = Set{};
selFaults : Sequence(String) = OclUndefined;
tmpExpressions : Sequence(IM!FaultsExpressionNode) = Sequence{};
j : Integer = 0;
faultPort : String = OclUndefined;
faultMode : String = OclUndefined;
tmpFGE : IM!FaultsGenerateErrors = OclUndefined;
}
do {
--For every line of the FLA specification
for(spec in flaRules) {
j <- j+1;
tmpError <- c.Errors->select(e | e.localName = 'e_'+j);
tmpLeft <- spec.trim().split('->')->first().trim(); --Get right hand side
tmpFaults <- tmpLeft.split(','); --Get the different failures in the right hand side
--For every fault in the left side of the rule
tmpExpressions <- Sequence{};
for(fault in tmpFaults) {
faultPort <- fault.split('\\.')->first();
faultMode <- fault.split('\\.')->last();
if(faultMode = thisModule.flaNoFailure) {
selFaults <- c.Faults->select(ft | ft.getPortName() = faultPort);
fExpression <- thisModule.FEXP_MultiOr(
selFaults->collect(f | thisModule.FEXP_Fault(f))
);
fExpression <- thisModule.FEXP_Not(fExpression);
}else if(faultMode = thisModule.flaWildcard) {
selFaults <- c.Faults->select(ft | ft.getPortName() = faultPort);
fExpression <- thisModule.FEXP_MultiOr(
selFaults->collect(f | thisModule.FEXP_Fault(f))
);
}else{
selFaults <- c.Faults->select(ft | ft.localName = fault);
fExpression <- thisModule.FEXP_Fault(
selFaults->first()
);
}
tmpExpressions <- tmpExpressions->append(fExpression);
}
fExpression <- thisModule.FEXP_MultiAnd(tmpExpressions);
tmpFGE <- thisModule.AddFGE(selFaults, tmpError, 'det(0)'.parseDistribution(), 1, 1);
fExpression.faultsGenerateErrors <- tmpFGE;
tmpFGE.PropagationLogic <- fExpression;
tmpFGE.PropagationLogicStringFormat <- fExpression.toString();
}
}
}
rule ErrorModel_FGE(inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
st : CHESS!ErrorModelBehavior = inst.getSBAStereotype();
errorModel : CHESS!ErrorModel = st.errorModel->first();
states : Sequence(UML!State) = errorModel.base_StateMachine.ownedElement->first().ownedElement->select(e | e.oclIsKindOf(UML!State));
pseudo : Sequence(CHESS!Pseudostate) = errorModel.base_StateMachine.ownedElement->first().ownedElement->select(e | e.oclIsKindOf(CHESS!Pseudostate));
transitions : Sequence(UML!Transition) = errorModel.base_StateMachine.ownedElement->first().ownedElement->select(e | e.oclIsKindOf(UML!Transition));
tmpStereotype : OclAny = OclUndefined;
tmpExternalFaults : String = OclUndefined;
tmpFGE : IM!FaultsGenerateErrors = OclUndefined;
tmpIP : IM!InternalPropagation = OclUndefined;
tmpFEXP : IM!FaultsExpressionNode = OclUndefined;
tmpEEXP : IM!ErrorsExpressionNode = OclUndefined;
}
do {
--Transform ErrorModel <<InternalPropagation>> Transitions,
--for which the 'externalFaults' attribute is *not* empty.
--(the others have been processed previously in rule ErrorModelToComponent)
for(tr in transitions) {
tmpStereotype <- tr.getSBAStereotype();
if(tmpStereotype.oclIsTypeOf(CHESS!InternalPropagation)) {
if(tmpStereotype.oclIsTypeOf(CHESS!InternalFault)) {
--Do nothing (processed elsewhere)
}else{
--Match <<InternalPropagation>> stereotype only
if(tmpStereotype.externalFaults.oclIsUndefined()) {
--Do nothing (processed elsewhere)
}else{
--Process InternalPropagation that have a value
--in the externalFaults attribute
--Set a default for the delay and weight
if(tmpStereotype.delay.oclIsUndefined()) {
tmpStereotype.delay <- 'det(0)';
}
if(tmpStereotype.weight.oclIsUndefined()) {
tmpStereotype.weight <- '1';
}
if(tr.source.isInitialState()) {
tmpExternalFaults <- tmpStereotype.externalFaults;
tmpFEXP <- thisModule.FEXP_ParseString(tmpExternalFaults, inst);
tmpFGE <- thisModule.AddFGE(
tmpFEXP.faultsList(),
thisModule.errmodErrorMap->get(Tuple{e=tr.target, cc=c}),
tmpStereotype.delay.parseDistribution(),
1,
tmpStereotype.weight.toReal()
);
tmpFEXP.faultsGenerateErrors <- tmpFGE;
tmpFGE.PropagationLogic <- tmpFEXP;
tmpFGE.PropagationLogicStringFormat <- tmpFEXP.toString();
}
else{
thisModule.InternalPropagation(tmpStereotype,inst);
}
}
}
}
}
}
}
lazy rule AddExternalFault {
from
fault : String,
inst : UML!InstanceSpecification
to
xft : IM!ExternalFault (
Component <- thisModule.InstanceToComponent(inst),
Name <- inst.name + '_xft_' + fault
)
}
lazy rule ErrorModelStateToError {
from
state : UML!Vertex,
inst : UML!InstanceSpecification
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
}
to
err : IM!Error (
Name <- inst.name + '_' + state.name,
Component <- c
)
do {
thisModule.errmodErrorMap <- thisModule.errmodErrorMap->including(Tuple{e=state, cc=c}, err);
}
}
lazy rule InternalFault {
from
chIntFault : CHESS!InternalFault,
inst : UML!InstanceSpecification
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
}
to
ift : IM!InternalFault (
Name <- c.Name + '_ift_' + (c.Faults->select(f | f.oclIsKindOf(IM!InternalFault))->size()+1),
Occurrence <- chIntFault.occurrence.parseDistribution(),
PermanentProbability <- 1,
Component <- c,
TransientDuration <- thisModule.Deterministic(0)
),
fge : IM!FaultsGenerateErrors (
Name <- c.Name + '_fge_' + (c.FaultsGeneratesErrors->size()+1),
Component <- c,
Source <- Sequence{ift},
Destination <- thisModule.errmodErrorMap->get(Tuple{e=chIntFault.base_Transition.target, cc=c}),
Weight <- 1,
PropagationProbability <- 1,
ActivationDelay <- thisModule.Deterministic(0),
PropagationLogic <- thisModule.FEXP_Fault(ift),
PropagationLogicStringFormat <- fge.PropagationLogic.toString()
)
do {
--Workaround for the DEEM simulator crashing when InternalFaults
--with zero delay are present in the model
if(ift.Occurrence.oclIsTypeOf(IM!Deterministic)) {
if(ift.Occurrence.Value = 0) {
ift.Occurrence.Value <- '1e-100'.toReal();
}
}
}
}
lazy rule InternalPropagation {
from
chIntProp : CHESS!InternalPropagation,
inst : UML!InstanceSpecification
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
myDelay : String = if chIntProp.delay.oclIsUndefined() then 'det(0)' else chIntProp.delay endif;
myWeight : Real = if chIntProp.weight.oclIsUndefined() then 1 else chIntProp.weight.toReal() endif;
}
to
imIntProp : IM!InternalPropagation (
Component <- c,
Name <- c.Name + '_intprop_' + (c.InternalPropagation->size()+1),
Source <- Sequence{thisModule.errmodErrorMap->get(Tuple{e=chIntProp.base_Transition.source, cc=c})},
Destination <- Sequence{thisModule.errmodErrorMap->get(Tuple{e=chIntProp.base_Transition.target, cc=c})},
PropagationProbability <- 1,
PropagationDelay <- myDelay.parseDistribution(),
Weight <- myWeight,
PropagationLogic <- thisModule.EEXP_Error(imIntProp.Source->first()),
PropagationLogicStringFormat <- imIntProp.PropagationLogic.toString(),
FaultGuard <- thisModule.FEXP_ParseString(chIntProp.externalFaults, inst)
)
}
rule AddFailureMode(name : String, c : IM!Component) {
to
fm : IM!FailureMode (
Name <- c.Name + '_' + name
)
do {
c.FailureModes <- c.FailureModes->append(fm);
fm;
}
}
rule AddError(name : String, c : IM!Component) {
to
e : IM!Error (
Name <- c.Name + '_' + name,
Component <- c
)
do {
e;
}
}
lazy rule AddEPFFromErrorModelFailure {
from
f : CHESS!Failure,
inst : UML!InstanceSpecification
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
eSource : IM!Error = thisModule.errmodErrorMap->get(Tuple{e=f.base_Transition.source, cc=c});
myDelay : String = if f.delay.oclIsUndefined() then 'det(0)' else f.delay endif;
myWeight : Real = if f.weight.oclIsUndefined() then 1 else f.weight.toReal() endif;
}
to
epf : IM!ErrorsProducesFailures (
Name <- c.Name + '_epf_' + (c.ErrorsGeneratesFailures->size()+1),
Source <- Sequence{eSource},
Destination <- c.FailureModes->select(fm | f.mode->includes(fm.localName)),
Component <- c,
PropagationDelay <- myDelay.parseDistribution(),
PropagationProbability <- 1,
Weight <- myWeight,
PropagationLogic <- thisModule.EEXP_Error(eSource),
PropagationLogicStringFormat <- epf.PropagationLogic.toString()
)
do {
epf;
}
}
rule AddFLARuleEPF(e : IM!Error) {
to
epf : IM!ErrorsProducesFailures (
Name <- e.Name + '_epf',
Source <- Sequence{e},
Destination <- Sequence{},
Component <- e.Component,
PropagationDelay <- thisModule.Deterministic(0),
PropagationProbability <- 1,
Weight <- 1,
PropagationLogic <- thisModule.EEXP_Error(e),
PropagationLogicStringFormat <- epf.PropagationLogic.toString()
)
do{
epf;
}
}
rule AddFGE(f : Sequence(IM!Fault), e : Sequence(IM!Error), delay : IM!Distribution, p : Real, weight : Real) {
using {
c : IM!Component = f->first().Component;
}
to
fge : IM!FaultsGenerateErrors (
Name <- c.Name + '_fge_' + (c.FaultsGeneratesErrors->size()+1),
Component <- c,
Source <- f,
Destination <- e,
ActivationDelay <- delay,
PropagationProbability <- p,
Weight <- weight
)
do {
fge;
}
}
rule AddEPF(e : IM!Error, fm : IM!FailureMode, delay : IM!Distribution, p : Real, weight : Real) {
using {
c : IM!Component = fm.Component;
}
to
epf : IM!ErrorsProducesFailures (
Name <- c.Name + '_epf_' + (c.ErrorsGeneratesFailures->size()+1),
Component <- c,
Source <- Set{e},
Destination <- Set{fm},
PropagationDelay <- delay,
PropagationProbability <- p,
Weight <- weight,
PropagationLogic <- thisModule.EEXP_Error(e),
PropagationLogicStringFormat <- epf.PropagationLogic.toString()
)
}
rule AddSourceError(fm : IM!FailureMode) {
using {
c : IM!Component = fm.Component;
}
to
e : IM!Error (
Name <- c.Name + '_e_' + fm.Name,
Component <- c
),
epf : IM!ErrorsProducesFailures (
Source <- Set{e},
Destination <- Set{fm},
Component <- c,
PropagationLogic <- thisModule.EEXP_Error(e),
PropagationLogicStringFormat <- epf.PropagationLogic.toString()
)
}
--------------------------------------------------------------------
-- Rules related to the definition of the metric
--------------------------------------------------------------------
lazy rule newEvalIntervalOfTime {
from
t : Real
to
iot : IM!IntervalOfTimeAveraged
(
begin <- 0,
end <- t
)
}
lazy rule newEvalInstantOfTime {
from
t : Real
to
instant : IM!InstantOfTime ( timePoint <- t )
}
--Find target failure modes to be considered based on the attributes
--of the StateBasedAnalysis stereotype.
rule FindTargetFailureModes(sba : CHESS!StateBasedAnalysis) {
using {
targets : Set(UML!InstanceSpecification) = Set{};
targetSlots : Set(UML!Slot) = Set{};
fmSelected : Set(IM!FailureMode) = Set{};
}
do {
--Find target components based on two attributes
-->platform
-->targetDepComponent
if(sba.targetDepComponent.isEmpty()) {
targets <- sba.platform->collect(p | p.base_Package.ownedMember->first())->flatten();
}else{
targets <- sba.targetDepComponent;
}
--Find ports of target components having an output dataflow
targetSlots <- targets->collect(i | i.getPortSlots())
->flatten()
->select(sl | sl.hasOutputFlow());
--Filter ports based on 'targetPort', if set
if(not sba.targetPort.isEmpty()) {
targetSlots <- sba.targetPort.asSet()->intersection(targetSlots);
}
--Process possibly existing downward delegations
targetSlots <- targetSlots->collect(sl | sl.getSBADelegationsDownwards())->flatten();
--Find all failure modes related to the selected ports
fmSelected <-
targetSlots->collect(sl | thisModule.InstanceToComponent(sl.refImmediateComposite()).FailureModes->select(fm | fm.getPortName() = sl.name))
->flatten()->asSet();
--Filter failure modes based on 'targetFailureMode', if set
if(not sba.targetFailureMode->isEmpty()) {
fmSelected <-
fmSelected->select(fm | sba.targetFailureMode->contains(fm.getModeName()));
}
fmSelected;
}
}
rule Reliability(sba : CHESS!StateBasedAnalysis, time : Real){
using {
strClean : String = sba.measure.regexReplaceAll('[={}()]', ' ').trim();
iInstant : Integer = strClean.indexOf('instantOfTime');
imsistema : IM!Sistema = IM!Sistema.allInstances()->first();
}
to
re : IM!Reliability (
Name <- sba.base_NamedElement.name,
target <- thisModule.FindTargetFailureModes(sba)
)
do{
imsistema.measures.add(re);
if (iInstant > 0) {
re.evaluations.add(
thisModule.newEvalInstantOfTime(
strClean.substring(iInstant + 1 + 'instantOfTime'.size(), strClean.size()).toReal()
)
);
}
else{
--Should not happen!
}
}
}
rule Availability(sba : CHESS!StateBasedAnalysis) {
using {
strClean : String = sba.measure.regexReplaceAll('[={}()]', ' ').trim();
iInterval : Integer = strClean.indexOf('intervalEnd');
iInstant : Integer = strClean.indexOf('instantOfTime');
imsistema : IM!Sistema = IM!Sistema.allInstances()->first();
}
to
re : IM!Availability (
Name <- sba.base_NamedElement.name,
target <- thisModule.FindTargetFailureModes(sba)
)
do{
imsistema.measures.add(re);
if (iInterval > 0) {
re.evaluations.add(
thisModule.newEvalIntervalOfTime(
strClean.substring(iInterval + 1 + 'intervalEnd'.size(), strClean.size()).toReal()
)
);
}
else if (iInstant > 0) {
re.evaluations.add(
thisModule.newEvalInstantOfTime(
strClean.substring(iInstant + 1 + 'instantOfTime'.size(), strClean.size()).toReal()
)
);
}
else{
--Should not happen!
}
}
}
rule PFD(sba : CHESS!StateBasedAnalysis) {
using {
strClean : String = sba.measure.regexReplaceAll('[={}()]', ' ').trim();
imsistema : IM!Sistema = IM!Sistema.allInstances()->first();
}
to
pfd : IM!FailureProbability (
Name <- sba.base_NamedElement.name,
target <- thisModule.FindTargetFailureModes(sba)
)
do{
imsistema.measures.add(pfd);
pfd.evaluations.add(
thisModule.newEvalInstantOfTime(
strClean.regexReplaceAll('PFD', ' ').trim().toReal()
)
);
}
}
--------------------------------------------------------------------
-- Rules to create IM!Distribution elements
--------------------------------------------------------------------
lazy rule Exponential {
from
lambda : Real
to
e : IM!Exponential ( Rate <- lambda )
}
lazy rule Deterministic {
from
value : Real
to
d : IM!Deterministic ( Value <- value )
}
lazy rule Uniform {
from
lower : Real,
upper : Real
to
d : IM!Uniform (
Lower <- lower,
Upper <- upper
)
}
lazy rule Gaussian {
from
mean : Real,
variance : Real
to
g : IM!Gaussian (
Mean <- mean,
Variance <- variance
)
}
lazy rule Gamma {
from
a : Real,
b : Real
to
g : IM!Gamma (
Alpha <- a,
Beta <- b
)
}
lazy rule Weibull {
from
a : Real,
b : Real
to
g : IM!Weibull (
Alpha <- a,
Beta <- b
)
}
--------------------------------------------------------------------
-- Rules to build Faults/Errors expressions
--------------------------------------------------------------------
rule FEXP_Fault(f: IM!Fault) {
to
fefn : IM!FaultsExpressionFaultNode (
Fault <- f
)
do{
fefn;
}
}
rule FEXP_Or(e1 : IM!FaultsExpressionNode, e2: IM!FaultsExpressionNode) {
to
feon : IM!FaultsExpressionOrNode (
FaultsExpression1 <- e1,
FaultsExpression2 <- e2
)
do{
feon;
}
}
rule FEXP_And(e1 : IM!FaultsExpressionNode, e2: IM!FaultsExpressionNode) {
to
fean : IM!FaultsExpressionAndNode (
FaultsExpression1 <- e1,
FaultsExpression2 <- e2
)
do{
fean;
}
}
rule FEXP_Not(e : IM!FaultsExpressionNode) {
to
fenn : IM!FaultsExpressionNotNode (
FaultsExpression <- e
)
do {
fenn;
}
}
rule FEXP_MultiOr(fe : Sequence(IM!FaultsExpressionNode)) {
using {
tmpExpression1 : IM!FaultsExpressionNode = OclUndefined;
tmpExpression2 : IM!FaultsExpressionNode = OclUndefined;
tmpSequence : Sequence(IM!Fault) = fe;
}
do {
if(fe->size() = 1) {
tmpExpression1 <- fe->first();
}else{
tmpExpression1 <- tmpSequence->first();
tmpSequence <- tmpSequence.subSequence(2, tmpSequence.size());
tmpExpression2 <- tmpSequence->first();
tmpSequence <- tmpSequence.subSequence(2, tmpSequence.size());
tmpExpression1 <- thisModule.FEXP_Or(tmpExpression1,tmpExpression2);
for(ft in tmpSequence) {
tmpExpression2 <- thisModule.FEXP_Or(
tmpExpression1,
ft
);
tmpExpression1 <- tmpExpression2;
}
}
tmpExpression1;
}
}
rule FEXP_MultiAnd(fe : Sequence(IM!FaultsExpressionNode)) {
using {
tmpExpression1 : IM!FaultsExpressionNode = OclUndefined;
tmpExpression2 : IM!FaultsExpressionNode = OclUndefined;
tmpSequence : Sequence(IM!Fault) = fe;
}
do {
if(fe->size() = 1) {
tmpExpression1 <- fe->first();
}else{
tmpExpression1 <- tmpSequence->first();
tmpSequence <- tmpSequence.subSequence(2, tmpSequence.size());
tmpExpression2 <- tmpSequence->first();
tmpSequence <- tmpSequence.subSequence(2, tmpSequence.size());
tmpExpression1 <- thisModule.FEXP_And(tmpExpression1,tmpExpression2);
for(ft in tmpSequence) {
tmpExpression2 <- thisModule.FEXP_And(
tmpExpression1,
ft
);
tmpExpression1 <- tmpExpression2;
}
}
tmpExpression1;
}
}
rule EEXP_Error(e: IM!Error) {
to
eeen : IM!ErrorsExpressionErrorNode (
Error <- e
)
do{
eeen;
}
}
--Parses a string into a FaultsExpression
---TODO: Implement more advanced parsing
rule FEXP_ParseString(exp : String, inst : UML!InstanceSpecification) {
using {
c : IM!Component = thisModule.InstanceToComponent(inst);
tmpSplit : Sequence(String) = OclUndefined;
expRet : IM!FaultsExpressionNode = OclUndefined;
}
do {
if(not exp.oclIsUndefined()) {
tmpSplit <- exp.split(' and | AND ');
if(tmpSplit.size() > 1) {
expRet <-
thisModule.FEXP_MultiAnd(
tmpSplit->collect(
ft | c.Faults->select(ff | ff.localName = ft.trim())->first()
)->
flatten()->
collect(ft | thisModule.FEXP_Fault(ft))
);
}else {
tmpSplit <- exp.split(' or | OR ');
if(tmpSplit.size() > 1) {
expRet <-
thisModule.FEXP_MultiOr(
tmpSplit->collect(
s | c.Faults->select(ft | ft.localName = s.trim())
)->
flatten()->
collect(ft | thisModule.FEXP_Fault(ft))
);
}else {
expRet <- thisModule.FEXP_Fault(tmpSplit->first());
}
}
}
expRet;
}
}
rule setFGEBackLinks(fen: IM!FaultsExpressionNode, fge: IM!FaultsGenerateErrors ) {
do {
fen.faultsGenerateErrors <- fge;
if (fen.oclIsTypeOf(IM!FaultsExpressionOrNode)) {
thisModule.setFGEBackLinks(fen.FaultsExpression1, fge);
thisModule.setFGEBackLinks(fen.FaultsExpression2, fge);
}else if (fen.oclIsTypeOf(IM!FaultsExpressionAndNode)){
thisModule.setFGEBackLinks(fen.FaultsExpression1, fge);
thisModule.setFGEBackLinks(fen.FaultsExpression2, fge);
}else if (fen.oclIsTypeOf(IM!FaultsExpressionNotNode)) {
thisModule.setFGEBackLinks(fen.FaultsExpression, fge);
}
}
}
rule setEPFBackLinks(een: IM!ErrorsExpressionNode, epf: IM!ErrorsProducesFailures ) {
do {
een.errorPropagation <- epf;
}
}
rule setIPBackLinks(een: IM!ErrorsExpressionNode, ip: IM!InternalPropagation ) {
do {
een.errorPropagation <- ip;
}
}
--Rule for Repair activities
unique lazy rule RepairActivity {
from
r : CHESS!Repair
to
act : IM!RepairActivity
(
Name <- r.base_Activity.name,
SuccessProbability <- r.probSuccess.toReal(),
Duration <- r.duration.parseDistribution(),
When <- timeexp
),
timeexp : IM!ScheduleExpression
(
T <-
if r.when.trim().startsWith('Periodic') then
thisModule.SCHEXP_Periodic(r.when)
else
if r.when.trim().startsWith('AtTime') then
thisModule.SCHEXP_AtTime(r.when)
else
OclUndefined
endif
endif,
EX <- timeexp_ex
),
timeexp_ex : IM!ScheduleExpressionTrue
do {
act.Target <- UML!Slot.allInstances()
->select(sl | r.targets->includes(sl.definingFeature))
->collect(sl | sl.value->first().instance)
->select(i | thisModule.umlInstancesRelevant->includes(i))
->collect(i | thisModule.InstanceToComponent(i));
}
}
--Rule for ErrorDetection activities
unique lazy rule ErrorDetectionActivity {
from
r : CHESS!ErrorDetection
to
act : IM!DetectionActivity
(
Name <- r.base_Activity.name,
Coverage <- r.probSuccess.toReal(),
Duration <- r.duration.parseDistribution(),
When <- timeexp
),
timeexp : IM!ScheduleExpression
(
T <-
if r.when.trim().startsWith('Periodic') then
thisModule.SCHEXP_Periodic(r.when)
else
if r.when.trim().startsWith('AtTime') then
thisModule.SCHEXP_AtTime(r.when)
else
OclUndefined
endif
endif,
EX <- timeexp_ex
),
timeexp_ex : IM!ScheduleExpressionTrue
do {
act.Target <- UML!Slot.allInstances()
->select(sl | r.targets->includes(sl.definingFeature))
->collect(sl | sl.value->first().instance)
->collect(i | thisModule.InstanceToComponent(i));
}
}
--rule RepairActivity(r : IM!RepairActivity){
--
-- to
-- se : IM!ScheduleExpression
-- (
-- T <- si
-- ),
-- si : IM!ScheduleExpressionImmediately
-- do{
-- r.When <- se;
-- for (c in r.Target){
-- for(fm in c.FailureModes) {
-- thisModule.SchedCond(fm);
-- }
-- }
-- if (thisModule.TempScen->size() = 1){
-- se.EX <- thisModule.TempScen->first();
-- }else{
-- for(scen in thisModule.TempScen){
-- if (scen <> thisModule.TempScen->last()){
-- thisModule.CreateScenOrExpr();
-- }
-- }
-- thisModule.TempScen->addAll(thisModule.TempScenSeq);
--
-- for(scen in thisModule.TempScen){
-- if (scen.oclIsTypeOf(IM!ScheduleExpressionOr)){
-- scen.e1 <- thisModule.TempScen.at(thisModule.Counter);
-- thisModule.Counter <- thisModule.Counter+1;
-- scen.e2 <- thisModule.TempScen.at(thisModule.Counter);
-- thisModule.Counter <- thisModule.Counter+1;
-- }
-- }
-- se.EX <- thisModule.TempScen->last();
-- }
--
-- thisModule.TempScen.clear();
-- thisModule.TempScenSeq.clear();
-- thisModule.Counter <- 1;
-- }
--}
rule SchedCond(fm : IM!FailureMode){
to
scefn : IM!ScheduleExpressionFailed (
failureMode <- fm
)
do{
thisModule.TempScen.add(scefn);
}
}
rule CreateScenOrExpr(){
to
sceon : IM!ScheduleExpressionOr
do{
thisModule.TempScenSeq.add(sceon);
}
}
--------------------------------------------------------------------
-- Rules to generate ScheduleExpression elements
--------------------------------------------------------------------
lazy rule SCHEXP_Periodic {
from
s : String
using {
sClean : String = s.regexReplaceAll('[={}()]', ' ').trim();
}
to
p : IM!ScheduleExpressionPeriodic
(
PeriodDuration <- d
),
d : IM!Deterministic
(
Value <- sClean.substring('Periodic'.size()+1, sClean.size()).toReal()
)
}
lazy rule SCHEXP_AtTime {
from
s : String
using {
sClean : String = s.regexReplaceAll('[={}()]', ' ').trim();
}
to
p : IM!ScheduleExpressionAtTime
(
t <- sClean.substring('AtTime'.size()+1, sClean.size()).toReal()
)
}
rule SCHEXP_Or(exp1 : IM!ScheduleExpressionCond, exp2 : IM!ScheduleExpressionCond) {
to
e : IM!ScheduleExpressionOr
(
e1 <- exp1,
e2 <- exp2
)
do {
e;
}
}
rule SCHEXP_And(exp1 : IM!ScheduleExpressionCond, exp2 : IM!ScheduleExpressionCond) {
to
e : IM!ScheduleExpressionAnd
(
e1 <- exp1,
e2 <- exp2
)
do {
e;
}
}
rule SCHEXP_FailureMode(fm : IM!FailureMode) {
to
e : IM!ScheduleExpressionFailed
(
failureMode <- fm
)
do {
e;
}
}
rule SCHEXP_MultiOr(schSeq : Set(IM!ScheduleExpressionCond)) {
using {
tmpExpression1 : IM!ScheduleExpressionCond = OclUndefined;
tmpExpression2 : IM!ScheduleExpressionCond = OclUndefined;
tmpSequence : Sequence(IM!ScheduleExpressionCond) = schSeq;
}
do {
if(schSeq->size() = 1) {
tmpExpression1 <- schSeq->first();
}else{
tmpExpression1 <- tmpSequence->first();
tmpSequence <- tmpSequence.subSequence(2, tmpSequence.size());
-- tmpExpression2 <- tmpSequence->first();
-- tmpSequence <- tmpSequence.subSequence(2, tmpSequence.size());
--
-- tmpExpression1 <- thisModule.SCHEXP_Or(tmpExpression1,tmpExpression2);
for(ee in tmpSequence) {
tmpExpression2 <- thisModule.SCHEXP_Or(
tmpExpression1,
ee
);
tmpExpression1 <- tmpExpression2;
}
}
tmpExpression1;
}
}
rule SCHEXP_FailureModesCollection(fms : Set(IM!FailureMode)) {
using {
tmp : IM!ScheduleExpressionCondition = OclUndefined;
}
do {
tmp <-
thisModule.SCHEXP_MultiOr(
fms->collect(fm | thisModule.SCHEXP_FailureMode(fm))
);
tmp;
}
}
--------------------------------------------------------------------
-- Rules for allocation
--------------------------------------------------------------------
rule Allocation(a : MARTE!Assign) {
using {
tmpXFT : IM!ExternalFault = OclUndefined;
}
do {
for(instFrom in a.from) {
for(instTo in a.to) {
for(fm in thisModule.InstanceToComponent(instTo).FailureModes) {
tmpXFT <- thisModule.AddExternalFault(fm.getModeName(), instFrom);
tmpXFT.Source <- fm;
tmpXFT.Name <- instFrom.name + '_allocation_' + fm.Name;
}
}
}
}
}
--rule Assign (a : MARTE!Assign){
--
-- do{
-- --"from" and "to" are keywords in ATL... (works anyway, only issue: they are highlighted)
-- thisModule.Instances.addAll(a.from);
---- thisModule.Components.addAll(a.to->collect(f | f.classifier->first()));
--
-- --get also connectors from the allocated HW/SW
-- for (f in a.from){
-- thisModule.Connectors.addAll(f.owner.getConnectors);
-- }
-- for (t in a.to){
-- thisModule.Connectors.addAll(t.owner.getConnectors);
-- }
--
-- --finally get ports from the allocated HW/SW
-- for (f in a.from){
-- for (i in f.owner.getInstances){
-- thisModule.Ports.addAll(i.slot->collect(d | d.definingFeature));
-- }
-- }
-- for (t in a.to){
-- for (i in t.owner.getInstances){
-- thisModule.Ports.addAll(i.slot->collect(d | d.definingFeature));
-- }
-- }
-- }
--}
--Find allocation specifications related to a given platform
helper context UML!Package def : getAllocations() : Set(MARTE!Assign) =
MARTE!Assign.allInstances()->select(a | a.base_Comment.owner = self.ownedElement->first().classifier->first());
--Find instances involved in allocations related to a given platform
helper context UML!Package def: getAllocationsInstances() : Set(UML!InstanceSpecification) =
self.getAllocations()->collect(a | a.from->union(a.to))->flatten();
--Check if a IM!Component already contains a specific failure mode
helper context IM!Component def: hasFailureMode(fm : String) : Boolean =
not self.FailureModes->select(f | f.localName.trim() = fm.trim())->isEmpty();
--Check if a IM!Component already contains a specific fault
helper context IM!Component def: hasFault(fm : String) : Boolean =
not self.Faults->select(f | f.localName.trim() = fm.trim())->isEmpty();
--Get <<Failure>> stereotype from a Transition
helper context UML!Transition def: getFailureStereotype() : CHESS!Failure =
CHESS!Failure.allInstances()->select(f | f.base_Transition = self)->first();
--Get <<ErrorState>> stereotype from a State
helper context UML!State def: getErrorStateStereotype() : CHESS!ErrorState =
CHESS!ErrorState.allInstances()->select(e | e.base_State = self)->first();
--Check if a Vertex is an initial state (healty state of the error model)
helper context UML!Vertex def: isInitialState() : Boolean =
if(self.oclIsKindOf(CHESS!Pseudostate)) then
self.kind = #initial
else
false
endif;
--Remove the component name
helper context String def: noNamespace(n : String) : String =
self.regexReplaceAll(n + '_', '');
helper context IM!Fault def: localName : String =
let fClean : String = self.Name.noNamespace(self.Component.Name)
in fClean.substring(5, fClean.size()); --Removes the initial xft_ or ift_ prefix
helper context IM!Error def: localName : String =
self.Name.noNamespace(self.Component.Name);
helper context IM!FailureMode def: localName : String =
self.Name.noNamespace(self.Component.Name);
helper context IM!Threat def: fullName : String = self.Name;
--Get info on a IM!Fault and IM!FailureMode
helper context IM!Fault def: getPortName() : String =
self.localName.split('\\.').at(1);
helper context IM!Fault def: getModeName() : String =
self.localName.split('\\.').at(2);
helper context IM!FailureMode def: getPortName() : String =
self.localName->split('\\.')->at(1);
helper context IM!FailureMode def: getModeName() : String =
self.localName.split('\\.').at(2);
--------------------------------------------------------------------
-- Parse strings in VSL notation into IM!Distribution elements
--------------------------------------------------------------------
helper context String def: parseDistribution() : IM!Distribution =
let dist : String = self.trim().toLower() in
if dist.startsWith('exp') then
dist.parseExponential()
else if dist.startsWith('det') then
dist.parseDeterministic()
else if dist.startsWith('uni') then
dist.parseUniform()
else if dist.startsWith('norm') or dist.startsWith('gauss') then
dist.parseGaussian()
else if dist.startsWith('gam') then
dist.parseGamma()
else if dist.startsWith('wei') then
dist.parseWeibull()
else
thisModule.Exponential(0)
endif endif endif endif endif endif;
helper context String def: parseExponential() : IM!Exponential =
thisModule.Exponential(self.substring(self.indexOf('(')+2, self.indexOf(')')).toReal());
helper context String def: parseDeterministic() : IM!Deterministic =
thisModule.Deterministic(self.substring(self.indexOf('(')+2, self.indexOf(')')).toReal());
helper context String def: parseUniform() : IM!Uniform =
let iComma : Integer = self.indexOf(',') in
thisModule.Uniform(
self.substring(self.indexOf('(')+2, iComma).toReal(),
self.substring(iComma+2, self.indexOf(')')).toReal()
);
helper context String def: parseGaussian() : IM!Gaussian =
let iComma : Integer = self.indexOf(',') in
thisModule.Gaussian(
self.substring(self.indexOf('(')+2, iComma).toReal(),
self.substring(iComma+2, self.indexOf(')')).toReal()
);
helper context String def: parseGamma() : IM!Gamma =
let iComma : Integer = self.indexOf(',') in
thisModule.Gamma(
self.substring(self.indexOf('(')+2, iComma).toReal(),
self.substring(iComma+2, self.indexOf(')')).toReal()
);
helper context String def: parseWeibull() : IM!Gamma =
let iComma : Integer = self.indexOf(',') in
thisModule.Weibull(
self.substring(self.indexOf('(')+2, iComma).toReal(),
self.substring(iComma+2, self.indexOf(')')).toReal()
);
--------------------------------------------------------------------
-- Collections that are used to filter and categorize model elements
--------------------------------------------------------------------
helper def : Instances : Sequence(UML2!InstanceSpecification) = Sequence {};
helper def : Connectors : Set(UML2!InstanceSpecification) = Set {};
helper def : Comments : Set (UML2!Comment) = Set {};
helper def : Ports : Set (UML2!Port) = Set {};
helper def : States : Set(UML2!State) = Set{};
helper def : Transitions : Set(UML2!Tansition) = Set{};
helper context UML!InstanceSpecification def: getBaseItem() : UML!Classifier = self.classifier->first();
--Find the SimpleStochasticBehavior element associated with a Classifier or an InstanceSpecification
--if it exists. Returns OclUndefined otherwise
helper context UML!Classifier def: getSimpleStochasticBehavior() : CHESS!SimpleStochasticBehavior =
CHESS!SimpleStochasticBehavior->allInstances()->select(ssb | ssb.base_Class = self)->first();
helper context UML!InstanceSpecification def: getSimpleStochasticBehavior() : CHESS!SimpleStochasticBehavior =
let instssb : CHESS!SimpleStochasticBehavior =
CHESS!SimpleStochasticBehavior->allInstances()->select(ssb | ssb.base_InstanceSpecification = self)->first() in
if instssb <> OclUndefined then instssb else
let base : UML!Class = self.getBaseItem() in
if base = OclUndefined then base else base.getSimpleStochasticBehavior() endif
endif;
--------------------------------------------------------------------
-- Helpers to get dependability information from stereotypes
--------------------------------------------------------------------
--Do we have dependability information for this instance?
helper context UML!InstanceSpecification def: hasSBAInformation() : Boolean = self.getSBAStereotype() <> OclUndefined;
--If the InstanceSpecification has its own stereotype then return it,
-- otherwise return the one of the classifier
helper context UML!InstanceSpecification def: getSBAStereotype() : OclAny =
let s : OclAny = self.getSBAStereotypeInstance() in
if s = OclUndefined then self.classifier->first().getSBAStereotypeClassifier() else s endif;
--Get the SBA stereotype applied to the instance, if any
helper context UML!InstanceSpecification def: getSBAStereotypeInstance() : OclAny =
thisModule.sbaStereotypes->collect(s | s.allInstances())->flatten()->select(st | st.base_InstanceSpecification = self)->first();
--Find the CHESS stereotype that is used on a given instance specification, or on its classifier
helper context UML!Class def: getSBAStereotypeClassifier() : OclAny =
thisModule.sbaStereotypes->collect(s | s.allInstances())->flatten()->select(st | st.base_Class = self)->first();
--Recursive helper to identify which instances need to be taken into account,
--i.e., to identify those that have dependability information attached, or no
--subinstances
helper context UML!InstanceSpecification def: findSBAConstituents() : Set(UML!InstanceSpecification) =
if self.hasSBAInformation() or self.getSubInstances().isEmpty() then
Set{self}
else
self.getSubInstances()->collect(i | i.findSBAConstituents())->flatten()
endif;
--Get the stereotype associated to an error model transition
helper context UML!Transition def: getSBAStereotype() : OclAny =
thisModule.sbaTransitions->collect(s | s.allInstances())->
flatten()->select(t | t.base_Transition = self)->
first();
--Does this error model transition has dependability information associated with it?
helper context UML!Transition def: hasSBAInformation() : Boolean = not self.getSBAStereotype().oclIsUndefined();
--------------------------------------------------------------------
-- Helpers to get, start from a given InstanceSpecification,
-- port instances and subcomponent instances
--------------------------------------------------------------------
helper context UML!InstanceSpecification def: getPortSlots() : Set(UML!Slot) =
self.slot->select(s | s.definingFeature.oclIsKindOf(UML!Port));
helper context UML!InstanceSpecification def: getSubInstanceSlots() : Set(UML!Slot) =
self.slot->select(s | not s.definingFeature.oclIsKindOf(UML!Port));
helper context UML!InstanceSpecification def: getSubInstances() : Set(UML!InstanceSpecification) =
self.getSubInstanceSlots()->collect(s | s.value->first().instance);
helper context UML!InstanceSpecification def: isSubInstanceOf(parent : UML!InstanceSpecification) : Boolean =
parent.getSubInstances()->includes(self);
--Get the name of a port slot, as the name of the originating port
helper context UML!Slot def: name : String = self.definingFeature.name;
--helper context UML!Slot def: getConnectedSlotsInput() : Set(UML!Slot) =
-- self;
--helper context UML!Slot def: getConnectedSlotsOutput() : Set(UML!Slot) =
-- self;
--helper context UML!Slot def: getConnectedSlots() : Set(UML!Slot) =
-- self.getConnectedSlotsInput->union(self.getConnectedSlotsOutput);
--------------------------------------------------------------------
-- Check if a Port (or Slot) has input or output dataflow
--------------------------------------------------------------------
helper context UML!Slot def: hasInputFlow() : Boolean = self.definingFeature.hasInputFlow();
helper context UML!Slot def: hasOutputFlow() : Boolean = self.definingFeature.hasOutputFlow();
helper context UML!Port def: hasInputFlow() : Boolean =
let clientserverport : MARTE!ClientServerPort = MARTE!ClientServerPort.allInstances()->select(c | c.base_Port = self)->first() in
let flowport : SYSML!FlowPort = SYSML!FlowPort.allInstances()->select(c | c.base_Port = self)->first() in
let flowportmarte : MARTE!FlowPort = MARTE!FlowPort.allInstances()->select(c | c.base_Port = self)->first() in
if clientserverport <> OclUndefined then clientserverport.hasInputFlow() else
if flowport <> OclUndefined then flowport.hasInputFlow() else
if flowportmarte <> OclUndefined then flowportmarte.hasInputFlowMarte() else
false
endif endif endif;
helper context UML!Port def: hasOutputFlow() : Boolean =
let clientserverport : MARTE!ClientServerPort = MARTE!ClientServerPort.allInstances()->select(c | c.base_Port = self)->first() in
let flowport : SYSML!FlowPort = SYSML!FlowPort.allInstances()->select(c | c.base_Port = self)->first() in
let flowportmarte : MARTE!FlowPort = MARTE!FlowPort.allInstances()->select(c | c.base_Port = self)->first() in
if clientserverport <> OclUndefined then clientserverport.hasOutputFlow() else
if flowport <> OclUndefined then flowport.hasOutputFlow() else
if flowportmarte <> OclUndefined then flowportmarte.hasOutputFlowMarte() else
false
endif endif endif;
helper context SYSML!FlowPort def: hasInputFlow() : Boolean = self.direction <> #out;
helper context SYSML!FlowPort def: hasOutputFlow() : Boolean = self.direction = #out or self.direction = #inout;
helper context MARTE!FlowPort def: hasInputFlowMarte() : Boolean = self.direction <> #out;
helper context MARTE!FlowPort def: hasOutputFlowMarte() : Boolean = self.direction = #out or self.direction = #inout;
helper context MARTE!ClientServerPort def: hasInputFlow() : Boolean = self.kind <> #provided;
helper context MARTE!ClientServerPort def: hasOutputFlow() : Boolean = self.kind <> #required;
--------------------------------------------------------------------
-- Helpers to explore the model and get the component that is
-- connected to the other side of a port
--------------------------------------------------------------------
--Get connectors that are linked to a certain port instance
helper context UML!Slot def: getConnectors() : Set(UML!InstanceSpecification) =
thisModule.umlInstancesConnectors->
select(c | not c.slot->select(s | s.definingFeature = self.definingFeature
and s.value->first().instance = self.refImmediateComposite())->isEmpty());
--Is the connector instance a "normal" connection
--betweentwo components at the same level?
helper context UML!InstanceSpecification def: isConnection() : Boolean =
let sl : OrderedSet(UML!Slot) = self.slot->asOrderedSet() in
let i1 : UML!InstanceSpecification = sl->first().value->first().instance in
let i2 : UML!InstanceSpecification = sl->last().value->first().instance in
if i1.oclIsUndefined() or i2.oclIsUndefined() then false else
not i1.isSubInstanceOf(i2) and not i2.isSubInstanceOf(i1)
endif;
--Is the connector instance a delegation?
helper context UML!InstanceSpecification def: isDelegation() : Boolean =
let sl : OrderedSet(UML!Slot) = self.slot->asOrderedSet() in
let i1 : UML!InstanceSpecification = sl->first().value->first().instance in
let i2 : UML!InstanceSpecification = sl->last().value->first().instance in
i1.isSubInstanceOf(i2) or i2.isSubInstanceOf(i1);
--Get port instances that are *directly* connected to a certain port instance
helper context UML!Slot def: getConnectedImmediate() : Set(UML!Slot) =
let connectorsSlots : Set(UML!Slot) =
self.getConnectors()->select(c | c.isConnection())->
collect(c | c.slot)->
flatten()->
select(s | s.definingFeature <> self.definingFeature)
in
connectorsSlots->collect(s | s.value->first().instance.slot->
select(sl | sl.definingFeature = s.definingFeature))->flatten();
--Get port instances that receive/send delegation from/to a certain port instance
helper context UML!Slot def: getDelegationEnds() : Set(UML!Slot) =
let connectorsSlots : Set(UML!Slot) =
self.getConnectors()->select(c | c.isDelegation())->
collect(c | c.slot)->
flatten()->
select(s | s.definingFeature <> self.definingFeature)
in
connectorsSlots->collect(s | s.value->first().instance.slot->
select(sl | sl.definingFeature = s.definingFeature))->flatten();
--Get taget(s) of delegation in sub-instances
helper context UML!Slot def: getDelegationEndsDownwards() : Set(UML!Slot) =
self.getDelegationEnds()->select(s | s.refImmediateComposite().isSubInstanceOf(self.refImmediateComposite()));
--Get source(s) of delegation in parent instance
helper context UML!Slot def: getDelegationEndsUpwards() : Set(UML!Slot) =
self.getDelegationEnds()->select(s | self.refImmediateComposite().isSubInstanceOf(s.refImmediateComposite()));
--Get the target of delegation taking into account SBA stereotypes,
--i.e., get the first slot whose owning instance has SBA information.
--(it can be even the slot under examination itself)
helper context UML!Slot def: getSBADelegationsDownwards() : Set(UML!Slot) =
let inst : UML!InstanceSpecification = self.refImmediateComposite() in
let deleg : Set(UML!Slot) = self.getDelegationEndsDownwards() in
if deleg.isEmpty() or
inst.hasSBAInformation() or
inst.getSubInstances().isEmpty()
then
Set{self}
else
deleg->collect(e | e.getSBADelegationsDownwards())->flatten()
endif;
helper context UML!Slot def: getSBADelegationsUpwards() : Set(UML!Slot) =
let inst : UML!InstanceSpecification = self.refImmediateComposite() in
let deleg : Set(UML!Slot) = self.getDelegationEndsUpwards() in
if deleg.isEmpty() then
Set{self}
else
deleg->collect(e | e.getSBADelegationsUpwards())->flatten()
endif;
--Get the target of connection taking into account SBA stereotypes,
--i.e., get the first slot whose owning instance has SBA information.
--(it can be even the slot directly connected to the one under examination)
helper context UML!Slot def: getSBAConnections() : Set(UML!Slot) =
self.getSBADelegationsUpwards()->
collect(d | d.getConnectedImmediate())->flatten()->
collect(sl | sl.getSBADelegationsDownwards())->flatten();
--------------------------------------------------------------------
-- Parse failure modes for SimpleStochasticBehavior elements
--------------------------------------------------------------------
--Split the specification into different parts, one for each port, and find the
--failure modes for the port name passed as input. Calls parseFailureModes() below
helper context String def: parseFailureModesForPort(port : String) : Set(TupleType(fm: String, p: Real)) =
let strSeq : Sequence(String) = self.trim()->split(';') in
let strSelected : String = strSeq->select(s | s.trim().startsWith(port))->first() in
if strSelected = OclUndefined then
strSeq->first().parseFailureModes()
else
strSelected.parseFailureModes()
endif;
--From the specification in string format get the failure modes and proabilities for a single port
helper context String def: parseFailureModes() : Set(TupleType(fm: String, p: Real)) =
let str : String =
if self.indexOf('{') < 0 then
self.trim()
else
self.substring(self.indexOf('{')+2, self.size()).replaceAll('}', ' ').trim()
endif
in
let default : Set(TupleType(fm: String, p: Real)) = Set{Tuple{fm = 'failure', p = 1.0}} in
if str.size() = 0 then
default
else
let ret : Set(TupleType(fm: String, p: Real)) =
str.split(',')->collect(s | s.split(':'))->
collect(seq | Tuple{fm = seq->first().trim(), p = seq.last().toReal()})
in
if ret->isEmpty() then
default
else
ret
endif endif;
--------------------------------------------------------------------
-- Helpers to manage the metrics
--------------------------------------------------------------------
--temporary parser to retrieve which dependability measure a SBAnalysis refers to
helper context CHESS!StateBasedAnalysis def: WhichMeasure : String =
if self.measure.startsWith('Reliability') then 'Reliability'
else if self.measure.startsWith('Availability') then 'Availability'
else if self.measure.toUpper().startsWith('PFD') then 'PFD'
else 'error'
endif endif endif;
--------------------------------------------------------------------
-- Helpers to manage Faults/Errors expressions
--------------------------------------------------------------------
helper context IM!FaultsExpressionFaultNode def: toString(): String = self.Fault.Name;
helper context IM!FaultsExpressionOrNode def: toString(): String = '(' + self.FaultsExpression1.toString() + ' OR ' + self.FaultsExpression2.toString() + ')';
helper context IM!FaultsExpressionAndNode def: toString() : String = '(' + self.FaultsExpression1.toString() + ' AND ' + self.FaultsExpression2.toString() + ')';
helper context IM!FaultsExpressionNotNode def: toString() : String = '(NOT ' + self.FaultsExpression.toString() + ')';
--Get the list of Fault elements involved in a FaultsExpression
helper context IM!FaultsExpressionNode def: faultsList() : Sequence(IM!Fault) =
if self.oclIsTypeOf(IM!FaultsExpressionFaultNode) then
let fexp : IM!FaultsExpressionFaultNode = self in
Sequence{fexp.Fault}
else if self.oclIsTypeOf(IM!FaultsExpressionNotNode) then
let fexp : IM!FaultsExpressionNotNode = self in
fexp.FaultsExpression.faultsList()
else if self.oclIsTypeOf(IM!FaultsExpressionAndNode) then
let fexp : IM!FaultsExpressionAndNode = self in
fexp.FaultsExpression1.faultsList()->union(fexp.FaultsExpression2.faultsList())
else if self.oclIsTypeOf(IM!FaultsExpressionOrNode) then
let fexp : IM!FaultsExpressionOrNode = self in
fexp.FaultsExpression1.faultsList()->union(fexp.FaultsExpression2.faultsList())
else
Sequence{} --it should never happen
endif endif endif endif;
helper context IM!ErrorsExpressionErrorNode def: toString(): String = self.Error.Name;
helper context IM!ErrorsExpressionOrNode def: toString(): String = '(' + self.ErrorsExpression1.toString() + ' OR ' + self.ErrorsExpression2.toString() + ')';
--------------------------------------------------------------------
-- For debugging purposes: pretty print SBA stereotypes
--------------------------------------------------------------------
helper context CHESS!SimpleStochasticBehavior def: toString() : String =
'<<SimpleStochasticBehavior>>(' + self.failureOccurrence + ', ' + self.repairDelay + ', ' + self.failureModesDistribution + ')';
helper context CHESS!FLABehavior def: toString() : String = '<<FLABehavior>>(' + self.fptc + ')';
helper context CHESS!ErrorModelBehavior def: toString() : String = '<<ErrorModelBehavior>>(' + self.errorModel + ')';
helper context CHESS!ErrorModel def: toString() : String = '<<ErrorModel>>(' + self.base_StateMachine + ')';