FlowSpecificationCreationUtil.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.ui.internal.palette;
import java.util.Collections;
import java.util.List;
import org.osate.aadl2.AbstractFeature;
import org.osate.aadl2.AbstractType;
import org.osate.aadl2.ComponentClassifier;
import org.osate.aadl2.ComponentType;
import org.osate.aadl2.Context;
import org.osate.aadl2.DataAccess;
import org.osate.aadl2.DataType;
import org.osate.aadl2.DeviceType;
import org.osate.aadl2.DirectedFeature;
import org.osate.aadl2.DirectionType;
import org.osate.aadl2.Element;
import org.osate.aadl2.Feature;
import org.osate.aadl2.FeatureGroup;
import org.osate.aadl2.Parameter;
import org.osate.aadl2.Port;
import org.osate.aadl2.ProcessType;
import org.osate.aadl2.ProcessorType;
import org.osate.aadl2.Subcomponent;
import org.osate.aadl2.SubprogramAccess;
import org.osate.aadl2.SubprogramGroupType;
import org.osate.aadl2.SubprogramType;
import org.osate.aadl2.SystemType;
import org.osate.aadl2.ThreadGroupType;
import org.osate.aadl2.ThreadType;
import org.osate.aadl2.VirtualProcessorType;
import org.osate.ge.BusinessObjectContext;
import org.osate.ge.aadl2.internal.AadlNamingUtil;
import org.osate.ge.aadl2.internal.util.AadlFeatureUtil;
import org.osate.ge.aadl2.ui.internal.AadlUiUtil;
import org.osate.ge.query.ExecutableQuery;
import org.osate.ge.services.QueryService;
class FlowSpecificationCreationUtil {
private static final ExecutableQuery<Object> COMPONENT_CLASSIFIER_OR_SUBCOMPONENT_QUERY = ExecutableQuery
.create(root -> root.ancestors()
.filter(fa -> fa.getBusinessObject() instanceof ComponentClassifier
|| fa.getBusinessObject() instanceof Subcomponent)
.first());
private static final ExecutableQuery<Object> CONTEXT_QUERY = ExecutableQuery
.create(root -> root.ancestors().filter(fa -> fa.getBusinessObject() instanceof FeatureGroup));
/**
* Returns whether a specified feature diagram element may be used as a flow end for a flow specification.
* feature, its direction must be IN OUT or match the specified direction
*/
public static boolean isValidFlowEnd(final Feature feature, final BusinessObjectContext featureBoc,
final DirectionType requiredDirection, final QueryService queryService) {
// Ensure that the feature is contained in a component type
if (getPotentialOwnersByFeature(featureBoc, queryService).size() == 0) {
return false;
}
// Check that the feature is of the appropriate type
if (!(feature instanceof Port || feature instanceof Parameter || feature instanceof DataAccess
|| feature instanceof SubprogramAccess || feature instanceof FeatureGroup
|| feature instanceof AbstractFeature)) {
return false;
}
// If it is a direct feature, it must have the specified direction or be an in out feature. Take into account feature group, inverse, etc..
if (feature instanceof DirectedFeature) {
// Determine the actual direction of the feature. Since it could effected by things like inverse feature groups, etc
final DirectedFeature df = (DirectedFeature) feature;
DirectionType direction = df.getDirection();
if (direction == DirectionType.IN || direction == DirectionType.OUT) {
if (AadlFeatureUtil.isFeatureInverted(featureBoc)) {
direction = (direction == DirectionType.IN) ? DirectionType.OUT : DirectionType.IN;
}
}
if (direction != requiredDirection && direction != DirectionType.IN_OUT) {
return false;
}
}
return true;
}
public static List<ComponentType> getPotentialOwnersByFeature(BusinessObjectContext featureBoc,
final QueryService queryService) {
Context context = getContext(featureBoc, queryService);
final Feature feature = (Feature) featureBoc.getBusinessObject();
final String childName = context == null ? feature.getName() : context.getName();
if (childName == null) {
return Collections.emptyList();
}
final BusinessObjectContext containerBoc = getFlowSpecificationOwnerBoc(featureBoc, queryService);
if (containerBoc == null) {
return Collections.emptyList();
}
final Element bo = (Element) containerBoc.getBusinessObject();
return AadlUiUtil.getPotentialClassifierTypesForEditing(bo)
.stream()
.filter(FlowSpecificationCreationUtil::canOwnFlowSpecification)
.map(ComponentType.class::cast)
.filter(ct -> hasFeatureWithName(ct, childName))
.toList();
}
static Context getContext(final BusinessObjectContext featureBoc, final QueryService queryService) {
var results = queryService.getResults(CONTEXT_QUERY, featureBoc, featureBoc.getBusinessObject());
if (results.isEmpty()) {
return null;
}
var last = results.get(results.size() - 1);
return (Context) last.getBusinessObjectContext().getBusinessObject();
}
static List<Context> getContexts(final BusinessObjectContext featureBoc, final QueryService queryService) {
var results = queryService.getResults(CONTEXT_QUERY, featureBoc, featureBoc.getBusinessObject());
return results.stream().map(qr -> (Context) qr.getBusinessObjectContext().getBusinessObject()).toList();
}
private static boolean hasFeatureWithName(final ComponentType ct, final String nameToCheck) {
return ct.getAllFeatures().stream().map(f -> f.getName()).anyMatch(n -> nameToCheck.equalsIgnoreCase(n));
}
/**
* Get the business object context for the container/owner of a flow specification involving the specified feature
* @param featureBoc
* @param queryService
* @return
*/
protected static BusinessObjectContext getFlowSpecificationOwnerBoc(BusinessObjectContext featureBoc,
final QueryService queryService) {
return queryService.getFirstBusinessObjectContextOrNull(COMPONENT_CLASSIFIER_OR_SUBCOMPONENT_QUERY, featureBoc,
featureBoc.getBusinessObject());
}
protected static boolean canOwnFlowSpecification(final Object bo) {
return bo instanceof ThreadGroupType || bo instanceof ThreadType || bo instanceof VirtualProcessorType
|| bo instanceof ProcessType || bo instanceof DeviceType || bo instanceof AbstractType
|| bo instanceof ProcessorType || bo instanceof DataType || bo instanceof SystemType
|| bo instanceof SubprogramType || bo instanceof SubprogramGroupType;
}
protected static String getNewFlowSpecificationName(final ComponentType ct) {
return AadlNamingUtil.buildUniqueIdentifier(ct, "new_flow_spec");
}
}