ForAllElement.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.modelsupport.modeltraversal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.osate.aadl2.ComponentCategory;
import org.osate.aadl2.ComponentImplementation;
import org.osate.aadl2.Element;
import org.osate.aadl2.NamedElement;
import org.osate.aadl2.instance.ComponentInstance;
import org.osate.aadl2.instance.InstanceObject;
import org.osate.aadl2.instance.SystemInstance;
import org.osate.aadl2.instance.SystemOperationMode;
import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporter;
import org.osate.aadl2.modelsupport.errorreporting.AnalysisErrorReporterManager;
import org.osate.aadl2.modelsupport.util.AadlUtil;
/**
* ForAllElement plays the role of an iterator object that supports traversal of
* AADL models Encapsulates traversal algorithms over models. Each instance of
* ForAllElement contains a resultList that holds all visited model objects as
* result of the default action.
* <p>
* Processing of model elements is performed by the {@link #process(Element)}
* method, which by default calls {@link #suchThat(Element)} to evaluate a
* condition and then {@link #action(Element)} to perform an action. The default
* condition is <code>true</code> and the default action is to add the visited
* Element to a resultList. Subclasses can either override {@link #suchThat} and
* or {@link #action} to get the desired filtering effects, or they can override
* {@link #process} directly.
* <p>
* Traversals may append objects to a result list. The default implementation of
* {@link #action} simply adds the visited object to the list. Many of the
* traversals return this list as their result. Analysis are not required to do
* anything with this list, however. This list can also be retreived using
* {@link #getResultList()}.
* <p>
* For ease of anonymous invocation, traversals specify a preferred or default
* traversal method at construction time using one of the constants
* {@link #NO_DEFAULT}, {@link #PROCESS_BOTTOM_UP_COMPONENT_IMPL},
* {@link #PROCESS_POST_ORDER_ALL}, {@link #PROCESS_PRE_ORDER_ALL},
* {@link #PROCESS_TOP_DOWN_COMPONENT_CLASSIFIER}, or
* {@link #PROCESS_TOP_DOWN_COMPONENT_IMPL}. This default traversal method is
* used by the {@link #defaultTraversal(Element)} and
* {@link #defaultTraversal(List)} methods. If no default is explicitly
* specified, then {@link #PROCESS_PRE_ORDER_ALL} is used. If the default
* traversal is {@link #NO_DEFAULT}, then the default traversal methods will
* throw an {@link java.lang.UnsupportedOperationException}.
* <p>
* The default traversal can be run over all the declarative models in the
* workspace using {@link #defaultTraversalAllDeclarativeModels()}. It can be
* run over all the instance models in the workspace using
* {@link #defaultTraversalAllInstances()}.
* <p>
* A traversal can cancel itself by calling {@link #cancelTraversal()}. The
* traversal methods routinely invoke {@link #notCancelled()} to see if the
* traversal has been cancelled. The end user of the traversal object can
* determine if the traversal was cancelled by checking {@link #cancelled()}.
* The result list is not in a well defined state when the traversal has been
* cancelled.
*
* @author phf
*/
public class ForAllElement implements IProcessingMethod {
/*
* ============================================================= Constants
* for specifying the default traversal algorithm
* =============================================================
*/
/**
* Constant indicating that there is no default traversal method. Attemps to
* use the default traversal method via {@link #defaultTraversal(Element)},
* {@link #defaultTraversal(List)}, etc. will fail with an
* {@link UnsupportedOperationException}.
*/
public static final int NO_DEFAULT = 0;
/**
* Constant indicating the default traversal method is
* {@link #processBottomUpComponentImpl(ComponentImplementation)}.
*/
public static final int PROCESS_BOTTOM_UP_COMPONENT_IMPL = 1;
/**
* Constant indicating the default traversal method is
* {@link #processPostOrderAll(Element)}.
*/
public static final int PROCESS_POST_ORDER_ALL = 2;
/**
* Constant indicating the default traversal method is
* {@link #processPreOrderAll(Element)}.
*/
public static final int PROCESS_PRE_ORDER_ALL = 3;
/**
* Constant indicating the default traversal method is
* {@link #processTopDownComponentClassifier(ComponentImplementation)}.
*/
public static final int PROCESS_TOP_DOWN_COMPONENT_CLASSIFIER = 4;
/**
* Constant indicating the default traversal method is
* {@link #processTopDownComponentImpl(ComponentImplementation)}.
*/
public static final int PROCESS_TOP_DOWN_COMPONENT_IMPL = 5;
private static final int LAST_TRAVERSAL_CONSTANT = 5;
/**
* The default setting for the default traversal method. The current value
* for this is {@link #PROCESS_PRE_ORDER_ALL}.
*/
public static final int DEFAULT_DEFAULT_TRAVERSAL = PROCESS_PRE_ORDER_ALL;
/*
* ============================================================= Instance
* variables =============================================================
*/
/** The error manager used by the traversal. */
private final AnalysisErrorReporterManager errManager;
/**
* This list is returned as the result value of the various traversal
* methods. An implementation may or may not use it. The default
* implementation of {@link #action(Element)} adds the visited model object
* to the list.
*/
protected final EList<Element> resultList = new BasicEList<Element>(200);
/** The default traversal method. */
private final AbstractTraversal defaultTraversalMethod;
/** Was the traversal cancelled? */
private boolean notCancelled = true;
/*
* =============================================================
* Constructors
* =============================================================
*/
/**
* Create a new traversal that uses the given error manager and uses the
* given default traversal algorithm.
*
* @param defTraversal The default traversal algorithm. One of
* {@link #NO_DEFAULT}, {@link #PROCESS_BOTTOM_UP_COMPONENT_IMPL}
* , {@link #PROCESS_POST_ORDER_ALL},
* {@link #PROCESS_PRE_ORDER_ALL},
* {@link #PROCESS_TOP_DOWN_COMPONENT_CLASSIFIER}, or
* {@link #PROCESS_TOP_DOWN_COMPONENT_IMPL}.
* @param errMgr The analysis error manager to use to report error results.
*/
public ForAllElement(final int defTraversal, final AnalysisErrorReporterManager errMgr) {
if (defTraversal < 0 || defTraversal > LAST_TRAVERSAL_CONSTANT) {
throw new IllegalArgumentException("Unknown default traversal");
}
defaultTraversalMethod = generateTraversal(defTraversal);
errManager = errMgr;
}
/**
* Create a new traversal that uses
* {@link AnalysisErrorReporterManager#NULL_ERROR_MANANGER the null error
* mananger} and the given default traversal algorithm.
*
* @param defTraversal The default traversal algorithm. One of
* {@link #NO_DEFAULT}, {@link #PROCESS_BOTTOM_UP_COMPONENT_IMPL}
* , {@link #PROCESS_POST_ORDER_ALL},
* {@link #PROCESS_PRE_ORDER_ALL},
* {@link #PROCESS_TOP_DOWN_COMPONENT_CLASSIFIER}, or
* {@link #PROCESS_TOP_DOWN_COMPONENT_IMPL}.
*/
public ForAllElement(final int defTraversal) {
this(defTraversal, AnalysisErrorReporterManager.NULL_ERROR_MANANGER);
}
/**
* Create a new traversal that uses the given error manager and uses the
* {@link #DEFAULT_DEFAULT_TRAVERSAL default default traversal algorithm}.
*
* @param errMgr The analysis error manager to use to report error results.
*/
public ForAllElement(final AnalysisErrorReporterManager errMgr) {
this(DEFAULT_DEFAULT_TRAVERSAL, errMgr);
}
/**
* Create a new traversal that uses
* {@link AnalysisErrorReporterManager#NULL_ERROR_MANANGER the null error
* mananger} the {@link #DEFAULT_DEFAULT_TRAVERSAL default default traversal
* algorithm}.
*/
public ForAllElement() {
this(AnalysisErrorReporterManager.NULL_ERROR_MANANGER);
}
/*
* ============================================================= The basic
* processing framework
* =============================================================
*/
/**
* Process a single model object. This method is invoked on each model
* object by the traversal methods (e.g., {@link #processEList(EList)},
* {@link #processPreOrderAll(Element)}, etc.). The default implementation
* is
*
* <pre>
* protected void process(Element theElement) {
* if (suchThat(theElement)) {
* action(theElement);
* }
* }
* </pre>
* <P>
* But subclasses can reimplement this method to do anything.
*
* @see #action(Element)
* @see #suchThat(Element)
*/
protected void process(final Element theElement) {
if (suchThat(theElement)) {
action(theElement);
}
}
/**
* Process a single model object. Delegates to {@link #process(Element)}.
* This method exists to satisfy the {@link IProcessingMethod} interface. I
* would have preferred to have a <code>process</code> method in the
* interface, but I cannot because the <code>ForAllElement.process</code>
* method is <code>protected</code>. If I put the method in an interface, I
* would have to make the method <code>public</code>, which could break
* existing code.
*/
@Override
public final void processObject(final Element theElement) {
if (theElement instanceof InstanceObject) {
InstanceObject io = (InstanceObject) theElement;
SystemInstance root = io.getSystemInstance();
SystemOperationMode som = root == null ? null : root.getCurrentSystemOperationMode();
if (som == null || io.isActive(som)) {
process(io);
}
} else {
process(theElement);
}
}
/**
* Processes a list of Elements by invoking {@link #process(Element)} on
* every element of the list in order. The default implementations of
* {@link #process(Element)}, {@link #suchThat}, and {@link #action} mean
* that by default this method just returns the input list of elements. It
* can be used to filter out elements by overriding
* {@link #suchThat(Element)}.
* <p>
* This method checks {@link #notCancelled()} after each element in the
* list, and terminates the processing if the traversal has been cancelled.
*
* @param list EList of Elements
* @return EList result list of objects that have been visited by any
* traversal with the given ForAllElement
* @see #process(Element)
* @see #cancelTraversal()
* @see #notCancelled()
*/
public final EList<Element> processEList(final EList<? extends Element> list) {
for (Iterator<? extends Element> it = list.iterator(); notCancelled() && it.hasNext();) {
process(it.next());
}
return resultList;
}
/**
* Method used to filter out objects during traversal. Intended to be
* overridden. Used by the default implementation of
* {@link #process(Element)}:
*
* <pre>
* protected void process(Element theElement) {
* if (suchThat(theElement)) {
* action(theElement);
* }
* }
* </pre>
* <p>
* By default, this method returns <code>true</code>.
*
* @param obj The object to test
* @return Whether the object should be visited or not.
* @see #process(Element)
* @see #action(Element)
*/
protected boolean suchThat(Element obj) {
return true;
}
/**
* Action to be performed on the currently visited model object. This method
* is intended to be overridden. This method is used by the default
* implementation of {@link #process(Element)}:
*
* <pre>
* protected void process(Element theElement) {
* if (suchThat(theElement)) {
* action(theElement);
* }
* }
* </pre>
* <p>
* By default, this method adds the object to {@link #resultList}. But this
* method can do anything.
*
* @param obj The object to visit.
* @see #suchThat(Element)
* @see #process(Element)
*/
protected void action(Element obj) {
resultList.add(obj);
}
/**
* Get the result list of the traversal. By default, this is the list of the
* all visited nodes, in the order they were visited. But the actual
* contents of this list depend on the implementation of
* {@link #process(Element)}.
*/
@Override
public EList<Element> getResultList() {
return resultList;
}
/*
* ============================================================= Handle
* traversal cancellation
* =============================================================
*/
/**
* Mark that the traversal should be cancelled. This should be called by a
* specific traversal implementation to halt the traversal. It is not
* <code>public</code> because there is no sense in outsiders calling this
* method.
*
* @see #cancelled()
* @see #notCancelled()
*/
protected final void cancelTraversal() {
notCancelled = false;
}
/**
* Test if we are cancelled. Unlike {@link #cancelTraversal()}, this method
* is <code>public</code>: it is interesting for the user of the traversal
* to learn if the traversal was cancelled.
*
* @see #notCancelled
*/
@Override
public final boolean cancelled() {
return !notCancelled;
}
/**
* Test if we weren't cancelled. Unlike {@link #cancelTraversal()}, this
* method is <code>public</code>: it is interesting for the user of the
* traversal to learn if the traversal was cancelled.
* <p>
* Most the time it is more interesting to know that the traversal wasn't
* cancelled, than to know that it was cancelled.
*
* @see #cancelled()
*/
@Override
public final boolean notCancelled() {
return notCancelled;
}
/*
* ============================================================= Default
* traversal methods
* =============================================================
*/
/**
* Get the traversal object for the specified traversal type.
*/
private AbstractTraversal generateTraversal(final int traversal) {
switch (traversal) {
case NO_DEFAULT:
return NullTraversal.prototype;
case PROCESS_BOTTOM_UP_COMPONENT_IMPL:
return new BottomUpComponentImplTraversal(this);
case PROCESS_POST_ORDER_ALL:
return new PostOrderTraversal(this);
case PROCESS_PRE_ORDER_ALL:
return new PreOrderTraversal(this);
case PROCESS_TOP_DOWN_COMPONENT_CLASSIFIER:
return new TopDownComponentClassifierTravseral(this);
case PROCESS_TOP_DOWN_COMPONENT_IMPL:
return new TopDownComponentImplTraversal(this);
}
return NullTraversal.prototype;
}
/**
* Execute the default traversal algorithm using the given root object. In
* case of instance models, takes into account the current mode when
* traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object to start the traversal.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> defaultTraversal(final Element obj) {
defaultTraversalMethod.visitRoot(obj);
return resultList;
}
/**
* Execute the default traversal algorithm using the given list of root
* objects. The traversal is run on each root node in the order they appear
* in the list. In case of instance models, takes into account the current
* mode when traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param objs List of root objects.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #defaultTraversalMethod
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> defaultTraversal(final List<? extends Element> objs) {
return defaultTraversalMethod.visitList(objs);
}
/**
* Perform the default traversal on all the declarative models in the
* workspace.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #defaultTraversalMethod
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList defaultTraversalAllDeclarativeModels() {
return defaultTraversalMethod.visitWorkspaceDeclarativeModels();
}
/**
* Perform the default traversal on all the instance models in the
* workspace. Not all traversal algorithsm support this operation: If the
* specified default traversal is {@link #PROCESS_BOTTOM_UP_COMPONENT_IMPL},
* {@link #PROCESS_TOP_DOWN_COMPONENT_CLASSIFIER}, or
* {@link #PROCESS_TOP_DOWN_COMPONENT_IMPL} then this will throw an
* {@link UnsupportedOperationException}.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #defaultTraversalMethod
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList defaultTraversalAllInstances() {
return defaultTraversalMethod.visitWorkspaceInstanceModels();
}
/*
* ============================================================= Prefix
* order traversal
* =============================================================
*/
/**
* Does preorder processing of the model starting at the given node. In case
* of instance models, takes into account the current mode when traversing
* the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object of the traversal.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processPreOrderAll(final Element obj) {
new PreOrderTraversal(this).visitRoot(obj);
return resultList;
}
/**
* Does preorder processing of the model starting at the given root nodes.
* The subtree rooted at each node in the list is visited in its entirety
* before the next root node is visited. In case of instance models, takes
* into account the current mode when traversing the content hierarchy of
* model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param objlist The roots nodes to be visited.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPreOrderAll(final EList objlist) {
return (new PreOrderTraversal(this)).visitList(objlist);
}
/**
* Process all AADL models in the AadlWorkspace in in prefix order. In case
* of instance models, takes into account the current mode when traversing
* the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPreOrderAll() {
return (new PreOrderTraversal(this)).visitWorkspace();
}
/**
* Process all declarative AADL models in the AadlWorkspace in prefix order.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPreOrderAllDeclarativeModels() {
return (new PreOrderTraversal(this)).visitWorkspaceDeclarativeModels();
}
/**
* Process all AADL instance models in the AadlWorkspace in prefix order. In
* case of instance models, takes into account the current mode when
* traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPreOrderAllInstances() {
return (new PreOrderTraversal(this)).visitWorkspaceInstanceModels();
}
/**
* Visits all the {@link ComponentInstance} objects in the given instance
* model in prefix order. Takes into account the current mode when
* traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object for the traversal.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processPreOrderComponentInstance(final ComponentInstance obj) {
processObject(obj);
final EList<Element> list = obj.getChildren();
for (Iterator<Element> it = list.iterator(); notCancelled() && it.hasNext();) {
final Element child = it.next();
if (child instanceof ComponentInstance) {
this.processPreOrderComponentInstance((ComponentInstance) child);
}
}
return resultList;
}
/**
* Visits all the {@link ComponentInstance} objects of the given category in
* the given instance model in prefix order. Takes into account the current
* mode when traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object for the traversal.
* @param cat The category of the component instances to visit.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processPreOrderComponentInstance(final ComponentInstance obj,
final ComponentCategory cat) {
// Only process if the category matches
if (obj.getCategory() == cat) {
processObject(obj);
}
// always scan the children
final EList<?> list = obj.getChildren();
for (Iterator<?> it = list.iterator(); notCancelled && it.hasNext();) {
final Element child = (Element) it.next();
if (child instanceof ComponentInstance) {
final ComponentInstance ci = (ComponentInstance) child;
this.processPreOrderComponentInstance(ci, cat);
}
}
return resultList;
}
/**
* process a single model element. When true is returned do not recurse to the element's children.
* By Default, if suchThat is satisfied invoke the action and return true.
* Otherwise do not take an action and return false.
* This lets use visit the first layer of elements in the hierarchy that satisfy suchThat.
* Using the default action, this effectively lets us create a list of "leaf" elements,
* i.e., elements that satisfy suchThat.
* @param theElement
* @return Boolean true if children should not be visited
*/
protected boolean processStop(Element theElement) {
if (suchThat(theElement)) {
if (theElement instanceof NamedElement) {
// { System.out.println(((NamedElement) theElement).getName());}
action(theElement);
}
return true;
}
return false;
}
/**
* Modifies processPreOrderComponentInstance to stop processing down
* when a component with error model is found
* If the suchThat method returned true, it means an error model subclause was found
* and we stop traversing the model down
*
* Does preorder processing of Component Instance containment hierarchy
* Takes into account the current mode when traversing the content hierarchy
* of model instances The default implementation applies the suchThat
* condition and if true adds the element to the result list
*
* @param obj
* InstanceObject root object
* @return EList result list of objects that have been visited by any traversal with the given ForAllElement
*
*/
public final EList processPreOrderComponentInstanceStop(ComponentInstance obj) {
if (!processStop(obj)) {
EList list = obj.getChildren();
for (Iterator it = list.iterator(); notCancelled() && it.hasNext();) {
Object child = it.next();
if (child instanceof ComponentInstance) {
processPreOrderComponentInstanceStop((ComponentInstance) child);
}
}
}
return resultList;
}
/*
* ============================================================= Postfix
* order traversal
* =============================================================
*/
/**
* Does postorder processing of the model starting at the given node. In
* case of instance models, takes into account the current mode when
* traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object of the traversal.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processPostOrderAll(final Element obj) {
(new PostOrderTraversal(this)).visitRoot(obj);
return resultList;
}
/**
* Does postorder processing of the model starting at the given root nodes.
* The subtree rooted at each node in the list is visited in its entirety
* before the next root node is visited. In case of instance models, takes
* into account the current mode when traversing the content hierarchy of
* model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param objlist The roots nodes to be visited.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPostOrderAll(final EList objlist) {
return (new PostOrderTraversal(this)).visitList(objlist);
}
/**
* Process all AADL models in the AadlWorkspace in postfix order. In case of
* instance models, takes into account the current mode when traversing the
* content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPostOrderAll() {
return (new PostOrderTraversal(this)).visitWorkspace();
}
/**
* Process all declarative AADL models in the AadlWorkspace in postfix
* order.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPostOrderAllDeclarativeModels() {
return (new PostOrderTraversal(this)).visitWorkspaceDeclarativeModels();
}
/**
* Process all AADL instance models in the AadlWorkspace in postfix order.
* Takes into account the current mode when traversing the content hierarchy
* of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processPostOrderAllInstances() {
return (new PostOrderTraversal(this)).visitWorkspaceInstanceModels();
}
/**
* Visits all the {@link ComponentInstance} objects in the given instance
* model in post fix order. Takes into account the current mode when
* traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object for the traversal.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processPostOrderComponentInstance(final ComponentInstance obj) {
final EList<Element> list = obj.getChildren();
for (Iterator<Element> it = list.iterator(); notCancelled() && it.hasNext();) {
final Element child = it.next();
if (child instanceof ComponentInstance) {
this.processPostOrderComponentInstance((ComponentInstance) child);
}
}
if (notCancelled()) {
processObject(obj);
}
return resultList;
}
/**
* Visits all the {@link ComponentInstance} objects that are of the given
* component category (e.g., system, data, thread, etc.) in the given
* instance model in post fix order. Takes into account the current mode
* when traversing the content hierarchy of model instances.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param obj The root object for the traversal.
* @param cat The category.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processPostOrderComponentInstance(final ComponentInstance obj,
final ComponentCategory cat) {
final EList<Element> list = obj.getChildren();
for (Iterator<Element> it = list.iterator(); notCancelled() && it.hasNext();) {
final Element child = it.next();
if (child instanceof ComponentInstance) {
this.processPostOrderComponentInstance((ComponentInstance) child);
}
}
// Only process if the category matches
if (notCancelled() && (obj.getCategory() == cat)) {
processObject(obj);
}
return resultList;
}
/*
* ============================================================= Top down
* classifier traversal
* =============================================================
*/
/**
* Visits all the Component Classifiers used in subtree rooted at the given
* node in a prefix order. That is, given a component implementation, it
* <ol>
* <li>visits the component implementation
* <li>visits the component type
* <li>For each subcomponent (including subprogram subcomponents)
* <ul>
* <li>recursively visits the component implementation of the subcomponent,
* if the full component implementation is given.
* <li>visits the component type of the subcomponent, if given
* </ul>
* </ol>
* <p>
* A particular classifier may be visited more than once.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param root The root node.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<Element> processTopDownComponentClassifier(final ComponentImplementation root) {
(new TopDownComponentClassifierTravseral(this)).visitRoot(root);
return resultList;
}
/**
* Process all declarative AADL models in the AadlWorkspace according to the
* top-down component-classifier ordering; see
* {@link #processTopDownComponentClassifier(ComponentImplementation)} for more
* information.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processTopDownComponentClassifierAllDeclarativeModels() {
return (new TopDownComponentClassifierTravseral(this)).visitWorkspaceDeclarativeModels();
}
/*
* ============================================================= Top down
* component implementation traversal
* =============================================================
*/
/**
* Visits all the Component Implementations used in the subtree rooted at
* the given node in a prefix order. That is, given a component
* implementation, it
* <ol>
* <li>visits the component implementation
* <li>For each subcomponent (including subprogram subcomponents) it
* recursively visits the component implementation of the subcomponent, if
* the full component implementation is given.
* </ol>
* <p>
* A particular classifier may be visited more than once.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @param root The root node.
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processTopDownComponentImpl(final ComponentImplementation root) {
(new TopDownComponentImplTraversal(this)).visitRoot(root);
return resultList;
}
/**
* Process all declarative AADL models in the AadlWorkspace according to the
* top-down component implementation ordering; see
* {@link #processTopDownComponentImpl(ComponentImplementation)} for more information.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processTopDownComponentImpl() {
return (new TopDownComponentImplTraversal(this)).visitWorkspaceDeclarativeModels();
}
/*
* ============================================================= Top down
* component implementation traversal
* =============================================================
*/
/**
* Visits all the component implementations in the subtree rooted at the
* given node in reverse containment order. That is, a component
* implementation is visited before all the component implementations that
* reference it.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processBottomUpComponentImpl(final ComponentImplementation root) {
(new BottomUpComponentImplTraversal(this)).visitRoot(root);
return resultList;
}
/**
* Visits all the component implementations in the workspace in reverse
* containment order. That is, a component implementation is visited before
* all the component implementations that reference it.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList<?> processBottomUpComponentImpl() {
return (new BottomUpComponentImplTraversal(this)).visitWorkspaceDeclarativeModels();
}
/*
* ============================================================= All
* component implementations
* =============================================================
*/
/**
* Visits all component implementations in the workspace.
* <p>
* This method checks {@link #notCancelled()} after visiting each element,
* and terminates the processing if the traversal has been cancelled.
*
* @return The value of {@link #resultList}. The contents of this list
* depend on the implementation of {@link #process}/{@link #action}.
* @see #cancelTraversal()
* @see #notCancelled()
* @see #process(Element)
*/
public final EList processAllComponentImpl() {
return processEList(AadlUtil.getAllComponentImpl());
}
/*
* ============================================================= Batch
* processing methods
* =============================================================
*/
/**
* Run a series of traversals over a set of resources, recording those that
* passed and those that failed. Each traversal is run over the all the
* resources before the next analysis is run. Only those resources that pass
* analysis <code>j</code> are analyzed by analysis <code>j+1</code>.
* Pass/fail is determined by whether the the number of errors on the
* resource increased after an analysis was run. Errors are determined by
* checking the error count (via
* {@link edu.cmu.sei.aadl.model.pluginsupport.ErrorReporter#getNumErrors()}
* ) on the error reporter associated with each Resource. The union of the
* returned set with the elements added to <code>outputBad</code> equals
* <code>inputResourceSet</code>.
*
* @param inputResourceSet Set of resources to analyse. The analysis is run
* on each resource in turn. The resources are assumed to be AADL
* Object models, that is the {@link Resource#getContents()}
* returns a one-element list whose element is an
* {@link edu.cmu.sei.aadl.model.core.AadlSpec} object.
* @param switches The analyses to run, as an array of length >= 1. Each
* analysis is invoked using its
* {@link #defaultTraversal(Element) default traversal}
* @param outputBad Set that is modified by the method to include all
* elements of <code>inputResourceSet</code> that fail the series
* analyses.
* @return An unmodifiable set of those elements of
* <code>inputResourceSet</code> that pass <em>all</em> the
* analyses.
*/
public static Set<Resource> processResources(final Set<? extends Resource> inputResourceSet,
final ForAllElement[] switches, final Set<? super Resource> outputBad) {
if (switches.length == 0) {
throw new IllegalArgumentException("Array of switches is zero-length");
}
Set<Resource> currentInput = new HashSet<Resource>(inputResourceSet);
for (int i = 0; i < switches.length; i++) {
currentInput = switches[i].processResources(currentInput, outputBad);
}
/*
* Must go through loop at least once, so currentInput will never alias
* inputResourceSet, although it may be a clone of it. Return value of
* processResources(...) is already unmodifiable.
*/
return currentInput;
}
/**
* Run a series of traversals over a set of resources, recording those that
* passed and those that failed. Each traversal is run over the all the
* resources before the next analysis is run. This method differs from
* {@link #processResources(Set, ForAllElement[], Set)} in that all the
* traversals are run over all the resources regardless of whether a
* previous traversal failed. Errors are determined by checking the error
* count (via
* {@link edu.cmu.sei.aadl.model.pluginsupport.ErrorReporter#getNumErrors()}
* ) on the error reporter associated with each Resource. The union of the
* returned set with the elements added to <code>outputBad</code> equals
* <code>inputResourceSet</code>.
*
* @param inputResourceSet Set of resources to analyse. The analysis is run
* on each resource in turn. The resources are assumed to be AADL
* Object models, that is the {@link Resource#getContents()}
* returns a one-element list whose element is an
* {@link edu.cmu.sei.aadl.model.core.AadlSpec} object.
* @param switches The analyses to run, as an array of length >= 1. Each
* analysis is invoked using its
* {@link #defaultTraversal(Element) default traversal}
* @param outputBad Set that is modified by the method to include all
* elements of <code>inputResourceSet</code> that fail the series
* analyses.
* @return An unmodifiable set of those elements of
* <code>inputResourceSet</code> that pass <em>all</em> the
* analyses.
*/
public static Set<Resource> processResourcesIgnoreFailure(final Set<? extends Resource> inputResourceSet,
final ForAllElement[] switches, final Set<? super Resource> outputBad) {
if (switches.length == 0) {
throw new IllegalArgumentException("Array of switches is zero-length");
}
final Set<Resource> bad = new HashSet<Resource>();
for (int i = 0; i < switches.length; i++) {
switches[i].processResources(inputResourceSet, bad);
}
final Set<Resource> result = new HashSet<Resource>(inputResourceSet);
result.removeAll(bad);
outputBad.addAll(bad);
return Collections.unmodifiableSet(result);
}
/**
* Run the {@link #defaultTraversal(Element) default traversal} over a set
* of resources, recording those that passed and those that failed.
* Pass/fail is determined by whether the the number of errors on the
* resource—as determined by error manager associated with the
* traversal object—increased after the analysis was run. The union of
* the return value and the elements added to <code>outputBad</code> equals
* <code>inputResourceSet</code>.
*
* @param inputResourceSet Set of resources to analyse. The analysis is run
* on each resource in turn. The resources are assumed to be AADL
* Object models, that is the {@link Resource#getContents()}
* returns a one-element list whose element is an
* {@link edu.cmu.sei.aadl.model.core.AadlSpec} object.
* @param outputBad Set that is modified by the method to include all
* elements of <code>inputResourceSet</code> that fail the
* analysis.
* @return An unmodifiable set of those elements of
* <code>inputResourceSet</code> that pass <em>all</em> the
* analyses.
*/
public final Set<Resource> processResources(final Set<? extends Resource> inputResourceSet,
final Set<? super Resource> outputBad) {
final Set<Resource> good = new HashSet<Resource>();
for (final Resource r : inputResourceSet) {
final EList<EObject> rc = r.getContents();
final AnalysisErrorReporter errReporter = errManager.getReporter(r);
final int errCountBefore = errReporter.getNumErrors();
if (!rc.isEmpty()) {
EObject o = rc.get(0);
this.defaultTraversal((Element) o);
}
if (errReporter.getNumErrors() > errCountBefore) {
outputBad.add(r);
} else {
good.add(r);
}
}
return Collections.unmodifiableSet(good);
}
/**
* Run a series of traversals over a tree rooted at a given Element. If a
* particular traversal fails, i.e., it generates errors in the error
* reporter, then the subsequent traversals are not performed.
*
* @param root The Element that is the root of the tree to traverse.
* @param switches The analyses to run, as an array of length >= 1. Each
* analysis is invoked using its
* {@link #defaultTraversal(Element) default traversal}
* @return The index of the last traversal to be successfully run. So if all
* the traversals were successful this value will be
* <code>switches.length-1</code>. If none of the traversals were
* successful, this value is <code>-1</code>.
*/
public static int processTree(final Element root, final ForAllElement[] switches) {
if (switches.length == 0) {
throw new IllegalArgumentException("Array of switches is zero-length");
}
final Resource rsrc = root.eResource();
int lastSuccessful = -1;
boolean failed = false;
for (int i = 0; !failed && i < switches.length; i++) {
final AnalysisErrorReporter errReporter = switches[i].getErrorManager().getReporter(rsrc);
final int beforeCount = errReporter.getNumErrors();
switches[i].defaultTraversal(root);
if (errReporter.getNumErrors() > beforeCount) {
failed = true;
} else {
lastSuccessful = i;
}
}
return lastSuccessful;
}
/**
* Run a series of traversals over a tree rooted at a given Element. All
* traversals are run over the tree regardless of whether a previous
* traversal failed.
*
* @param root The Element that is the root of the tree to traverse.
* @param switches The analyses to run, as an array of length >= 1. Each
* analysis is invoked using its
* {@link #defaultTraversal(Element) default traversal}
*/
public static void processTreeIgnoreFailure(final Element root, final ForAllElement[] switches) {
if (switches.length == 0) {
throw new IllegalArgumentException("Array of switches is zero-length");
}
for (int i = 0; i < switches.length; i++) {
switches[i].defaultTraversal(root);
}
}
/*
* ============================================================= Error
* reporting methods
* =============================================================
*/
/**
* Get the analysis error reporter manager associated with this traversal.
* @return the error manager
*/
public final AnalysisErrorReporterManager getErrorManager() {
return errManager;
}
/**
* Report an internal error.
*
* @param message The error message.
*/
public final void internalError(final String message) {
errManager.internalError(message);
}
/**
* Report an internal error.
*
* @param e The exception causing the error.
*/
public final void internalError(final Exception e) {
errManager.internalError(e);
}
/**
* Report an error on an Element (AADL object model object) using the error
* reporter associated with that object's {@link Resource}.
*
* @param obj the object to which the marker is pointing
* @param msg the message as string
*/
public final void error(final Element obj, final String msg) {
errManager.error(obj, msg);
}
public final void error(final Element obj, final String msg, final String[] attrs, final Object[] values) {
errManager.error(obj, msg, attrs, values);
}
/**
* Report a warning on an Element (AADL object model object) using the error
* reporter associated with that object's {@link Resource}.
*
* @param obj the object to which the marker is pointing
* @param msg the message as string
*/
public final void warning(final Element obj, final String msg) {
errManager.warning(obj, msg);
}
public final void warning(final Element obj, final String msg, final String[] attrs, final Object[] values) {
errManager.warning(obj, msg, attrs, values);
}
/**
* Report an information message on an Element (AADL object model object)
* using the error reporter associated with that object's {@link Resource}.
*
* @param obj the object to which the marker is pointing
* @param msg the message as string
*/
public final void info(final Element obj, final String msg) {
errManager.info(obj, msg);
}
public final void info(final Element obj, final String msg, final String[] attrs, final Object[] values) {
errManager.info(obj, msg, attrs, values);
}
}