InstanceUtil.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.aadl2.instance.util;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.osate.aadl2.Classifier;
import org.osate.aadl2.ComponentClassifier;
import org.osate.aadl2.ComponentImplementation;
import org.osate.aadl2.ComponentPrototype;
import org.osate.aadl2.ComponentPrototypeActual;
import org.osate.aadl2.ComponentPrototypeBinding;
import org.osate.aadl2.ComponentType;
import org.osate.aadl2.Connection;
import org.osate.aadl2.FeatureClassifier;
import org.osate.aadl2.FeatureGroup;
import org.osate.aadl2.FeatureGroupPrototype;
import org.osate.aadl2.FeatureGroupPrototypeActual;
import org.osate.aadl2.FeatureGroupPrototypeBinding;
import org.osate.aadl2.FeatureGroupType;
import org.osate.aadl2.FeaturePrototypeActual;
import org.osate.aadl2.FeaturePrototypeBinding;
import org.osate.aadl2.FeaturePrototypeReference;
import org.osate.aadl2.FeatureType;
import org.osate.aadl2.Prototype;
import org.osate.aadl2.PrototypeBinding;
import org.osate.aadl2.Subcomponent;
import org.osate.aadl2.instance.ComponentInstance;
import org.osate.aadl2.instance.ConnectionInstance;
import org.osate.aadl2.instance.ConnectionReference;
import org.osate.aadl2.instance.FeatureCategory;
import org.osate.aadl2.instance.FeatureInstance;
import org.osate.aadl2.instance.InstanceObject;
import org.osate.aadl2.instance.SystemInstance;
import org.osate.aadl2.instance.SystemOperationMode;
/**
* @author lwrage
*/
public class InstanceUtil {
/**
* @author lwrage
*/
// TODO-LW: handle arrays
public static class InstantiatedClassifier {
/** Special value used to represent NULL return value in the classifier cache. */
public static final InstantiatedClassifier NULL = new InstantiatedClassifier(null, null);
/**
*
*/
private Classifier classifier;
/**
*
*/
private EList<PrototypeBinding> bindings;
InstantiatedClassifier() {
}
public InstantiatedClassifier(Classifier classifier, EList<PrototypeBinding> bindings) {
this.classifier = classifier;
this.bindings = bindings;
}
/**
* return the classifier variable
* @param
* @return Classifier
* @since 4.0
*/
public Classifier getClassifier() {
return classifier;
}
/**
* return the bindings variable
* @param
* @return EList<PrototypeBinding>
* @since 4.0
*/
public EList<PrototypeBinding> getBindings() {
return bindings;
}
/**
* @since 5.0
*/
public boolean hasBindings() {
return !(bindings == null || bindings.isEmpty());
}
}
private static final EList<PrototypeBinding> noBindings = new BasicEList<PrototypeBinding>();
/**
* Get the component type of a component instance. Resolve prototypes if
* needed.
*
* @param ci the component instance
* @param index the index of the instance object in an array
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return the component type
*/
public static ComponentType getComponentType(ComponentInstance ci, int index,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
ComponentType type = null;
if (ci instanceof SystemInstance) {
type = ((SystemInstance) ci).getComponentImplementation().getType();
} else {
final InstantiatedClassifier ic = getInstantiatedClassifier(ci, index, classifierCache);
if (ic != null) {
ComponentClassifier cc = (ComponentClassifier) ic.classifier;
if (cc != null && cc instanceof ComponentImplementation) {
if (cc instanceof ComponentImplementation) {
type = ((ComponentImplementation) cc).getType();
}
} else {
type = (ComponentType) cc;
}
}
}
return type;
}
/**
* Get the component implementation of a component instance. Resolve
* prototypes if needed.
*
* @param ci the component instance
* @param index the index of the instance object in an array
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return the component implementation
*/
public static ComponentImplementation getComponentImplementation(ComponentInstance ci, int index,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
ComponentImplementation impl = null;
if (ci instanceof SystemInstance) {
impl = ((SystemInstance) ci).getComponentImplementation();
} else {
final InstantiatedClassifier ic = getInstantiatedClassifier(ci, index, classifierCache);
if (ic != null) {
final ComponentClassifier cc = (ComponentClassifier) ic.classifier;
if (cc != null && cc instanceof ComponentImplementation) {
impl = (ComponentImplementation) cc;
}
}
}
return impl;
}
/**
* Get the component classifier of a component instance. Resolve
* prototypes if needed.
*
* @param ci the component instance
* @param index the index of the instance object in an array
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return the component classifier
*/
public static ComponentClassifier getComponentClassifier(ComponentInstance ci, int index,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
ComponentClassifier cc = null;
if (ci instanceof SystemInstance) {
cc = ((SystemInstance) ci).getComponentImplementation();
} else {
final InstantiatedClassifier ic = getInstantiatedClassifier(ci, index, classifierCache);
if (ic != null) {
cc = (ComponentClassifier) ic.classifier;
}
}
return cc;
}
/**
* Get the feature group classifier of a feature instance. Resolve
* prototypes if needed.
*
* @param fi the feature instance
* @param index the index of the instance object in an array
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return the feature group classifier, null if the feature instance isn't a feature group
*/
public static FeatureGroupType getFeatureGroupType(FeatureInstance fi, int index,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
FeatureGroupType fgt = null;
if (fi.getCategory() == FeatureCategory.FEATURE_GROUP) {
final InstantiatedClassifier ic = getInstantiatedClassifier(fi, index, classifierCache);
if (ic != null) {
fgt = (FeatureGroupType) ic.classifier;
}
}
return fgt;
}
/**
* Get the component or feature group classifier that is instantiated by an
* instance object. Resolve prototypes if needed.
*
* @param iobj the instance object
* @param index the index of the instance object in an array
* @return the instantiated classifier together with bindings for anonymous
* classifiers
*/
public static InstantiatedClassifier getInstantiatedClassifier(InstanceObject iobj, int index) {
return getInstantiatedClassifier(iobj, index, null);
}
/**
* Get the component or feature group classifier that is instantiated by an
* instance object. Resolve prototypes if needed.
*
* @param iobj the instance object
* @param index the index of the instance object in an array
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return the instantiated classifier together with bindings for anonymous
* classifiers
*/
public static InstantiatedClassifier getInstantiatedClassifier(InstanceObject iobj, int index,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
InstantiatedClassifier ic = null;
if (classifierCache != null) {
final InstantiatedClassifier temp = classifierCache.get(iobj);
if (temp != null) {
return temp == InstantiatedClassifier.NULL ? null : temp;
}
}
if (iobj instanceof SystemInstance) {
ic = new InstantiatedClassifier(((SystemInstance) iobj).getComponentImplementation(), noBindings);
}
if (ic == null) {
Classifier classifier = null;
EList<PrototypeBinding> prototypeBindings = null;
Prototype prototype = null;
if (iobj instanceof ComponentInstance) {
Subcomponent sub = ((ComponentInstance) iobj).getSubcomponent();
if (sub == null) {
return null;
}
classifier = sub.getClassifier();
prototypeBindings = sub.getOwnedPrototypeBindings();
prototype = sub.getPrototype();
} else if (iobj instanceof FeatureInstance fi) {
if (fi.getFeature() instanceof FeatureGroup fg) {
FeatureType ft = fg.getFeatureType();
classifier = (ft instanceof Classifier) ? (Classifier) ft : null;
prototype = (ft instanceof Prototype) ? (Prototype) ft : null;
} else {
FeatureClassifier fc = fi.getFeature().getAllFeatureClassifier();
classifier = (fc instanceof Classifier cl) ? cl : null;
prototype = (fc instanceof Prototype p) ? p : null;
}
} else {
return null;
}
if (classifier != null) {
ic = new InstantiatedClassifier(classifier, prototypeBindings);
}
// no classifier => try prototype
if (ic == null) {
if (prototype != null) {
// resolve prototype
if (prototype instanceof ComponentPrototype cproto) {
ComponentPrototypeActual cpa = resolveComponentPrototype(cproto, iobj, classifierCache);
if (cpa != null) {
ic = new InstantiatedClassifier((ComponentClassifier) cpa.getSubcomponentType(),
cpa.getBindings());
} else {
// ISSUE 986: If the constraining classifier is missing (null), then don't create an InstantiatedClassifier object
var cc = findConstrainingClassifier(iobj, cproto, classifierCache);
if (cc != null) {
ic = new InstantiatedClassifier(cc, noBindings);
}
}
} else if (prototype instanceof FeatureGroupPrototype fgproto) {
FeatureGroupPrototypeActual fpa = resolveFeatureGroupPrototype(fgproto, iobj, classifierCache);
if (fpa != null) {
ic = new InstantiatedClassifier((FeatureGroupType) fpa.getFeatureType(), fpa.getBindings());
} else {
var cfgt = findConstrainingFeatureGroupType(iobj, fgproto, classifierCache);
if (cfgt != null) {
ic = new InstantiatedClassifier(cfgt, noBindings);
}
}
}
}
}
}
if (classifierCache != null) {
classifierCache.put(iobj, ic == null ? InstantiatedClassifier.NULL : ic);
}
return ic;
}
private static ComponentClassifier findConstrainingClassifier(InstanceObject iobj, ComponentPrototype cproto,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
if (classifierCache == null) {
return null;
}
for (Prototype p : getPrototypes(iobj, classifierCache)) {
if (p.getName().equalsIgnoreCase(cproto.getName())) {
for (var pp = p; pp != null; pp = pp.getRefined()) {
if (pp instanceof ComponentPrototype fgp) {
var cfg = fgp.getConstrainingClassifier();
if (cfg != null) {
return cfg;
}
}
}
}
}
return null;
}
private static FeatureGroupType findConstrainingFeatureGroupType(InstanceObject iobj, FeatureGroupPrototype fgproto,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
if (classifierCache == null) {
return null;
}
for (Prototype p : getPrototypes(iobj, classifierCache)) {
if (p.getName().equalsIgnoreCase(fgproto.getName())) {
for (var pp = p; pp != null; pp = pp.getRefined()) {
if (pp instanceof FeatureGroupPrototype fgp) {
var cfg = fgp.getConstrainingFeatureGroupType();
if (cfg != null) {
return cfg;
}
}
}
}
}
return null;
}
private static List<Prototype> getPrototypes(InstanceObject iobj,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
Classifier ownerCl = classifierCache.get(iobj.getOwner()).getClassifier();
if (ownerCl instanceof ComponentClassifier ccl) {
return ccl.getAllPrototypes();
} else if (ownerCl instanceof FeatureGroupType fgt) {
return fgt.getAllPrototypes();
}
return Collections.emptyList();
}
/**
* Find the binding for a given component prototype.
*
* @param proto the prototype to resolve
* @param context the context in which the prototype is used, e.g., a
* subcomponent instance
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return The component prototype actual that the prototype resolves to.
*/
public static ComponentPrototypeActual resolveComponentPrototype(Prototype proto, InstanceObject context,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
ComponentPrototypeActual cpa = null;
ComponentPrototypeBinding cpb = (ComponentPrototypeBinding) resolvePrototype(proto, context, classifierCache);
if (cpb == null) {
// cannot resolve
return null;
}
EList<ComponentPrototypeActual> actuals = cpb.getActuals();
if (actuals != null && actuals.size() > 0) {
ComponentPrototypeActual actual = actuals.get(0);
if (actual.getSubcomponentType() instanceof ComponentClassifier) {
cpa = actual;
} else {
// resolve recursively
cpa = resolveComponentPrototype((ComponentPrototype) actual.getSubcomponentType(),
context.getContainingComponentInstance(), classifierCache);
}
}
return cpa;
}
/**
* Find the binding for a given feature group prototype.
*
* @param proto the prototype to resolve
* @param context the context in which the prototype is used, e.g., a
* subcomponent instance
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return The feature group prototype actual the prototype is bound to.
*/
public static FeatureGroupPrototypeActual resolveFeatureGroupPrototype(Prototype proto, InstanceObject context,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
FeatureGroupPrototypeActual result = null;
FeatureGroupPrototypeBinding fgpb = (FeatureGroupPrototypeBinding) resolvePrototype(proto, context,
classifierCache);
if (fgpb == null) {
// cannot resolve
return null;
}
FeatureGroupPrototypeActual actual = fgpb.getActual();
if (actual.getFeatureType() instanceof FeatureGroupType) {
result = actual;
} else {
// resolve recursively
result = resolveFeatureGroupPrototype((FeatureGroupPrototype) actual.getFeatureType(),
context.getContainingComponentInstance(), classifierCache);
}
return result;
}
/**
* Find the binding for a given feature prototype.
*
* @param proto the prototype to resolve
* @param context the context in which the prototype is used, e.g., a
* subcomponent instance
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return The actual feature this prototype resolves to.
*/
public static FeaturePrototypeActual resolveFeaturePrototype(Prototype proto, InstanceObject context,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
FeaturePrototypeActual result = null;
FeaturePrototypeBinding fpb = (FeaturePrototypeBinding) resolvePrototype(proto, context, classifierCache);
if (fpb == null) {
return null;
}
result = fpb.getActual();
if (result instanceof FeaturePrototypeReference) {
// resolve recursively
result = resolveFeaturePrototype(((FeaturePrototypeReference) fpb.getActual()).getPrototype(),
context.getContainingComponentInstance(), classifierCache);
}
return result;
}
/**
* Find the binding for a given prototype.
*
* @param proto the prototype to resolve
* @param context the context in which the prototype is used, e.g., a
* subcomponent instance
* @param classifierCache an optional cache of known instantiated
* classifiers, may be null
* @return The binding that assigns the value to the prototype relative to
* its usage context.
*/
public static PrototypeBinding resolvePrototype(Prototype proto, InstanceObject context,
HashMap<InstanceObject, InstantiatedClassifier> classifierCache) {
PrototypeBinding result = null;
InstanceObject parent = (InstanceObject) context.getOwner();
// prototype binding may be attached to parent (anonymous component classifier)
if (parent instanceof SystemInstance) {
ComponentImplementation impl = ((SystemInstance) parent).getComponentImplementation();
if (impl == null) {
return null;
}
result = impl.lookupPrototypeBinding(proto);
} else if (parent instanceof ComponentInstance) {
Subcomponent parentSub = ((ComponentInstance) parent).getSubcomponent();
if (parentSub != null) {
result = parentSub.lookupPrototypeBinding(proto);
}
}
// lookup in parent's classifier (nested prototype bindings)
if (result == null && parent != null) {
InstantiatedClassifier parentClassifier = getInstantiatedClassifier(parent, 0, classifierCache);
if (parentClassifier.bindings != null) {
for (PrototypeBinding binding : parentClassifier.bindings) {
if (binding.getFormal() == proto) {
result = binding;
break;
}
}
}
if (result == null) {
result = parentClassifier.classifier.lookupPrototypeBinding(proto);
}
}
return result;
}
public static final String NORMAL_SOM_NAME = "No Modes";
public static boolean isNoMode(SystemOperationMode som) {
return som.getName().equalsIgnoreCase(NORMAL_SOM_NAME) || som.getName().equalsIgnoreCase("NoModes");
}
/**
* find connection instance with connection of name "name" in component instance
* @param ci
* @param name
* @return
*/
public static ConnectionInstance findConnectionInstance(ComponentInstance ci, Connection conn) { // String name) {
for (ConnectionInstance ei : ci.getConnectionInstances()) {
for (ConnectionReference connref : ei.getConnectionReferences()) {
// Connection conn = connref.getConnection();
if (conn == connref.getConnection()) {
return ei;
}
}
}
return null;
}
public static ComponentInstance findConnectionContext(ConnectionInstance conni, Connection conn) {
for (ConnectionReference connref : conni.getConnectionReferences()) {
// Connection conn = connref.getConnection();
if (conn == connref.getConnection()) {
return connref.getContext();
}
}
return null;
}
/**
* return cross connection of a connection instance
* @param conni
* @return Connection
*/
public static Connection getCrossConnection(ConnectionInstance conni) {
for (ConnectionReference connref : conni.getConnectionReferences()) {
Connection conn = connref.getConnection();
if (conn.getSource().getContext() instanceof Subcomponent
&& conn.getDestination().getContext() instanceof Subcomponent) {
return conn;
}
}
return null;
}
}