| /** |
| ******************************************************************************** |
| * Copyright (c) 2020 Eclipse APP4MC contributors. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.amalthea._import.btf.model; |
| |
| import java.util.AbstractMap.SimpleEntry; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Objects; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import java.util.stream.Stream; |
| |
| import org.eclipse.app4mc.amalthea.model.ProcessEventType; |
| import org.eclipse.app4mc.amalthea.model.RunnableEventType; |
| import org.eclipse.emf.common.util.Enumerator; |
| |
| public enum BTFEntityState { |
| |
| // initial state |
| notInitialized(new SimpleEntry<>(Collections.emptyList(), Arrays.asList(RunnableEventType.START)), // |
| new SimpleEntry<>(Collections.emptyList(), Arrays.asList(ProcessEventType.ACTIVATE))), |
| // in BTF this is actually the "active" state |
| startDelay(new SimpleEntry<>(Arrays.asList(ProcessEventType.ACTIVATE), Arrays.asList(ProcessEventType.START))), |
| running(new SimpleEntry<>( |
| Arrays.asList(RunnableEventType.START, RunnableEventType.RESUME), |
| Arrays.asList(RunnableEventType.TERMINATE, RunnableEventType.SUSPEND)), // |
| new SimpleEntry<>( |
| Arrays.asList(ProcessEventType.START, ProcessEventType.RESUME, ProcessEventType.RUN), |
| Arrays.asList(ProcessEventType.TERMINATE, ProcessEventType.PREEMPT, ProcessEventType.POLL, ProcessEventType.WAIT))), |
| polling(new SimpleEntry<>(Arrays.asList(ProcessEventType.POLL, ProcessEventType.POLL_PARKING), Arrays.asList(ProcessEventType.RUN, ProcessEventType.PARK))), |
| parking(new SimpleEntry<>(Arrays.asList(ProcessEventType.PARK), Arrays.asList(ProcessEventType.POLL_PARKING, ProcessEventType.RELEASE_PARKING))), |
| waiting(new SimpleEntry<>(Arrays.asList(ProcessEventType.WAIT), Arrays.asList(ProcessEventType.RELEASE))), |
| ready(new SimpleEntry<>(Arrays.asList(RunnableEventType.SUSPEND), Arrays.asList(RunnableEventType.RESUME)), // |
| new SimpleEntry<>(Arrays.asList(ProcessEventType.PREEMPT, ProcessEventType.RELEASE, ProcessEventType.RELEASE_PARKING), |
| Arrays.asList(ProcessEventType.RESUME))), |
| // meta state (not represented as combi state for simplicity) |
| response(new SimpleEntry<>(Arrays.asList(ProcessEventType.ACTIVATE), Arrays.asList(ProcessEventType.TERMINATE))), |
| // final state |
| terminated(new SimpleEntry<>(Arrays.asList(RunnableEventType.TERMINATE), Collections.emptyList()), // |
| new SimpleEntry<>(Arrays.asList(ProcessEventType.TERMINATE), Collections.emptyList())); |
| |
| public final Map<BTFEntityType, Entry<List<Enumerator>, List<Enumerator>>> entityType2InOutEvents; |
| // list of all states excluding initial and final states |
| public static final List<BTFEntityState> actStates = Stream.of(values()) |
| .filter(p -> p.entityType2InOutEvents.values().stream().noneMatch(e -> e.getKey().isEmpty())) |
| .filter(p -> p.entityType2InOutEvents.values().stream().noneMatch(e -> e.getValue().isEmpty())) |
| .collect(Collectors.toList()); |
| |
| @SafeVarargs |
| private BTFEntityState(final Entry<List<Enumerator>, List<Enumerator>>... inOutEvents) { |
| this.entityType2InOutEvents = new LinkedHashMap<>(); |
| Stream.of(inOutEvents).forEach(e -> { |
| String entityTypeName = e.getKey().stream().findFirst().orElseGet(e.getValue().stream().findFirst()::get).getClass().getSimpleName(); |
| entityTypeName = entityTypeName.substring(0, entityTypeName.indexOf("EventType")).toLowerCase(); |
| this.entityType2InOutEvents.put(BTFEntityType.getForName(entityTypeName), e); |
| }); |
| } |
| |
| public static List<String> getValidityConstraints(final BTFEntityType entityType) { |
| final List<String> validityConstraints = new ArrayList<>(); |
| // events for initial and final states must occur exactly once |
| Stream.of(values()).filter(s -> !actStates.contains(s)).map(s -> s.entityType2InOutEvents.get(entityType)) |
| .filter(Objects::nonNull).forEach(entry -> { |
| entry.getKey().forEach(e -> validityConstraints.add(e.getName().toLowerCase() + "EventCount = 1")); |
| entry.getValue().forEach(e -> validityConstraints.add(e.getName().toLowerCase() + "EventCount = 1")); |
| }); |
| // sum of incoming events must equal sum of outgoing events (excluding loop events) |
| actStates.stream().map(s -> s.entityType2InOutEvents.get(entityType)).filter(Objects::nonNull).forEach(entry -> { |
| final Set<Enumerator> loopEvents = new LinkedHashSet<>(entry.getKey()); |
| loopEvents.retainAll(entry.getValue()); |
| final String left = entry.getKey().stream().filter(e -> !loopEvents.contains(e)).map(e -> e.getName().toLowerCase() + "EventCount") |
| .collect(Collectors.joining(" + ")); |
| final String right = entry.getValue().stream().filter(e -> !loopEvents.contains(e)).map(e -> e.getName().toLowerCase() + "EventCount") |
| .collect(Collectors.joining(" + ")); |
| validityConstraints.add(left + " = " + right); |
| }); |
| return validityConstraints; |
| } |
| |
| public static Set<Enumerator> getPossibleEventsFor(final BTFEntityType entityType) { |
| final Set<Enumerator> result = new LinkedHashSet<>(BTFCountMetric.getInvolvedBTFEventsForEntityType(entityType)); |
| Stream.of(values()).map(s -> s.entityType2InOutEvents.get(entityType)) |
| .filter(Objects::nonNull).flatMap(e -> Stream.concat(e.getKey().stream(), e.getValue().stream())).distinct() |
| .forEach(result::add); |
| return result; |
| } |
| |
| } |