Java tutorial
/******************************************************************************* * Copyright (c) 2015 Willink Transformations and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * E.D.Willink - Initial API and implementation *******************************************************************************/ package org.eclipse.qvtd.compiler.internal.scheduler; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.function.BinaryOperator; import java.util.stream.Stream; import org.eclipse.emf.ecore.EObject; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.ocl.pivot.Class; import org.eclipse.ocl.pivot.CollectionType; import org.eclipse.ocl.pivot.CompleteClass; import org.eclipse.ocl.pivot.CompleteModel; import org.eclipse.ocl.pivot.DataType; import org.eclipse.ocl.pivot.Import; import org.eclipse.ocl.pivot.Model; import org.eclipse.ocl.pivot.Property; import org.eclipse.ocl.pivot.Type; import org.eclipse.ocl.pivot.utilities.ClassUtil; import org.eclipse.ocl.pivot.utilities.FeatureFilter; import org.eclipse.ocl.pivot.utilities.PivotConstants; import org.eclipse.ocl.pivot.utilities.PivotUtil; import org.eclipse.qvtd.compiler.internal.schedule2qvti.QVTs2QVTiVisitor; import org.eclipse.qvtd.pivot.qvtbase.TypedModel; import org.eclipse.qvtd.pivot.qvtbase.utilities.QVTbaseUtil; import org.eclipse.qvtd.pivot.qvtcorebase.analysis.DomainUsage; import org.eclipse.qvtd.pivot.schedule.AbstractDatum; import org.eclipse.qvtd.pivot.schedule.ClassDatum; import org.eclipse.qvtd.pivot.schedule.PropertyDatum; import org.eclipse.qvtd.pivot.schedule.utilities.GraphStringBuilder; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; public class ScheduledRegion extends AbstractRegion { public static final class IsPassedBindingEdgePredicate implements Predicate<Connection> { public static final @NonNull IsPassedBindingEdgePredicate INSTANCE = new IsPassedBindingEdgePredicate(); @Override public boolean apply(Connection connection) { return connection.isPassed(); } } public static final class IsUsedBindingEdgePredicate implements Predicate<Connection> { public static final @NonNull IsUsedBindingEdgePredicate INSTANCE = new IsUsedBindingEdgePredicate(); @Override public boolean apply(Connection connection) { return connection.isUsed(); } } /** * Propagate the used bindings from callingNode to calledNode. */ private static void createUsedBindings(@NonNull Node calledNode, @Nullable Node callingNode, @NonNull Map<Node, Node> bindings) { Node oldPrevNode = bindings.get(calledNode); if (oldPrevNode != null) { // been here before assert (oldPrevNode == callingNode) || (callingNode == null); return; } if (bindings.containsKey(calledNode) && (callingNode == null)) { // here before and consistently null return; } bindings.put(calledNode, callingNode); for (NavigationEdge calledEdge : calledNode.getNavigationEdges()) { Node nextCalledNode = calledEdge.getTarget();//.getCastEquivalentNode(); if (!nextCalledNode.isRealized() && !nextCalledNode.isAttributeNode()) { Edge nextCallingEdge = callingNode != null ? callingNode.getNavigationEdge(calledEdge.getProperty()) : null; if (nextCallingEdge != null) { Node nextCallingNode = nextCallingEdge.getTarget();//.getCastEquivalentNode(); assert nextCallingNode.isNull() == nextCalledNode.isNull(); if (!nextCalledNode.isNull()) { createUsedBindings(nextCalledNode, nextCallingNode, bindings); } } else { createUsedBindings(nextCalledNode, null, bindings); } } } } /** * Return true if the predicates of calledNode are not in conflict with the navigable paths from callingNode. * bindings identifies already identified conflict free pairs that do not need re-assessment. */ private static boolean isConflictFree(@NonNull Node calledNode, @NonNull Node callingNode, @NonNull Map<Node, Node> bindings) { Node oldPrevNode = bindings.put(calledNode, callingNode); if (oldPrevNode != null) { assert oldPrevNode == callingNode; return true; } for (NavigationEdge calledEdge : calledNode.getNavigationEdges()) { Node nextCalledNode = calledEdge.getTarget();//.getCastEquivalentNode(); if (!nextCalledNode.isRealized() && !nextCalledNode.isAttributeNode()) { Edge nextCallingEdge = callingNode.getNavigationEdge(calledEdge.getProperty()); if (nextCallingEdge != null) { Node nextCallingNode = nextCallingEdge.getTarget();//.getCastEquivalentNode(); if ((nextCallingNode.isNull() != nextCalledNode.isNull())) { return false; } if (!isConflictFree(nextCalledNode, nextCallingNode, bindings)) { return false; } } } } return true; } public static @NonNull BinaryOperator<@NonNull String> stringJoin(@NonNull String delimiter) { return (a, b) -> String.valueOf(a) + delimiter + String.valueOf(b); } private final @NonNull String name; protected final @NonNull CompleteModel completeModel; /** */ private final @NonNull List<Region> regions = new ArrayList<Region>(); /** * All the connections defined in this region, but not those in nested regions. */ private @NonNull List<Connection> connections = new ArrayList<Connection>(); /** * The input models that may introduce model elements for transformation. */ private final @NonNull HashMap<Model, DomainUsage> inputModels = new HashMap<Model, DomainUsage>(); /** * Mapping from each input class to the composite properties that may contain the class or its subclasses. *-- The mapping incorporates an inheritance closure; a composition property that may compose B instances *-- is also registered as a composition of all of B's superclasses such as OclAny. Consequently a consumer *-- of some type need only lookup the consumed type to obtain all the composition properties that could *-- introduce the consumed type; the exact type or its superclasses that may need dynamic type selection. *-- If an input model is unhelpful enough to provide a composes-OclAny relationship, then this unhelpful *-- relationship is included in every entry since it must be considered as an introducer for every possible *-- consumption. */ private final @NonNull Map<ClassDatumAnalysis, @NonNull Set<Property>> containedClassDatumAnalysis2compositeProperties = new HashMap<ClassDatumAnalysis, @NonNull Set<Property>>(); /** * The input model classes that may be used as independent inputs by mappings and the nodes at which they are consumed. * In the worst case a flat schedule just permutes allInstances() to provide all mapping inputs. */ private final @NonNull Map<ClassDatumAnalysis, @NonNull List<Node>> consumedClassDatumAnalysis2headNodes = new HashMap<ClassDatumAnalysis, @NonNull List<Node>>(); /** * Mapping from each composite property to the classes consumed by mappings and transitive compositions. * No mapping entry is created for composition properties that are not required to introduce model elements. * * For simple cases each composition introduces instances of just a single class corresponding to its composed type. * In more complex cases a composition may also introduce instances of superclasses of its composed type. */ private final @NonNull Map<Property, @NonNull Set<ClassDatumAnalysis>> consumedCompositeProperty2introducedClassDatumAnalyses = new HashMap<Property, @NonNull Set<ClassDatumAnalysis>>(); /** * The per-class join nodes that identify all introducers. */ private final @NonNull Map<ClassDatumAnalysis, List<Node>> introducedClassDatumAnalysis2nodes = new HashMap<ClassDatumAnalysis, List<Node>>(); /** * The Realized Nodes that produce each ClassDatum. */ private final @NonNull Map<ClassDatumAnalysis, @NonNull List<Node>> producedClassDatumAnalysis2realizedNodes = new HashMap<ClassDatumAnalysis, @NonNull List<Node>>(); /** * The Realized Edges that produce each PropertyDatum (or its opposite). */ private final @NonNull Map<PropertyDatum, List<NavigationEdge>> producedPropertyDatum2realizedEdges = new HashMap<PropertyDatum, List<NavigationEdge>>(); /** * The per-class connections that unite a set of sources via a shared connection. */ private final @NonNull Map<ClassDatumAnalysis, Map<Set<Node>, Connection>> classDatumAnalysis2nodes2connections = new HashMap<ClassDatumAnalysis, Map<Set<Node>, Connection>>(); /** * The per-class connections that unite all producers and their non-input consumers. */ // private final @NonNull Map<ClassDatumAnalysis, Node> producedClassDatumAnalysis2joinNodes = new HashMap<ClassDatumAnalysis, Node>(); /** * The composition properties that can introduce instances for each ClassDatumAnalysis. */ // private final @NonNull Map<ClassDatumAnalysis, Set<Property>> consumedClassDatumAnalysis2compositionProperties = new HashMap<ClassDatumAnalysis, Set<Property>>(); private RegionOrdering regionOrderer = null; public ScheduledRegion(@NonNull String name, @NonNull Region primaryRegion) { super(primaryRegion.getSuperRegion()); this.name = name; this.completeModel = getSchedulerConstants().getEnvironmentFactory().getCompleteModel(); } public ScheduledRegion(@NonNull String name, @NonNull List<Region> regions) { super(ClassUtil.nonNullState(regions.get(0)).getSuperRegion()); this.name = name; this.completeModel = getSchedulerConstants().getEnvironmentFactory().getCompleteModel(); for (@SuppressWarnings("null") @NonNull Region region : regions) { addRegion(region); } } @Override public <R> R accept(@NonNull Visitor<R> visitor) { return visitor.visitRootRegion(this); } /** * Propagate all used binding edges up to an ordering edge in their common region. * // @SuppressWarnings("unused") private void accumulateOrderingDependencies() { Region2Order region2order = new Region2Order(); region2order.computeRegionOrdering(getCallableRegions()); for (Edge usedBindingEdge : getUsedBindingEdges()) { if (region2orderingEdge2usedEdges == null) { region2orderingEdge2usedEdges = new HashMap<Region, Map<Edge, Set<Edge>>>(); } Node targetNode = usedBindingEdge.getTarget(); // Iterable<Node> passedBindingSources = targetNode.getUsedBindingSources(); for (@SuppressWarnings("null")@NonNull Node sourceNode : targetNode.getUsedBindingSources()) { Set<Edge> orderingEdges = region2depths.accumulateOrderingDependency(sourceNode, targetNode); for (Edge orderingEdge : orderingEdges) { Region commonRegion = orderingEdge.getRegion(); Map<Edge, Set<Edge>> orderingEdge2usedEdges = region2orderingEdge2usedEdges.get(commonRegion); if (orderingEdge2usedEdges == null) { orderingEdge2usedEdges = new HashMap<Edge, Set<Edge>>(); region2orderingEdge2usedEdges.put(commonRegion, orderingEdge2usedEdges); } Set<Edge> usedEdges = orderingEdge2usedEdges.get(orderingEdge); if (usedEdges == null) { usedEdges = new HashSet<Edge>(); orderingEdge2usedEdges.put(orderingEdge, usedEdges); } usedEdges.add(usedBindingEdge); System.out.println("Ordering used children of " + commonRegion.getName() + " for " + usedBindingEdge); } } } for (Region region : getRegions()) { for (Edge recursionEdge : region.getRecursionEdges()) { if (region2orderingEdge2usedEdges == null) { region2orderingEdge2usedEdges = new HashMap<Region, Map<Edge, Set<Edge>>>(); } Node targetNode = recursionEdge.getTarget(); // Iterable<Node> passedBindingSources = targetNode.getUsedBindingSources(); // for (@SuppressWarnings("null")@NonNull Node sourceNode : targetNode.getUsedBindingSources()) { Node sourceNode = recursionEdge.getSource(); if (targetNode.isHead()) { for (@SuppressWarnings("null")@NonNull Node targetCallingNode : targetNode.getPassedBindingSources()) { for (@SuppressWarnings("null")@NonNull Node sourceCallingNode : sourceNode.getUsedBindingSources()) { // Check same region Set<Edge> orderingEdges = region2depths.accumulateOrderingDependency(sourceCallingNode, targetCallingNode); for (Edge orderingEdge : orderingEdges) { Region commonRegion = orderingEdge.getRegion(); Map<Edge, Set<Edge>> orderingEdge2usedEdges = region2orderingEdge2usedEdges.get(commonRegion); if (orderingEdge2usedEdges == null) { orderingEdge2usedEdges = new HashMap<Edge, Set<Edge>>(); region2orderingEdge2usedEdges.put(commonRegion, orderingEdge2usedEdges); } Set<Edge> recursionEdges = orderingEdge2usedEdges.get(orderingEdge); if (recursionEdges == null) { recursionEdges = new HashSet<Edge>(); orderingEdge2usedEdges.put(orderingEdge, recursionEdges); } recursionEdges.add(recursionEdge); System.out.println("Ordering recursive children of " + commonRegion.getName() + " for " + recursionEdges); } } } } } } return region2orderingEdge2usedEdges; } */ private void addConsumedNode(@NonNull Node headNode) { // assert !"EObject".equals(headNode.getCompleteClass().getName()); Region region = headNode.getRegion(); Region invokingRegion = region.getInvokingRegion(); assert (invokingRegion == this) || (invokingRegion == null); ClassDatumAnalysis consumedClassDatumAnalysis = headNode.getClassDatumAnalysis(); // if ("EObject".equals(consumedClassDatumAnalysis.getCompleteClass().getName())) { // System.out.println("Got it"); // } List<Node> nodes = consumedClassDatumAnalysis2headNodes.get(consumedClassDatumAnalysis); if (nodes == null) { nodes = new ArrayList<Node>(); consumedClassDatumAnalysis2headNodes.put(consumedClassDatumAnalysis, nodes); } if (!nodes.contains(headNode)) { nodes.add(headNode); } } // @Override public void addConnection(@NonNull Connection connection) { assert !connections.contains(connection); // for (Connection oldConnection : connections) { // if (oldConnection.getConnectionRole() == connection.getConnectionRole()) { // assert (edge.getSource() != oldConnection.getSource()) || (edge.getTarget() != oldConnection.getTarget()); // } // } connections.add(connection); } private void addIntroducedNode(@NonNull Node introducedNode) { ClassDatumAnalysis classDatumAnalysis = getElementalClassDatumAnalysis(introducedNode); List<Node> nodes = introducedClassDatumAnalysis2nodes.get(classDatumAnalysis); if (nodes == null) { nodes = new ArrayList<Node>(); introducedClassDatumAnalysis2nodes.put(classDatumAnalysis, nodes); } nodes.add(introducedNode); } private void addProducedEdge(@NonNull NavigationEdge producedEdge) { PropertyDatum propertyDatum = getPropertyDatum(producedEdge); if (propertyDatum == null) { propertyDatum = getPropertyDatum(producedEdge); // FIXME debugging } assert propertyDatum != null; addProducedEdge(producedEdge, propertyDatum); } private void addProducedEdge(@NonNull NavigationEdge producedEdge, @NonNull PropertyDatum propertyDatum) { List<NavigationEdge> edges = producedPropertyDatum2realizedEdges.get(propertyDatum); if (edges == null) { edges = new ArrayList<NavigationEdge>(); producedPropertyDatum2realizedEdges.put(propertyDatum, edges); } assert !edges.contains(producedEdge); edges.add(producedEdge); for (AbstractDatum superAbstractDatum : propertyDatum.getSuper()) { if (superAbstractDatum instanceof PropertyDatum) { addProducedEdge(producedEdge, (PropertyDatum) superAbstractDatum); } } } private void addProducedNode(@NonNull Node producedNode) { ClassDatumAnalysis classDatumAnalysis = getElementalClassDatumAnalysis(producedNode); for (ClassDatumAnalysis superClassDatumAnalysis : classDatumAnalysis.getSuperClassDatumAnalyses()) { List<Node> nodes = producedClassDatumAnalysis2realizedNodes.get(superClassDatumAnalysis); if (nodes == null) { nodes = new ArrayList<Node>(); producedClassDatumAnalysis2realizedNodes.put(superClassDatumAnalysis, nodes); } nodes.add(producedNode); } } public void addRegion(@NonNull Region region) { assert !regions.contains(region); if (regions.add(region)) { region.setInvokingRegion(this); // allMappingRegions.addAll(nestedRegion.getAllMappingRegions()); } } /* private void assignDepths() { Map<Region, Integer> region2depth = new HashMap<Region, Integer>(); for (Region region : getRegions()) { region.computeDepths(region2depth); } for (Map.Entry<Region, Integer> entry : region2depth.entrySet()) { System.out.println(entry.getValue() + " : " + entry.getKey().getName()); } } */ /** * Create the bindings and if necessary a join node to ensure that all sources of usedNode's * ClassDatum are ready before any usedNode's region executes.. * private void addUsedInputNode(@NonNull Node usedNode) { ClassDatumAnalysis classDatumAnalysis = usedNode.getClassDatumAnalysis(); Node joinNode = classDatumAnalysis2joinNodes.get(classDatumAnalysis); if (joinNode == null) { joinNode = Nodes.JOIN.createNode(this, "-all-", classDatumAnalysis); classDatumAnalysis2joinNodes.put(classDatumAnalysis, joinNode); List<Node> nodes = introducedClassDatumAnalysis2nodes.get(classDatumAnalysis); if (nodes != null) { for (@SuppressWarnings("null")@NonNull Node node : nodes) { Edges.PASSED_BINDING.createEdge(this, node, null, joinNode); } } List<Node> realizedNodes = producedClassDatumAnalysis2realizedNodes.get(classDatumAnalysis); if (realizedNodes != null) { for (@SuppressWarnings("null")@NonNull Node realizedNode : realizedNodes) { Edges.PASSED_BINDING.createEdge(this, realizedNode, null, joinNode); } } } Edges.USED_BINDING.createEdge(this, joinNode, null, usedNode); } */ /** * Identify all the classes whose instances may be required as independent mapping inputs. */ private void computeConsumedConsumedClassDatumAnalysis2headNodes() { // // Single-node head groups contribute a corresponding consumed class provided the // class is part of the input model and is not an internal convenience. // for (@SuppressWarnings("null") @NonNull Region region : getRegions()) { for (Node predicatedNode : region.getMatchableNodes()) { if (!predicatedNode.isHead()) { if (!predicatedNode.isLoaded() && !predicatedNode.isConstant() && !predicatedNode.isInternal()) { if (!isOnlyCastOrRecursed(predicatedNode)) { // FIXME Eliminate cast nodes addConsumedNode(predicatedNode); } } } } for (List<Node> headNodes : region.getHeadNodeGroups()) { if (headNodes.size() == 1) { Node headNode = headNodes.get(0); // if (headNode.isKnown() && !headNode.isInternal()) { if (headNode.isLoaded() && !headNode.isInternal()) { addConsumedNode(headNode); } } } } // // Multiple-node head groups contribute similarly, but just one corresponding class, // preferably one that is already consumed. // for (@SuppressWarnings("null") @NonNull Region region : getRegions()) { for (List<Node> headNodes : region.getHeadNodeGroups()) { if (headNodes.size() != 1) { boolean gotOne = false; for (Node headNode : headNodes) { if (!headNode.isKnown()) { gotOne = true; break; } else { ClassDatumAnalysis consumedClassDatumAnalysis = headNode.getClassDatumAnalysis(); if (consumedClassDatumAnalysis2headNodes.containsKey(consumedClassDatumAnalysis)) { gotOne = true; break; } } } if (!gotOne) { Node bestHeadNode = selectBestHeadNode(headNodes); addConsumedNode(bestHeadNode); } } } } } /** * Identify all the containment relationships in the input models. */ private void computeContainedClassDatumAnalysis2compositeProperties() { Map<org.eclipse.ocl.pivot.Package, DomainUsage> allPackagesSet = new HashMap<org.eclipse.ocl.pivot.Package, DomainUsage>(); List<org.eclipse.ocl.pivot.Package> allPackagesList = new ArrayList<org.eclipse.ocl.pivot.Package>(); for (@SuppressWarnings("null") @NonNull Model asModel : inputModels.keySet()) { DomainUsage domainUsage = inputModels.get(asModel); for (@SuppressWarnings("null") org.eclipse.ocl.pivot.@NonNull Package asPackage : asModel.getOwnedPackages()) { if (allPackagesSet.put(asPackage, domainUsage) == null) { allPackagesList.add(asPackage); } } for (@SuppressWarnings("null") @NonNull Import asImport : asModel.getOwnedImports()) { EObject importedObject = asImport.getImportedNamespace(); while ((importedObject != null) && !(importedObject instanceof org.eclipse.ocl.pivot.Package)) { importedObject = importedObject.eContainer(); } if (importedObject instanceof org.eclipse.ocl.pivot.Package) { org.eclipse.ocl.pivot.Package asPackage = (org.eclipse.ocl.pivot.Package) importedObject; if (allPackagesSet.put(asPackage, domainUsage) == null) { allPackagesList.add(asPackage); } } } } for (int i = 0; i < allPackagesList.size(); i++) { org.eclipse.ocl.pivot.Package asPackage = allPackagesList.get(i); DomainUsage domainUsage = ClassUtil.nonNullState(allPackagesSet.get(asPackage)); for (@SuppressWarnings("null") org.eclipse.ocl.pivot.@NonNull Package asPackage2 : asPackage.getOwnedPackages()) { if (allPackagesSet.put(asPackage2, domainUsage) == null) { allPackagesList.add(asPackage2); } } for (@SuppressWarnings("null") org.eclipse.ocl.pivot.@NonNull Class asClass : asPackage.getOwnedClasses()) { for (@SuppressWarnings("null") @NonNull Property asProperty : asClass.getOwnedProperties()) { if (asProperty.isIsComposite()) { computeContainedClassDatumAnalysis2compositeProperties3(asProperty, domainUsage); } Type asType = asProperty.getType(); if (asType instanceof org.eclipse.ocl.pivot.Class) { org.eclipse.ocl.pivot.Package asPackage2 = ((org.eclipse.ocl.pivot.Class) asType) .getOwningPackage(); if (allPackagesSet.put(asPackage2, domainUsage) == null) { allPackagesList.add(asPackage2); } } } } } assert allPackagesSet.size() == allPackagesList.size(); assert allPackagesSet.keySet().equals(new HashSet<org.eclipse.ocl.pivot.Package>(allPackagesList)); } private void computeContainedClassDatumAnalysis2compositeProperties3(@NonNull Property asProperty, @NonNull DomainUsage domainUsage) { Type asType = QVTbaseUtil.getElementalType(ClassUtil.nonNullState(asProperty.getType())); if (asType instanceof org.eclipse.ocl.pivot.Class) { ClassDatumAnalysis classDatumAnalysis = getSchedulerConstants().getClassDatumAnalysis((Class) asType, ClassUtil.nonNullState(domainUsage.getTypedModel())); Set<Property> compositeProperties = containedClassDatumAnalysis2compositeProperties .get(classDatumAnalysis); if (compositeProperties == null) { compositeProperties = new HashSet<Property>(); containedClassDatumAnalysis2compositeProperties.put(classDatumAnalysis, compositeProperties); } compositeProperties.add(asProperty); } } /** * Identify all the classes/superClasses/subClasses that each compositeProperty may introduce for use as mapping heads. We do not * need to worry about arbitrary user extensions since the introducer will introduce such an extension as one or more of the types * that are actually interesting as inputs. * * NB. A mapping expecting an instance of K is statically applicable for any instance of a class derived from K, * and dynamically applicable for any instance of K masquerading as one of its super Class. */ private void computeConsumedCompositeProperty2introducedClassDatumAnalyses() { // // Find the composite properties for each consumed class and its super classes, and accumulate // the container classes of all used properties as additional consumed classes. // Set<ClassDatumAnalysis> allConsumedClassDatumAnalyses = new HashSet<ClassDatumAnalysis>( consumedClassDatumAnalysis2headNodes.keySet()); List<ClassDatumAnalysis> allConsumedClassDatumAnalysesList = new ArrayList<ClassDatumAnalysis>( allConsumedClassDatumAnalyses); for (int i = 0; i < allConsumedClassDatumAnalysesList.size(); i++) { ClassDatumAnalysis consumedClassDatumAnalysis = allConsumedClassDatumAnalysesList.get(i); for (@SuppressWarnings("null") @NonNull ClassDatumAnalysis consumedSuperClassDatumAnalysis : consumedClassDatumAnalysis .getSuperClassDatumAnalyses()) { Set<Property> consumedCompositeProperties = containedClassDatumAnalysis2compositeProperties .get(consumedSuperClassDatumAnalysis); if (consumedCompositeProperties != null) { for (Property consumedCompositeProperty : consumedCompositeProperties) { // Set<Property> consumedCompositeProperties = consumedClassDatumAnalysis2compositionProperties.get(consumedClassDatumAnalysis); // if (consumedCompositeProperties == null) { // consumedCompositeProperties = new HashSet<Property>(); // consumedClassDatumAnalysis2compositionProperties.put(consumedClassDatumAnalysis, consumedCompositeProperties); // } // consumedCompositeProperties.add(compositeProperty); Set<ClassDatumAnalysis> introducedClassDatumAnalyses = consumedCompositeProperty2introducedClassDatumAnalyses .get(consumedCompositeProperty); if (introducedClassDatumAnalyses == null) { introducedClassDatumAnalyses = new HashSet<ClassDatumAnalysis>(); consumedCompositeProperty2introducedClassDatumAnalyses.put(consumedCompositeProperty, introducedClassDatumAnalyses); } introducedClassDatumAnalyses.add(consumedClassDatumAnalysis); org.eclipse.ocl.pivot.Class containerClass = consumedCompositeProperty.getOwningClass(); assert containerClass != null; ClassDatumAnalysis containerSuperClassDatumAnalysis = getSchedulerConstants() .getClassDatumAnalysis(containerClass, consumedClassDatumAnalysis.getTypedModel()); if (allConsumedClassDatumAnalyses.add(containerSuperClassDatumAnalysis)) { allConsumedClassDatumAnalysesList.add(containerSuperClassDatumAnalysis); } } } } } assert allConsumedClassDatumAnalyses.size() == allConsumedClassDatumAnalysesList.size(); } private void computeInputModels() { for (ClassDatumAnalysis classDatumAnalysis : getSchedulerConstants().getClassDatumAnalyses()) { DomainUsage domainUsage = classDatumAnalysis.getDomainUsage(); if (domainUsage.isCheckable() && !domainUsage.isEnforceable()) { Type type = classDatumAnalysis.getClassDatum().getType(); org.eclipse.ocl.pivot.Package asPackage = PivotUtil.getContainingPackage(type); if ((asPackage != null) && !PivotConstants.ORPHANAGE_URI.equals(asPackage.getURI())) { Model model = PivotUtil.getContainingModel(type); if (model != null) { inputModels.put(model, domainUsage); } } } } } /* private void computeProperty2introducedClasses() { // // Find the composite properties for each consumed class and its super classes, and accumulate // the container classes of all used properties as additional consumed classes. // Set<ClassDatumAnalysis> allConsumedClassDatumAnalyses = new HashSet<ClassDatumAnalysis>(consumedClassDatumAnalysis2headNodes.keySet()); List<ClassDatumAnalysis> allConsumedClassDatumAnalysesList = new ArrayList<ClassDatumAnalysis>(allConsumedClassDatumAnalyses); for (int i = 0; i < allConsumedClassDatumAnalysesList.size(); i++) { ClassDatumAnalysis consumedClassDatumAnalysis = allConsumedClassDatumAnalysesList.get(i); for (@SuppressWarnings("null")@NonNull ClassDatumAnalysis consumedSuperClassDatumAnalysis : consumedClassDatumAnalysis.getSuperClassDatumAnalyses()) { Set<Property> compositeProperties = containedClassDatumAnalysisClosure2compositeProperties.get(consumedSuperClassDatumAnalysis); if (compositeProperties != null) { for (Property compositeProperty : compositeProperties) { Set<Property> consumedCompositeProperties = consumedClassDatumAnalysis2compositionProperties.get(consumedClassDatumAnalysis); if (consumedCompositeProperties == null) { consumedCompositeProperties = new HashSet<Property>(); consumedClassDatumAnalysis2compositionProperties.put(consumedClassDatumAnalysis, consumedCompositeProperties); } consumedCompositeProperties.add(compositeProperty); Set<ClassDatumAnalysis> introducedClassDatumAnalyses = consumedCompositeProperty2introducedClassDatumAnalyses.get(compositeProperty); if (introducedClassDatumAnalyses == null) { introducedClassDatumAnalyses = new HashSet<ClassDatumAnalysis>(); consumedCompositeProperty2introducedClassDatumAnalyses.put(compositeProperty, introducedClassDatumAnalyses); } introducedClassDatumAnalyses.add(consumedSuperClassDatumAnalysis); org.eclipse.ocl.pivot.Class containerClass = compositeProperty.getOwningClass(); assert containerClass != null; ClassDatumAnalysis containerSuperClassDatumAnalysis = getSchedulerConstants().getClassDatumAnalysis(containerClass, consumedSuperClassDatumAnalysis.getDomainUsage()); if (allConsumedClassDatumAnalyses.add(containerSuperClassDatumAnalysis)) { allConsumedClassDatumAnalysesList.add(containerSuperClassDatumAnalysis); } } } } } assert allConsumedClassDatumAnalyses.size() == allConsumedClassDatumAnalysesList.size(); // // Find the composite properties for which a superclass of a contained class is a consumed class. // for (Entry<ClassDatumAnalysis, Set<Property>> entry : containedClassDatumAnalysisClosure2compositeProperties.entrySet()) { ClassDatumAnalysis classDatumAnalysis = entry.getKey(); for (@SuppressWarnings("null")@NonNull ClassDatumAnalysis superClassDatumAnalysis : classDatumAnalysis.getSuperClassDatumAnalyses()) { if (consumedClassDatumAnalysis2headNodes.get(superClassDatumAnalysis) != null) { for (Property compositeProperty : entry.getValue()) { Set<ClassDatumAnalysis> introducedClassDatumAnalyses = consumedCompositeProperty2introducedClassDatumAnalyses.get(compositeProperty); if (introducedClassDatumAnalyses == null) { introducedClassDatumAnalyses = new HashSet<ClassDatumAnalysis>(); consumedCompositeProperty2introducedClassDatumAnalyses.put(compositeProperty, introducedClassDatumAnalyses); } introducedClassDatumAnalyses.add(superClassDatumAnalysis); } } } } } */ /** * Identify all the classes that are produced by mappings. */ private void computeProducedClassDatumAnalysis2realizedNodes() { // // Single-node head groups contribute a corresponding consumed class provided the // class is part of the input model and is not an internal convenience. // for (@SuppressWarnings("null") @NonNull Region region : getRegions()) { for (Node assignedNode : region.getAssignedNodes()) { if (assignedNode.isClassNode()) { addProducedNode(assignedNode); } } for (@SuppressWarnings("null") @NonNull NavigationEdge realizedNavigationEdge : region.getRealizedNavigationEdges()) { addProducedEdge(realizedNavigationEdge); } } } /** * Where multiple child consumers are ordered, redirect the later consumers to use the * preceding consumer making all the state of the preceding consumers available for re-use. * @SuppressWarnings("unused") private void convertConsumedOrdering(@NonNull Region commonRegion, @NonNull Map<Edge, Set<Edge>> orderingEdge2usedEdges) { for (Node node : commonRegion.getNodes()) { Iterable<Node> passedBindingTargets = node.getPassedBindingTargets(); if (Iterables.size(passedBindingTargets) > 0) { Iterable<Node> sortedCalledNodes = AbstractNode.getSortedTargets(passedBindingTargets); Set<Node> availableSources = new HashSet<Node>(); Set<Node> oldConnections = null; Node sourceNode = node; availableSources.add(sourceNode); for (Node calledNode : sortedCalledNodes) { Edge callingEdge = calledNode.getPassedBindingEdge(); assert callingEdge != null; Node oldSource = callingEdge.getSource(); if (oldSource.isConnection()) { if (oldConnections == null) { oldConnections = new HashSet<Node>(); } oldConnections.add(oldSource); } Set<Node> requiredSources = new HashSet<Node>(); for (Node requiredSource : calledNode.getPassedBindingSources()) { requiredSources.add(requiredSource); } requiredSources.removeAll(availableSources); requiredSources.add(sourceNode); Node sourceOrConnectionNode = getSourceOrConnectionNode(requiredSources, sourceNode.getClassDatumAnalysis()); if (oldSource != sourceOrConnectionNode) { callingEdge.setSource(sourceOrConnectionNode); } availableSources.addAll(requiredSources); sourceNode = calledNode; } if (oldConnections != null) { for (Node oldConnection : oldConnections) { if (oldConnection.getOutgoingEdges().size() <= 0) { oldConnection.destroy(); } } } } } } */ /** * Create the Passed Binding edges and join nodes between all introducers and their corresponding consuming heads. */ private void createBindings() { for (Region region : getCallableRegions()) { if (region instanceof RootRegion) { continue; } // // Single-node head groups contribute a corresponding consumed class provided the // class is part of the input model and is not an internal convenience. // for (List<Node> headNodes : region.getHeadNodeGroups()) { Node headNode; if (headNodes.size() == 1) { headNode = headNodes.get(0); } else { headNode = selectBestHeadNode(headNodes); } if (/*headNode.isLoaded() &&*/ !headNode.isInternal()) { createBinding(headNode); } } // // Bind the non-navigable predicated nodes too // for (NavigationEdge predicatedEdge : region.getPredicatedNavigationEdges()) { Node predicatedNode = predicatedEdge.getTarget(); if (predicatedEdge.isNavigation() && !predicatedEdge.isCast()) { // FIXME isCast does not need to be isNavigation now that it can be isNavigable PropertyDatum propertyDatum = getPropertyDatum(predicatedEdge); List<NavigationEdge> realizedEdges = producedPropertyDatum2realizedEdges.get(propertyDatum); if (realizedEdges != null) { Property predicatedProperty = predicatedEdge.getProperty(); List<Node> realizingNodes = new ArrayList<Node>(); for (NavigationEdge realizedEdge : realizedEdges) { Node realizedNode; if (realizedEdge.getProperty() == predicatedProperty) { realizedNode = realizedEdge.getTarget(); } else { assert realizedEdge.getProperty() == predicatedProperty.getOpposite(); realizedNode = realizedEdge.getSource(); } if (!realizingNodes.contains(realizedNode)) { realizingNodes.add(realizedNode); } } boolean isCast = false; boolean isOther = false; boolean isRecursion = false; for (Edge outgoingEdge : predicatedNode.getOutgoingEdges()) { if (outgoingEdge.isCast()) { isCast = true; Node castNode = outgoingEdge.getTarget(); assert !castNode.isConstant(); assert !castNode.isLoaded(); Connection predicatedConnection = getConnection(realizingNodes, castNode.getClassDatumAnalysis()); if (!Iterables.contains(predicatedConnection.getTargets(), castNode)) { predicatedConnection.addUsedTargetNode(castNode, false); } } else if (outgoingEdge.isRecursion()) { isRecursion = true; } else { isOther = true; } } if (isOther || !(isCast || isRecursion)) { // Iterable<Connection> passedConnections = predicatedNode.getIncomingPassedConnections(); // Connection usedConnection = predicatedNode.getIncomingUsedConnection(); // boolean isNew = (usedConnection == null) && Iterables.isEmpty(passedConnections); // if (!isNew) { // FIXME could be multiple // isNew = (usedConnection == null) && Iterables.isEmpty(passedConnections); // } // FIXME could be multiple Connection predicatedConnection = getConnection(realizingNodes, predicatedNode.getClassDatumAnalysis()); if (!Iterables.contains(predicatedConnection.getTargets(), predicatedNode)) { predicatedConnection.addUsedTargetNode(predicatedNode, false); } } } } // if (!predicatedNode.isLoaded() && !predicatedNode.isConstant() && !isOnlyCastOrRecursed(predicatedNode)) { // } } } } private void createBinding(@NonNull Node headNode) { List<Node> sourceNodes = null; ClassDatumAnalysis classDatumAnalysis = headNode.getClassDatumAnalysis(); // // Locate viable introducers // Iterable<Node> recursionSources = headNode.getRecursionSources(); List<Node> introducingNodes = getIntroducingNodes(classDatumAnalysis); if (introducingNodes != null) { for (@SuppressWarnings("null") @NonNull Node introducingNode : introducingNodes) { if (isConflictFree(headNode, introducingNode, new HashMap<Node, Node>()) && !Iterables.contains(recursionSources, introducingNode)) { if (sourceNodes == null) { sourceNodes = new ArrayList<Node>(); } sourceNodes.add(introducingNode); } } } // // Locate viable producers // List<Node> producingNodes = getProducingNodes(classDatumAnalysis); if (producingNodes != null) { for (@SuppressWarnings("null") @NonNull Node producingNode : producingNodes) { if (isConflictFree(headNode, producingNode, new HashMap<Node, Node>())) { if (sourceNodes == null) { sourceNodes = new ArrayList<Node>(); } sourceNodes.add(producingNode); } } } if (sourceNodes != null) { // // Connection up the head // Connection headConnection = getConnection(sourceNodes, headNode.getClassDatumAnalysis()); if (headNode.getNodeRole().isExtraGuardVariable()) { headConnection.addUsedTargetNode(headNode, false); } else { headConnection.addPassedTargetNode(headNode); } // // Locate the corresponding sources for each guard in each calling region. // HashMap<Node, List<Node>> predicated2availableSources = new HashMap<Node, List<Node>>(); HashMap<Node, List<Region>> predicated2missingSources = new HashMap<Node, List<Region>>(); for (Node sourceNode : sourceNodes) { Region headRegion = headNode.getRegion(); if ((headRegion != sourceNode.getRegion()) && !(headRegion instanceof CompositionRegion)) { HashMap<Node, Node> predicated2source = new HashMap<Node, Node>(); createUsedBindings(headNode, sourceNode, predicated2source); for (Map.Entry<Node, Node> entry : predicated2source.entrySet()) { @SuppressWarnings("null") @NonNull Node calledNode = entry.getKey(); if (!calledNode.isHead()) { Node callingNode = entry.getValue(); if (callingNode != null) { List<Node> availableSources = predicated2availableSources.get(calledNode); if (availableSources == null) { availableSources = new ArrayList<Node>(); predicated2availableSources.put(calledNode, availableSources); } availableSources.add(callingNode); } else { List<Region> missingSources = predicated2missingSources.get(calledNode); if (missingSources == null) { missingSources = new ArrayList<Region>(); predicated2missingSources.put(calledNode, missingSources); } missingSources.add(sourceNode.getRegion()); } } } } } // // Connection the available calling sources to their called guards. // for (Map.Entry<Node, List<Node>> entry : predicated2availableSources.entrySet()) { @SuppressWarnings("null") @NonNull Node calledNode = entry.getKey(); if (!calledNode.isLoaded() && !calledNode.isConstant()) { @SuppressWarnings("null") @NonNull List<Node> availableNodes = entry.getValue(); Connection guardConnection = getConnection(availableNodes, calledNode.getClassDatumAnalysis()); guardConnection.addUsedTargetNode(calledNode, false); } } for (Map.Entry<Node, List<Region>> entry : predicated2missingSources.entrySet()) { @SuppressWarnings("null") @NonNull Node calledNode = entry.getKey(); // @SuppressWarnings("null")@NonNull List<Region> missingRegions = entry.getValue(); // for (Region missingRegion : missingRegions) { ClassDatumAnalysis classDatumAnalysis2 = calledNode.getClassDatumAnalysis(); List<Node> missingSourceNodes = new ArrayList<Node>(); List<Node> introducedNodes = getIntroducingNodes(classDatumAnalysis2); if (introducedNodes != null) { missingSourceNodes.addAll(introducedNodes); } List<Node> producedNodes = getProducingNodes(classDatumAnalysis2); if (producedNodes != null) { missingSourceNodes.addAll(producedNodes); } for (int i = missingSourceNodes.size(); --i >= 0;) { Node missingSourceNode = missingSourceNodes.get(i); if (missingSourceNode.getRegion() == calledNode.getRegion()) { missingSourceNodes.remove(i); // FIXME only if a Recursion Edge } } if ((missingSourceNodes.size() > 0) && !calledNode.isLoaded()) { Connection missingConnection = getConnection(missingSourceNodes, calledNode.getClassDatumAnalysis()); missingConnection.addUsedTargetNode(calledNode, false); } // } } // FIXME guard2missingSources } } /** * Create a ContainmentRegion for each in-use composition property with a head consuming node to consume the containing class * and an introduced node for each class by which the composed instances are consumed. */ private @NonNull List<Region> createContainmentRegions() { List<Region> containmentRegions = new ArrayList<Region>(); for (Entry<Property, Set<ClassDatumAnalysis>> entry : consumedCompositeProperty2introducedClassDatumAnalyses .entrySet()) { @SuppressWarnings("null") @NonNull Property parent2childrenProperty = entry.getKey(); TypedModel typedModel = entry.getValue().iterator().next().getTypedModel(); CompositionRegion containmentRegion = new CompositionRegion(superRegion, parent2childrenProperty, typedModel); Node headNode = containmentRegion.getComposingNode(); CompleteClass parentClass = headNode.getCompleteClass(); addConsumedNode(headNode); for (@SuppressWarnings("null") @NonNull ClassDatumAnalysis classDatumAnalysis : entry.getValue()) { Node introducedNode = containmentRegion.addClassDatumAnalysis(classDatumAnalysis); addIntroducedNode(introducedNode); CompleteClass childClass = introducedNode.getCompleteClass(); Type childType = childClass.getPrimaryClass(); if (childType instanceof CollectionType) { @SuppressWarnings("null") @NonNull Type elementType = ((CollectionType) childType).getElementType(); childClass = getSchedulerConstants().getEnvironmentFactory().getCompleteModel() .getCompleteClass(elementType); } if (childClass.conformsTo(parentClass)) { Edges.PRIMARY_RECURSION.createEdge(containmentRegion, introducedNode, headNode); } } containmentRegions.add(containmentRegion); getSchedulerConstants().writeDOTfile(containmentRegion, "-3-contained"); getSchedulerConstants().writeGraphMLfile(containmentRegion, "-3-contained"); addRegion(containmentRegion); } return containmentRegions; } /** * Create the Used Binding edges and join nodes between all introducers and their corresponding non-head guards. * private void createNonHeadUsedBindings() { for (Region region : getRegions()) { for (Node predicatedNode : region.getMatchableNodes()) { if (/*!predicatedNode.isHead() &&* / predicatedNode.isClassNode()) { if (/*!predicatedNode.isLoaded() &&* / !predicatedNode.isHead() && !predicatedNode.isInternal() && (predicatedNode == predicatedNode.getCastEquivalentNode())) { // predicatedNode = predicatedNode.getCastEquivalentNode(); createNonHeadUsedBinding(predicatedNode); } } } } } */ /** * Create the bindings and if necessary a join node to ensure that all sources of consumingNode's * ClassDatum are passed to consumingNode using a bindingFactory edge. * private void createNonHeadUsedBinding(@NonNull Node guardNode) { List<Node> sourceNodes = null; ClassDatumAnalysis classDatumAnalysis = guardNode.getClassDatumAnalysis(); // // Locate viable introducers // List<Node> introducingNodes = introducedClassDatumAnalysis2nodes.get(classDatumAnalysis); if (introducingNodes != null) { for (Node introducingNode : introducingNodes) { if (introducingNode.getRegion().isConflictFree(introducingNode, guardNode)) { if (sourceNodes == null) { sourceNodes = new ArrayList<Node>(); } sourceNodes.add(introducingNode); } } } // // Locate viable producers // List<Node> producingNodes = producedClassDatumAnalysis2realizedNodes.get(classDatumAnalysis); if (producingNodes != null) { for (Node producingNode : producingNodes) { if (producingNode.getRegion().isConflictFree(producingNode, guardNode)) { if (sourceNodes == null) { sourceNodes = new ArrayList<Node>(); } sourceNodes.add(producingNode); } } } // // Connection them up // ClassDatumAnalysis classDatumAnalysis = guardNode.getClassDatumAnalysis(); List<Node> introducedNodes = introducedClassDatumAnalysis2nodes.get(classDatumAnalysis); List<Node> producedNodes = producedClassDatumAnalysis2realizedNodes.get(classDatumAnalysis); int size = (introducedNodes != null ? introducedNodes.size() : 0) + (producedNodes != null ? producedNodes.size() : 0); if (size <= 1) { if (introducedNodes != null) { for (@SuppressWarnings("null")@NonNull Node introducedNode : introducedNodes) { Edges.USED_BINDING.createEdge(this, introducedNode, null, guardNode); } } if (producedNodes != null) { for (@SuppressWarnings("null")@NonNull Node producedNode : producedNodes) { Edges.USED_BINDING.createEdge(this, producedNode, null, guardNode); } } } else { Node joinNode = classDatumAnalysis2joinNodes.get(classDatumAnalysis); if (joinNode == null) { joinNode = Nodes.JOIN.createNode(this, "-join-", classDatumAnalysis); classDatumAnalysis2joinNodes.put(classDatumAnalysis, joinNode); if (introducedNodes != null) { for (@SuppressWarnings("null")@NonNull Node introducedNode : introducedNodes) { Edges.PASSED_BINDING.createEdge(this, introducedNode, null, joinNode); } } if (producedNodes != null) { for (@SuppressWarnings("null")@NonNull Node producedNode : producedNodes) { Edges.PASSED_BINDING.createEdge(this, producedNode, null, joinNode); } } } Edges.USED_BINDING.createEdge(this, joinNode, null, guardNode); } } */ /** * Create a RootContainmentRegion that introduces model elements directly from the input model root, or from * composition relationships that form part of an extended metamodel that is not known until run-time. */ private @NonNull RootRegion createRootContainmentRegion() { RootRegion rootContainmentRegion = new RootRegion(superRegion); /* Set<ClassDatumAnalysis> rootClassDatumAnalyses = new HashSet<ClassDatumAnalysis>(); for (Entry<Property, Set<ClassDatumAnalysis>> entry : consumedCompositeProperty2introducedClassDatumAnalyses.entrySet()) { @SuppressWarnings("null")@NonNull Property parent2childrenProperty = entry.getKey(); Property childrenToParentProperty = parent2childrenProperty.getOpposite(); if ((childrenToParentProperty == null) || !childrenToParentProperty.isIsRequired()) { for (@SuppressWarnings("null")@NonNull ClassDatumAnalysis consumedClassDatumAnalysis : entry.getValue()) { if (rootClassDatumAnalyses.add(consumedClassDatumAnalysis)) { ClassNode introducedNode = rootContainmentRegion.addClassDatumAnalysis(consumedClassDatumAnalysis); addIntroducedNode(introducedNode); } } } } */ addRegion(rootContainmentRegion); Set<ClassDatumAnalysis> consumedClassDatumAnalyses = consumedClassDatumAnalysis2headNodes.keySet(); // FIXME all consumed classes for (@SuppressWarnings("null") @NonNull ClassDatumAnalysis consumedClassDatumAnalysis : consumedClassDatumAnalyses) { // System.out.println("ScheduledRegion.createRootContainmentRegion: " + consumedClassDatumAnalysis); boolean canBeAtRoot = !consumedClassDatumAnalysis.getDomainUsage().isEnforceable(); if (consumedClassDatumAnalysis.getClassDatum().getType() instanceof DataType) { canBeAtRoot = false; } else { Set<Property> containments = containedClassDatumAnalysis2compositeProperties .get(consumedClassDatumAnalysis); if (containments != null) { Set<Property> containments2 = new HashSet<Property>(); // FIXME omits independent containers for (Property property : consumedClassDatumAnalysis.getCompleteClass() .getProperties((FeatureFilter) null)) { Property oppositeProperty = property.getOpposite(); if ((oppositeProperty != null) && oppositeProperty.isIsComposite() && oppositeProperty.isIsRequired()) { containments2.add(oppositeProperty); } } // assert containments.equals(containments2); for (Property containment : containments) { Property container = containment.getOpposite(); if ((container != null) && container.isIsRequired()) { canBeAtRoot = false; break; } } } } if (canBeAtRoot) { Node introducedNode = rootContainmentRegion.addClassDatumAnalysis(consumedClassDatumAnalysis); addIntroducedNode(introducedNode); } } getSchedulerConstants().writeDOTfile(rootContainmentRegion, ""); return rootContainmentRegion; } public void createSchedule() { // // Identify the input models. // computeInputModels(); if (Scheduler.DUMP_INPUT_MODEL_TO_DOMAIN_USAGE.isActive()) { Scheduler.DUMP_INPUT_MODEL_TO_DOMAIN_USAGE.println(dumpInputModels().reduce("", stringJoin("\n\t"))); } // // Identify all the containment relationships in the input models. // computeContainedClassDatumAnalysis2compositeProperties(); if (Scheduler.DUMP_CLASS_TO_CONTAINING_PROPERTIES.isActive()) { Scheduler.DUMP_CLASS_TO_CONTAINING_PROPERTIES .println(dumpClass2ContainingProperties().reduce("", stringJoin("\n\t"))); } // // Identify all classes that are produced by mappings. // computeProducedClassDatumAnalysis2realizedNodes(); if (Scheduler.DUMP_CLASS_TO_REALIZED_NODES.isActive()) { Scheduler.DUMP_CLASS_TO_REALIZED_NODES .println(dumpClass2ProducingNode().reduce("", stringJoin("\n\t"))); } // // Identify all classes that are consumed as independent inputs of mappings. // computeConsumedConsumedClassDatumAnalysis2headNodes(); if (Scheduler.DUMP_CLASS_TO_CONSUMING_NODES.isActive()) { Scheduler.DUMP_CLASS_TO_CONSUMING_NODES .println(dumpClass2consumingNode().reduce("", stringJoin("\n\t"))); } // // Identify all classes that are transitively consumed as containers of consumed classes. // computeConsumedCompositeProperty2introducedClassDatumAnalyses(); if (Scheduler.DUMP_PROPERTY_TO_CONSUMING_CLASSES.isActive()) { Scheduler.DUMP_PROPERTY_TO_CONSUMING_CLASSES .println(dumpClass2ConsumingProperty().reduce("", stringJoin("\n\t"))); } // // Create containment regions to traverse all in-use compositions to introduce all consumed classes. // @SuppressWarnings("unused") List<Region> containmentRegions = createContainmentRegions(); // // Create the root containment region to introduce all root and otherwise contained consumed classes. // @SuppressWarnings("unused") RootRegion rootContainmentRegion = createRootContainmentRegion(); // // Grab all the easy single-headed regions as a first pass // // Region firstPassRegion = encapsulateFirstPass(rootContainmentRegion, containmentRegions); // // Bind each head node to the viable introducer/producer of its type. // createBindings(); // for (Map<Set<Node>, Connection> connections : classDatumAnalysis2nodes2connections.values()) { // for (@SuppressWarnings("null")@NonNull Connection connectionRegion : connections.values()) { // addRegion(connectionRegion); // } // } // // Bind each remaining guard node to the viable introducer/producer of its type. // // createNonHeadUsedBindings(); // getSchedulerConstants().writeDOTfile(this, "-4-bindings"); getSchedulerConstants().writeGraphMLfile(this, "-4-bindings"); getSchedulerConstants().writeRegionDOTfile(this, "-4r-bindings"); getSchedulerConstants().writeRegionGraphMLfile(this, "-4r-bindings"); // // Accumulate ordering dependencies at the common region. // Region2Depth region2depth = new Region2Depth(); regionOrderer = new RegionOrdering(region2depth, getRegions()); List<Schedulable> schedulableOrdering = regionOrderer.computeOrdering(); getSchedulerConstants().writeRegionDOTfile(this, "-5r-indexed"); getSchedulerConstants().writeRegionGraphMLfile(this, "-5r-indexed"); getSchedulerConstants().writeCallDOTfile(this, "-5c-indexed"); getSchedulerConstants().writeCallGraphMLfile(this, "-5c-indexed"); // Region2Index region2order = new Region2Index(); // region2order.computeRegionIndexes(getCallableRegions()); // Iterable<Region> sortedCallableRegions = regionOrdering;//AbstractRegion.EarliestRegionComparator.sort(getCallableRegions()); // // Index all predicated and realized edges by typed model and property. // Map<TypedModel, Map<Property, List<NavigationEdge>>> typedModel2property2predicatedEdges = new HashMap<TypedModel, Map<Property, List<NavigationEdge>>>(); Map<TypedModel, Map<Property, List<NavigationEdge>>> typedModel2property2realizedEdges = new HashMap<TypedModel, Map<Property, List<NavigationEdge>>>(); for (@SuppressWarnings("null") @NonNull Schedulable schedulable : schedulableOrdering) { if (schedulable instanceof Region) { Region region = (Region) schedulable; QVTs2QVTiVisitor.POLLED_PROPERTIES.println("building indexes for " + region + " " + region.getEarliestIndex() + ".." + region.getLatestIndex()); region.buildPredicatedNavigationEdgesIndex(typedModel2property2predicatedEdges); region.buildRealizedNavigationEdgesIndex(typedModel2property2realizedEdges); } } for (@SuppressWarnings("null") @NonNull Schedulable schedulable : schedulableOrdering) { if (schedulable instanceof Region) { Region region = (Region) schedulable; region.computeCheckedOrEnforcedEdges(typedModel2property2predicatedEdges, typedModel2property2realizedEdges); } } /* suspended - just an optimization - needs more hierarchical consideration // // Redirect ordered consumers to depend on each other's heads thereby respecting the ordering and // making earlier results available to later mappings. // if (region2orderingEdge2usedEdges != null) { for (@SuppressWarnings("null")@NonNull Region commonRegion : region2orderingEdge2usedEdges.keySet()) { @SuppressWarnings("null")@NonNull Map<Edge, Set<Edge>> orderingEdge2usedEdges = region2orderingEdge2usedEdges.get(commonRegion); convertConsumedOrdering(commonRegion, orderingEdge2usedEdges); } } writeDOTfile("-5-reconsume"); writeGraphMLfile("-5-reconsume"); */ /* suspended - just an optimization - needs more hierarchical consideration // // Merge again now that dependencies may be available. // Region2Depth region2depths = new Region2Depth(); List<Region> sortedRegions = region2depths.getSortedRegions(getRegions()); for (Region calledRegion : sortedRegions) { List<List<Node>> headNodeGroups = calledRegion.getHeadNodeGroups(); if ((headNodeGroups.size() == 1) && !(calledRegion instanceof CompositionRegion)) { Region callingRegion = null; boolean isMergeable = true; for (Node headNode : headNodeGroups.get(0)) { for (Node callingNode : headNode.getPassedBindingSources()) { if (callingRegion == null) { callingRegion = callingNode.getRegion(); } else if (callingRegion != callingNode.getRegion()) { isMergeable = false; break; } } } if ((callingRegion != null) && isMergeable && callingRegion.isLateMergeable(calledRegion, region2depths)) { Map<Node, Node> node2mergedNode = callingRegion.canMerge(calledRegion, region2depths, true); if (node2mergedNode != null) { MergedRegion mergedRegion; if (callingRegion instanceof MergedRegion) { mergedRegion = (MergedRegion)callingRegion; } else { getRegions().remove(calledRegion); mergedRegion = new MergedRegion((MergeableRegion)callingRegion); Region invokingRegion = callingRegion.getInvokingRegion(); assert invokingRegion != null; List<Region> regions = invokingRegion.getRegions(); int index = regions.indexOf(callingRegion); assert index >= 0; regions.set(index, mergedRegion); // mergedRegion.writeDOTfile("-6-merged"); // mergedRegion.writeGraphMLfile("-6-merged"); } mergedRegion.mergeRegion(calledRegion, node2mergedNode); getRegions().remove(calledRegion); mergedRegion.writeDOTfile("-6-merged"); mergedRegion.writeGraphMLfile("-6-merged"); mergedRegion.resolveRecursion(); mergedRegion.writeDOTfile("-7-merged"); mergedRegion.writeGraphMLfile("-7-merged"); region2depths.addRegion(mergedRegion); } } } } */ // // Propagate early results down to later mappings that need them. // /* for (Region calledRegion : sortedRegions) { calledRegion.refineBindings(this); } */ /* HashMap<Node, List<Node>> outerNode2outerNodes = new HashMap<Node, List<Node>>(); Map<Region, Map<NavigationEdge, NavigationEdge>> region2innerEdge2outerEdge = new HashMap<Region, Map<NavigationEdge, NavigationEdge>>(); propagateCommonNavigations(rootContainmentRegion, outerNode2outerNodes, region2innerEdge2outerEdge); for (@SuppressWarnings("null")@NonNull Map.Entry<Region, Map<NavigationEdge, NavigationEdge>> entry1 : region2innerEdge2outerEdge.entrySet()) { Region innerRegion = entry1.getKey(); for (@SuppressWarnings("null")@NonNull NavigationEdge innerEdge : entry1.getValue().keySet()) { Node innerNode = innerEdge.getTarget(); List<NavigationEdge> bestPath = null; for (@SuppressWarnings("null")@NonNull List<Node> headGroup : innerRegion.getHeadNodeGroups()) { for (@SuppressWarnings("null")@NonNull Node headNode : headGroup) { bestPath = getBestPath(bestPath, getPath(headNode, innerNode, new HashSet<Edge>())); } } assert bestPath != null; for (@SuppressWarnings("null")@NonNull Node node : innerRegion.getNodes()) { for (@SuppressWarnings("null")@NonNull Edge edge : node.getIncomingPassedBindingEdges()) { // ??? joins assert edge.getTarget() == node; Region outerRegion = edge.getSource().getRegion(); Map<Edge, Edge> innerEdge2outerEdge = createPath(edge.getSource(), bestPath); for (@SuppressWarnings("null")@NonNull Map.Entry<Edge, Edge> entry : innerEdge2outerEdge.entrySet()) { Edge outerEdge = entry.getValue(); Edge innerEdge2 = entry.getKey(); Edges.USED_BINDING.createEdge(outerRegion, outerEdge.getTarget(), innerEdge2.getName(), innerEdge2.getTarget()); } // innerNode2outerNode.put(node, edge.getSource()); // propagateSharedNodes(edge.getSource(), node, innerNode2outerNode); // propagatePassedEdges(edge.getSource(), node, innerNode2outerNode, innerNode2edge); } } } */ /* Map<Node, Edge> innerNode2edge = new HashMap<Node, Edge>(); Map<Node, Node> innerNode2outerNode = new HashMap<Node, Node>(); // for (NavigationEdge innerEdge : entry1.getValue().keySet()) { // innerNode2edge.put(innerEdge.getSource(), innerEdge); // } for (Node node : innerRegion.getNodes()) { for (Edge edge : node.getIncomingPassedBindingEdges()) { // ??? joins assert edge.getTarget() == node; Node outerNode = createPath(edge.getRegion(), bestEdge); innerNode2outerNode.put(node, edge.getSource()); propagateSharedNodes(edge.getSource(), node, innerNode2outerNode); propagatePassedEdges(edge.getSource(), node, innerNode2outerNode, innerNode2edge); } } for (Map.Entry<NavigationEdge, NavigationEdge> entry2 : entry1.getValue().entrySet()) { NavigationEdge innerEdge = entry2.getKey(); NavigationEdge outerEdge = entry2.getValue(); propagateEdge(outerEdge.getSource(), innerEdge.getSource()); propagateEdge(outerEdge.getTarget(), innerEdge.getTarget()); } */ // } // firstPassRegion.writeDOTfile(); // firstPassRegion.writeGraphMLfile(); } /* private void propagateSharedNodes(@NonNull Node outerSource, @NonNull Node innerSource, @NonNull Map<Node, Node> innerNode2outerNode) { for (NavigationEdge outerEdge : outerSource.getNavigationEdges()) { Node innerTarget = outerSource.getNavigationTarget(outerEdge.getProperty()); if (innerTarget != null) { Node outerTarget = outerEdge.getTarget(); Node oldNode = innerNode2outerNode.put(innerTarget, outerTarget); assert (oldNode == null) || (oldNode == outerTarget); if (oldNode != null) { propagateSharedNodes(outerTarget, innerTarget, innerNode2outerNode); } } } } private void propagatePassedEdges(@NonNull Node outerSource, @NonNull Node innerSource, @NonNull Map<Node, Node> innerNode2outerNode, @NonNull Map<Node, Edge> innerNode2edge) { for (NavigationEdge outerEdge : outerSource.getNavigationEdges()) { Node innerTarget = outerSource.getNavigationTarget(outerEdge.getProperty()); if (innerTarget != null) { Node outerTarget = outerEdge.getTarget(); Node oldNode = innerNode2outerNode.put(innerTarget, outerTarget); assert (oldNode == null) || (oldNode == outerTarget); if (oldNode != null) { propagatePassedEdges(outerTarget, innerTarget, innerNode2outerNode, innerNode2edge); } } } } */ /* private void propagateCommonNavigations(@NonNull Region region, Map<Node, List<Node>> outerNode2outerNodes, @NonNull Map<Region, Map<NavigationEdge, NavigationEdge>> region2innerEdge2outerEdge) { // Map<Node, Set<Node>> node2consumers = new HashMap<Node, Set<Node>>(); for (Node outerNode : region.getNodes()) { for (Edge edge : outerNode.getOutgoingPassedBindingEdges()) { Node innerNode = edge.getTarget(); Iterable<Edge> incomingPassedBindingEdges = innerNode.getIncomingPassedBindingEdges(); if (Iterables.size(incomingPassedBindingEdges) == 1) { // FIXME is passing to multi-called regions viable? Map<Node, List<Node>> innerNode2outerNodes = new HashMap<Node, List<Node>>(); for (Map.Entry<Node, List<Node>> entry : outerNode2outerNodes.entrySet()) { innerNode2outerNodes.put(entry.getKey(), new ArrayList<Node>(entry.getValue())); } assert outerNode == edge.getSource(); List<Node> outerNodes = innerNode2outerNodes.get(innerNode); if (outerNodes == null) { List<Node> outerOuterNodes = outerNode2outerNodes.get(outerNode); outerNodes = outerOuterNodes != null ? new ArrayList<Node>(outerOuterNodes) : new ArrayList<Node>(); innerNode2outerNodes.put(innerNode, outerNodes); } if (!outerNodes.contains(outerNode)) { outerNodes.add(outerNode); } propagateCommonNavigations(innerNode, innerNode2outerNodes, region2innerEdge2outerEdge); propagateCommonNavigations(innerNode.getRegion(), innerNode2outerNodes, region2innerEdge2outerEdge); } } } } */ /** * Recursively propagate the common navigation paths at innerSourceNode to all nodes navigable from * it accumulating equivalent navigations in innerNode2outerNodes. * private void propagateCommonNavigations(@NonNull Node innerSourceNode, @NonNull Map<Node, List<Node>> innerNode2outerNodes, @NonNull Map<Region, Map<NavigationEdge, NavigationEdge>> region2innerEdge2outerEdge) { Region innerRegion = innerSourceNode.getRegion(); Map<NavigationEdge, NavigationEdge> innerEdge2outerEdge = region2innerEdge2outerEdge.get(innerRegion); if (innerEdge2outerEdge == null) { innerEdge2outerEdge = new HashMap<NavigationEdge, NavigationEdge>(); region2innerEdge2outerEdge.put(innerRegion, innerEdge2outerEdge); } List<Node> outerSourceNodes = innerNode2outerNodes.get(innerSourceNode); for (NavigationEdge innerEdge : innerSourceNode.getNavigationEdges()) { Node innerTargetNode = innerEdge.getTarget(); if (innerTargetNode.isClassNode() && !innerEdge.getProperty().isIsMany()) { List<Node> outerTargetNodes = innerNode2outerNodes.get(innerTargetNode); if (outerTargetNodes == null) { outerTargetNodes = new ArrayList<Node>(); innerNode2outerNodes.put(innerTargetNode, outerTargetNodes); for (Node outerSourceNode : outerSourceNodes) { NavigationEdge outerEdge = outerSourceNode.getNavigationEdge(innerEdge.getProperty()); if (outerEdge != null) { Node outerTargetNode = outerEdge.getTarget(); if (!outerTargetNodes.contains(outerTargetNode)) { outerTargetNodes.add(outerTargetNode); List<Node> outerOuterTargetNodes = innerNode2outerNodes.get(outerTargetNode); if (outerOuterTargetNodes != null) { outerTargetNodes.addAll(outerOuterTargetNodes); } // FIXME accumulate an active binding } innerEdge2outerEdge.put(innerEdge, outerEdge); } } if (outerTargetNodes.size() > 0) { } propagateCommonNavigations(innerTargetNode, innerNode2outerNodes, region2innerEdge2outerEdge); } } } } */ public Stream<String> dumpClass2consumingNode() { Stream<String> entries = consumedClassDatumAnalysis2headNodes.keySet().stream().map(k -> { List<Node> list = consumedClassDatumAnalysis2headNodes.get(k); assert list != null; return String.valueOf(k) + " : " + list.stream().map(p -> p.getDisplayName()).sorted().reduce("", stringJoin("\n\t\t")); }); return entries.sorted(); } public Stream<String> dumpClass2ConsumingProperty() { Stream<String> entries = consumedCompositeProperty2introducedClassDatumAnalyses.keySet().stream().map(k -> { Set<ClassDatumAnalysis> set = consumedCompositeProperty2introducedClassDatumAnalyses.get(k); assert set != null; return String.valueOf(k) + " : " + set.stream().map(p -> p.toString()).sorted().reduce("", stringJoin("\n\t\t")); }); return entries.sorted(); } public Stream<String> dumpClass2ContainingProperties() { Stream<String> entries = containedClassDatumAnalysis2compositeProperties.keySet().stream().map(k -> { Set<Property> set = containedClassDatumAnalysis2compositeProperties.get(k); assert set != null; return String.valueOf(k) + " " + k.getClass().getSimpleName() + "@" + Integer.toHexString(System.identityHashCode(k)) + " : " + set.stream().map(p -> String.valueOf(p)).sorted().reduce("", stringJoin("\n\t\t")); }); return entries.sorted(); } public Stream<String> dumpClass2ProducingNode() { Stream<String> entries = producedClassDatumAnalysis2realizedNodes.keySet().stream().map(k -> { List<Node> list = producedClassDatumAnalysis2realizedNodes.get(k); assert list != null; return String.valueOf(k) + " : " + list.stream().map(p -> p.getDisplayName()).sorted().reduce("", stringJoin("\n\t\t")); }); return entries.sorted(); } public Stream<String> dumpInputModels() { Stream<String> entries = inputModels.keySet().stream() .map(k -> String.valueOf(k) + " : " + String.valueOf(inputModels.get(k))); return entries.sorted(); } public @NonNull Iterable<Region> getCallableRegions() { List<Region> callableRegions = new ArrayList<Region>(); for (@SuppressWarnings("null") @NonNull Region region : getRegions()) { if (/*!region.isConnectionRegion() &&*/ !region.isOperationRegion()) { callableRegions.add(region); } } return callableRegions; } public @NonNull Connection getConnection(@NonNull Iterable<Node> sourceNodes, @NonNull ClassDatumAnalysis classDatumAnalysis) { // assert !"EObject".equals(classDatumAnalysis.getCompleteClass().getName()); Map<Set<Node>, Connection> nodes2connection = classDatumAnalysis2nodes2connections.get(classDatumAnalysis); if (nodes2connection == null) { nodes2connection = new HashMap<Set<Node>, Connection>(); classDatumAnalysis2nodes2connections.put(classDatumAnalysis, nodes2connection); } Set<Node> sources = new HashSet<Node>(); for (Node sourceNode : sourceNodes) { sources.add(sourceNode); } Connection connection = nodes2connection.get(sources); if (connection != null) { return connection; } String joinName = "join-" + classDatumAnalysis.getCompleteClass().getName() + "-" + nodes2connection.size() + ""; connection = new BasicConnection(this, sources, joinName); nodes2connection.put(sources, connection); return connection; } // @Override public @NonNull Collection<Connection> getConnections() { return connections; } protected @NonNull ClassDatumAnalysis getElementalClassDatumAnalysis(@NonNull Node calledNode) { ClassDatumAnalysis classDatumAnalysis = calledNode.getClassDatumAnalysis(); CompleteClass completeClass = classDatumAnalysis.getCompleteClass(); org.eclipse.ocl.pivot.Class primaryClass = completeClass.getPrimaryClass(); if (primaryClass instanceof CollectionType) { org.eclipse.ocl.pivot.Class elementType = (org.eclipse.ocl.pivot.Class) ((CollectionType) primaryClass) .getElementType(); assert elementType != null; classDatumAnalysis = getSchedulerConstants().getClassDatumAnalysis(elementType, classDatumAnalysis.getTypedModel()); } return classDatumAnalysis; } protected @Nullable List<Node> getIntroducingNodes(@NonNull ClassDatumAnalysis classDatumAnalysis) { /* List<Node> introducingNodes = null; CompleteClass completeClass = classDatumAnalysis.getCompleteClass(); for (ClassDatumAnalysis aClassDatumAnalysis : introducedClassDatumAnalysis2nodes.keySet()) { // FIXME cache if (completeClass.conformsTo(aClassDatumAnalysis.getCompleteClass())) { if (introducingNodes == null) { introducingNodes = new ArrayList<Node>(); } introducingNodes.addAll(introducedClassDatumAnalysis2nodes.get(aClassDatumAnalysis)); } } */ return introducedClassDatumAnalysis2nodes.get(classDatumAnalysis); // Separate introduction of each consumed type } /* public @NonNull List<ConnectionRegion> getConnectionRegions(@NonNull Region toRegion) { List<ConnectionRegion> joinRegions = new ArrayList<ConnectionRegion>(); for (Connection edge : toRegion.getParentPassedConnections()) { Node sourceNode = edge.getSource(); ConnectionRegion joinRegion; Region sourceRegion = sourceNode.getRegion(); if (sourceRegion.isConnectionRegion()) { joinRegion = (ConnectionRegion) sourceRegion; } else { ClassDatumAnalysis classDatumAnalysis = sourceNode.getClassDatumAnalysis(); String joinName = "-join-" + classDatumAnalysis.getCompleteClass().getName() + "-" + toRegion.getName(); joinRegion = new ConnectionRegion(getSuperRegion(), joinName, classDatumAnalysis); Node joinNode = joinRegion.getConnectionNode(); Connections.PASSED_BINDING.createConnection(this, sourceNode, null, joinNode); Connections.PASSED_BINDING.createConnection(this, joinNode, null, edge.getTarget()); } joinRegions.add(joinRegion); addRegion(joinRegion); } return joinRegions; } */ @Override public @NonNull String getName() { return name; } protected @Nullable List<Node> getProducingNodes(@NonNull ClassDatumAnalysis classDatumAnalysis) { /* List<Node> producingNodes = null; CompleteClass completeClass = classDatumAnalysis.getCompleteClass(); for (ClassDatumAnalysis aClassDatumAnalysis : producedClassDatumAnalysis2realizedNodes.keySet()) { // FIXME cache if (completeClass.conformsTo(aClassDatumAnalysis.getCompleteClass())) { if (producingNodes == null) { producingNodes = new ArrayList<Node>(); } producingNodes.addAll(producedClassDatumAnalysis2realizedNodes.get(aClassDatumAnalysis)); } } */ return producedClassDatumAnalysis2realizedNodes.get(classDatumAnalysis); } protected @Nullable PropertyDatum getPropertyDatum(@NonNull NavigationEdge producedEdge) { assert !producedEdge.isCast(); // Handled by caller Property property = producedEdge.getProperty(); ClassDatumAnalysis classDatumAnalysis = producedEdge.getSource().getClassDatumAnalysis(); ClassDatum classDatum = classDatumAnalysis.getClassDatum(); for (PropertyDatum propertyDatum : classDatum.getPropertyDatums()) { if (propertyDatum.getProperty() == property) { return propertyDatum; } } property = property.getOpposite(); classDatumAnalysis = producedEdge.getTarget().getClassDatumAnalysis(); classDatum = classDatumAnalysis.getClassDatum(); for (PropertyDatum propertyDatum : classDatum.getPropertyDatums()) { if (propertyDatum.getProperty() == property) { return propertyDatum; } } return null; } public @NonNull RegionOrdering getRegionOrderer() { assert regionOrderer != null; return regionOrderer; } // @Override public @NonNull List<Region> getRegions() { return regions; } /* private @NonNull Node zzgetSourceOrConnectionNode(@NonNull Collection<Node> sourceNodes, @NonNull ClassDatumAnalysis classDatumAnalysis) { if (sourceNodes.size() <= 1) { @SuppressWarnings("null")@NonNull Node sourceNode = sourceNodes.iterator().next(); return sourceNode; } Map<Set<Node>, Connection> joins = classDatumAnalysis2nodes2connections.get(classDatumAnalysis); if (joins == null) { joins = new HashMap<Set<Node>, Connection>(); classDatumAnalysis2nodes2connections.put(classDatumAnalysis, joins); } Set<Node> sources = new HashSet<Node>(sourceNodes); Connection joinRegion = joins.get(sources); if (joinRegion != null) { return joinRegion.getConnectionNode(); } String joinName = "-join-" + classDatumAnalysis.getCompleteClass().getName() + "-" + joins.size(); joinRegion = new ConnectionRegion(getSuperRegion(), joinName, classDatumAnalysis); joins.put(sources, joinRegion); Node joinNode = joinRegion.getConnectionNode(); for (Node sourceNode : sourceNodes) { assert sourceNode != null; Connections.PASSED_BINDING.createConnection(this, sourceNode, null, joinNode); } return joinNode; } */ /* private final @NonNull Iterable<Edge> getUsedBindingEdges() { @SuppressWarnings("null") @NonNull Iterable<Edge> filter = Iterables.filter(getEdges(), IsUsedBindingEdgePredicate.INSTANCE); return filter; } */ /** * Return true if this node is consumed solely by casts (or recursions) and so need not be considered as a true consumer. * The downstream usages will consume more accurately. */ protected boolean isOnlyCastOrRecursed(@NonNull Node predicatedNode) { boolean isCast = false; for (Edge outgoingEdge : predicatedNode.getOutgoingEdges()) { if (!outgoingEdge.isCast() && !outgoingEdge.isRecursion()) { return false; } isCast = true; } return isCast; } @Override public boolean isLateMergeable(@NonNull Region innerRegion, @NonNull Region2Depth region2depths) { return false; } // @Override public void removeConnection(@NonNull Connection connection) { boolean wasRemoved = connections.remove(connection); assert wasRemoved; } private @NonNull Node selectBestHeadNode(@NonNull List<Node> headNodes) { return ClassUtil.nonNullState(headNodes.get(0)); // FIXME compute best navigability } // @Override public void toCallGraph(@NonNull GraphStringBuilder s) { s.setLabel(getName()); s.pushCluster(); for (@SuppressWarnings("null") @NonNull Region region : getCallableRegions()) { s.appendNode(region); for (@SuppressWarnings("null") @NonNull Edge edge : region.getRecursionEdges()) { s.appendEdge(edge.getSource().getRegion(), edge, edge.getTarget().getRegion()); } } // for (@SuppressWarnings("null")@NonNull Node node : getNodes()) { // s.appendNode(node); // } for (@SuppressWarnings("null") @NonNull Connection connection : getConnections()) { connection.toRegionGraph(s); } s.popCluster(); } @Override public void toGraph(@NonNull GraphStringBuilder s) { s.setLabel(getName()); s.pushCluster(); for (Region region : regions) { region.toGraph(s); } for (@SuppressWarnings("null") @NonNull Node node : getNodes()) { s.appendNode(node); } for (@SuppressWarnings("null") @NonNull Edge edge : getEdges()) { s.appendEdge(edge); } for (@SuppressWarnings("null") @NonNull Connection connection : getConnections()) { connection.toGraph(s); } s.popCluster(); } // @Override public void toRegionGraph(@NonNull GraphStringBuilder s) { s.setLabel(getName()); s.pushCluster(); for (@SuppressWarnings("null") @NonNull Region region : getCallableRegions()) { s.appendNode(region); for (@SuppressWarnings("null") @NonNull Edge edge : region.getRecursionEdges()) { s.appendEdge(edge.getSource().getRegion(), edge, edge.getTarget().getRegion()); } } // for (@SuppressWarnings("null")@NonNull Node node : getNodes()) { // s.appendNode(node); // } for (@SuppressWarnings("null") @NonNull Connection connection : getConnections()) { connection.toRegionGraph(s); } s.popCluster(); } }