AadlFlowSpecificationUtil.java
/**
* Copyright (c) 2004-2025 Carnegie Mellon University and others. (see Contributors file).
* All Rights Reserved.
*
* NO WARRANTY. ALL MATERIAL IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
* KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE
* OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT
* MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
*
* 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
*
* Created, in part, with funding and support from the United States Government. (see Acknowledgments file).
*
* This program includes and/or can make use of certain third party source code, object code, documentation and other
* files ("Third Party Software"). The Third Party Software that is used by this program is dependent upon your system
* configuration. By using this program, You agree to comply with any and all relevant Third Party Software terms and
* conditions contained in any such Third Party Software or separate license file distributed with such Third Party
* Software. The parties who own the Third Party Software ("Third Party Licensors") are intended third party benefici-
* aries to this license with respect to the terms applicable to their Third Party Software. Third Party Software li-
* censes only apply to the Third Party Software and not any other portion of this program or this program as a whole.
*/
package org.osate.ge.aadl2.internal.util;
import java.util.Objects;
import java.util.stream.Stream;
import org.osate.aadl2.EndToEndFlow;
import org.osate.aadl2.EndToEndFlowElement;
import org.osate.aadl2.EndToEndFlowSegment;
import org.osate.aadl2.FlowElement;
import org.osate.aadl2.FlowImplementation;
import org.osate.aadl2.FlowSegment;
import org.osate.aadl2.FlowSpecification;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.instance.ConnectionInstance;
import org.osate.aadl2.instance.EndToEndFlowInstance;
import org.osate.aadl2.instance.InstanceObject;
import org.osate.ge.BusinessObjectContext;
/**
* Utility functions for working with flow specifications and end to end flow specifications.
*
*/
public class AadlFlowSpecificationUtil {
/**
* Simple type for referencing a flow segment. This is more specific than a flow segment in the declarative model because the context or parent of such flow segments cannot be
* tied to a unique element in a queryable tree such as a diagram.
*
*/
public static class FlowSegmentReference {
public final NamedElement flowSegmentElement; // The element portion of the flow segment being referenced.
public final BusinessObjectContext container;
public FlowSegmentReference(final NamedElement flowSegmentElement, final BusinessObjectContext container) {
this.flowSegmentElement = Objects.requireNonNull(flowSegmentElement, "flowSegmentElement must not be null");
this.container = Objects.requireNonNull(container, "container must not be null");
}
}
public static BusinessObjectContext findQueryable(final FlowSegmentReference flowElementRef) {
return flowElementRef.container.getChildren().stream()
.filter(q -> {
if (q.getBusinessObject() instanceof NamedElement) {
final NamedElement ne = (NamedElement) q.getBusinessObject();
return AgeAadlUtil.getRootRefinedElement(ne) == AgeAadlUtil
.getRootRefinedElement(flowElementRef.flowSegmentElement);
}
return false;
}).findAny().orElse(null);
}
/**
* Returns a stream of flow elements that are referred to by a specified flow element.
* Returns an empty stream for all flow element references which are not a flow specification or end to end flow.
* @param flowElementRef
* @return
*/
public static Stream<FlowSegmentReference> findChildren(final FlowSegmentReference flowElementRef) {
if (flowElementRef.flowSegmentElement instanceof FlowSpecification) {
// Check if flow specification has flow implementation(s)
return AadlClassifierUtil.getComponentImplementation(flowElementRef.container.getBusinessObject())
.map(ci -> ci.getAllFlowImplementations().stream()
.filter(cfi -> AgeAadlUtil
.getRootRefinedElement(flowElementRef.flowSegmentElement) == AgeAadlUtil
.getRootRefinedElement(cfi.getSpecification()))
.flatMap(cfi -> cfi.getOwnedFlowSegments().stream()
.filter(flowSegment -> flowSegment.getFlowElement() != cfi.getSpecification()))
.map(flowSegment -> createFlowSegmentReference(flowSegment, flowElementRef.container)))
.orElse(Stream.empty());
} else if (flowElementRef.flowSegmentElement instanceof EndToEndFlow) {
return AadlClassifierUtil.getComponentImplementation(flowElementRef.container.getBusinessObject())
.map(ci -> ci.getAllEndToEndFlows().stream()
.filter(ete -> AgeAadlUtil.getRootRefinedElement(ete) == AgeAadlUtil
.getRootRefinedElement(flowElementRef.flowSegmentElement))
.flatMap(ete -> getAllEteFlowSegments(ete))
.map(eteFlowSegment -> createFlowSegmentReference(eteFlowSegment,
flowElementRef.container)))
.orElse(Stream.empty());
} else if (flowElementRef.flowSegmentElement instanceof EndToEndFlowInstance) {
return AadlInstanceObjectUtil.getComponentInstance(flowElementRef.container.getBusinessObject())
.map(ci -> ci.getEndToEndFlows().stream().filter(ete -> ete == flowElementRef.flowSegmentElement)
.flatMap(ete -> {
return ete.getFlowElements().stream()
.flatMap(fei -> {
if (fei instanceof ConnectionInstance) {
return ((ConnectionInstance) fei).getConnectionReferences().stream()
.map(cr -> createFlowSegmentReference(cr,
flowElementRef.container));
} else {
return Stream
.of(createFlowSegmentReference(fei, flowElementRef.container));
}
});
}))
.orElse(Stream.empty());
} else if (flowElementRef.flowSegmentElement instanceof FlowImplementation) {
final FlowImplementation fi = (FlowImplementation) flowElementRef.flowSegmentElement;
return fi.getOwnedFlowSegments().stream()
.map(flowSegment -> createFlowSegmentReference(flowSegment, flowElementRef.container));
} else {
return Stream.empty();
}
}
// Flatten end to end flow segments that are end to end flows and remove cyclic end to end flow segments
private static Stream<EndToEndFlowSegment> getAllEteFlowSegments(final EndToEndFlow eTEFlow) {
return eTEFlow.getAllFlowSegments().stream()
.filter(eTEFlowSegment -> eTEFlowSegment.getFlowElement() != eTEFlow).flatMap(eTEFlowSegment -> {
final EndToEndFlowElement eTEFlowElement = eTEFlowSegment.getFlowElement();
if (eTEFlowElement instanceof EndToEndFlow) {
return getAllEteFlowSegments((EndToEndFlow) eTEFlowElement);
}
return Stream.of(eTEFlowSegment);
});
}
public static FlowSegmentReference createFlowSegmentReference(final Object bo,
final BusinessObjectContext container) {
if (bo instanceof FlowSegment) {
final FlowSegment flowSegment = (FlowSegment) bo;
final FlowElement flowElement = flowSegment.getFlowElement();
if (flowSegment.getContext() == null) {
return createFlowSegmentReference(flowElement, container);
} else {
return container.getChildren().stream()
.filter(child -> {
if (child.getBusinessObject() instanceof NamedElement) {
final NamedElement ne = (NamedElement) child.getBusinessObject();
return AgeAadlUtil.getRootRefinedElement(ne) == AgeAadlUtil
.getRootRefinedElement(flowSegment.getContext());
}
return false;
}).findAny()
.map(contextQueryable -> createFlowSegmentReference(flowElement, contextQueryable)).orElse(null);
}
} else if (bo instanceof EndToEndFlowSegment) {
final EndToEndFlowSegment flowSegment = (EndToEndFlowSegment) bo;
final FlowElement flowElement = (FlowElement) flowSegment.getFlowElement();
if (flowSegment.getContext() == null) {
return createFlowSegmentReference(flowElement, container);
} else {
return container.getChildren().stream()
.filter(child -> {
if (child.getBusinessObject() instanceof NamedElement) {
final NamedElement ne = (NamedElement) child.getBusinessObject();
return AgeAadlUtil.getRootRefinedElement(ne) == AgeAadlUtil
.getRootRefinedElement(flowSegment.getContext());
}
return false;
}).findAny()
.map(contextQueryable -> createFlowSegmentReference(flowElement, contextQueryable)).orElse(null);
}
} else if (bo instanceof InstanceObject) {
final InstanceObject io = (InstanceObject) bo;
if (bo instanceof EndToEndFlowInstance) {
return new FlowSegmentReference(io, container);
} else {
return container.getAllDescendants().filter(q -> q.getBusinessObject() == io)
.findAny().map(q -> new FlowSegmentReference(io, q.getParent()))
.orElse(null);
}
} else if (bo instanceof FlowImplementation) {
final FlowImplementation fi = (FlowImplementation) bo;
return new FlowSegmentReference(fi, container);
} else if (bo instanceof NamedElement) {
return new FlowSegmentReference((NamedElement) bo, container);
} else {
throw new RuntimeException("Unexpected business object: " + bo);
}
}
}