| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.internal.sessions; |
| |
| import java.util.*; |
| import org.eclipse.persistence.descriptors.InheritancePolicy; |
| import org.eclipse.persistence.mappings.*; |
| import org.eclipse.persistence.internal.helper.*; |
| import org.eclipse.persistence.internal.localization.*; |
| import org.eclipse.persistence.descriptors.ClassDescriptor; |
| |
| /** |
| * This wraps a descriptor with information required to compute an order for |
| * dependencies. The algorithm is a simple topological sort. |
| */ |
| public class CommitOrderDependencyNode { |
| protected CommitOrderCalculator owner; |
| protected ClassDescriptor descriptor; |
| protected AbstractSession session; |
| |
| // These are the descriptors to which we have 1:1 relationships |
| protected Vector relatedNodes; |
| protected CommitOrderDependencyNode predecessor; |
| |
| // Indicates the state of the traversal |
| protected int traversalState; |
| static public int NotVisited = 1; |
| static public int InProgress = 2; |
| static public int Visited = 3; |
| |
| // When we first saw this node in the traversal |
| protected int discoveryTime; |
| |
| // When we finished visiting this node |
| protected int finishingTime; |
| |
| public CommitOrderDependencyNode(CommitOrderCalculator calculator, ClassDescriptor descriptor, AbstractSession session) { |
| this.owner = calculator; |
| this.descriptor = descriptor; |
| this.relatedNodes = new Vector(); |
| this.session = session; |
| } |
| |
| public ClassDescriptor getDescriptor() { |
| return descriptor; |
| } |
| |
| public int getFinishingTime() { |
| return finishingTime; |
| } |
| |
| public CommitOrderCalculator getOwner() { |
| return owner; |
| } |
| |
| public CommitOrderDependencyNode getPredecessor() { |
| return predecessor; |
| } |
| |
| public Vector getRelatedNodes() { |
| return relatedNodes; |
| } |
| |
| public boolean hasBeenVisited() { |
| return (traversalState == Visited); |
| } |
| |
| public boolean hasNotBeenVisited() { |
| return (traversalState == NotVisited); |
| } |
| |
| public void markInProgress() { |
| traversalState = InProgress; |
| } |
| |
| public void markNotVisited() { |
| traversalState = NotVisited; |
| } |
| |
| public void markVisited() { |
| traversalState = Visited; |
| } |
| |
| /** |
| * Add all owned classes for each descriptor through checking the mappings. |
| * If I have a foreign mapping with a constraint dependency, then add it |
| * If I'm related to a class, I'm related to all its subclasses and superclasses. |
| * If my superclass is related to a class, I'm related to it. |
| */ |
| public void recordMappingDependencies() { |
| for (Enumeration<DatabaseMapping> mappings = getDescriptor().getMappings().elements(); |
| mappings.hasMoreElements();) { |
| DatabaseMapping mapping = mappings.nextElement(); |
| if (mapping.isForeignReferenceMapping()) { |
| if (mapping.hasConstraintDependency()) { |
| Class<?> ownedClass; |
| ClassDescriptor refDescriptor = mapping.getReferenceDescriptor(); |
| if (refDescriptor == null) { |
| refDescriptor = session.getDescriptor(((ForeignReferenceMapping)mapping).getReferenceClass()); |
| } |
| ownedClass = refDescriptor.getJavaClass(); |
| |
| if (ownedClass == null) { |
| throw org.eclipse.persistence.exceptions.DescriptorException.referenceClassNotSpecified(mapping); |
| } |
| CommitOrderDependencyNode node = getOwner().nodeFor(ownedClass); |
| Vector ownedNodes = withAllSubclasses(node); |
| |
| // I could remove duplicates here, but it's not that big a deal. |
| Helper.addAllToVector(relatedNodes, ownedNodes); |
| } else if (mapping.hasInverseConstraintDependency()) { |
| Class<?> ownerClass; |
| ClassDescriptor refDescriptor = mapping.getReferenceDescriptor(); |
| if (refDescriptor == null) { |
| refDescriptor = session.getDescriptor(((ForeignReferenceMapping)mapping).getReferenceClass()); |
| } |
| ownerClass = refDescriptor.getJavaClass(); |
| if (ownerClass == null) { |
| throw org.eclipse.persistence.exceptions.DescriptorException.referenceClassNotSpecified(mapping); |
| } |
| CommitOrderDependencyNode ownerNode = getOwner().nodeFor(ownerClass); |
| Vector ownedNodes = withAllSubclasses(this); |
| |
| // I could remove duplicates here, but it's not that big a deal. |
| Helper.addAllToVector(ownerNode.getRelatedNodes(), ownedNodes); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Add all owned classes for each descriptor through checking the mappings. |
| * If I have a foreign mapping with a constraint dependency, then add it |
| * If I'm related to a class, I'm related to all its subclasses and superclasses. |
| * If my superclass is related to a class, I'm related to it. |
| */ |
| public void recordSpecifiedDependencies() { |
| for (Enumeration constraintsEnum = getDescriptor().getConstraintDependencies().elements(); |
| constraintsEnum.hasMoreElements();) { |
| Class<?> ownedClass = (Class)constraintsEnum.nextElement(); |
| CommitOrderDependencyNode node = getOwner().nodeFor(ownedClass); |
| Vector ownedNodes = withAllSubclasses(node); |
| |
| // I could remove duplicates here, but it's not that big a deal. |
| Helper.addAllToVector(relatedNodes, ownedNodes); |
| } |
| } |
| |
| public void setDiscoveryTime(int time) { |
| discoveryTime = time; |
| } |
| |
| public void setFinishingTime(int time) { |
| finishingTime = time; |
| } |
| |
| public void setPredecessor(CommitOrderDependencyNode n) { |
| predecessor = n; |
| } |
| |
| @Override |
| public String toString() { |
| if (descriptor == null) { |
| return ToStringLocalization.buildMessage("empty_commit_order_dependency_node", null); |
| } else { |
| Object[] args = { descriptor }; |
| return ToStringLocalization.buildMessage("node", args); |
| } |
| } |
| |
| public void visit() { |
| //Visit this node as part of a topological sort |
| int startTime; |
| markInProgress(); |
| startTime = getOwner().getNextTime(); |
| setDiscoveryTime(startTime); |
| |
| for (Enumeration e = getRelatedNodes().elements(); e.hasMoreElements();) { |
| CommitOrderDependencyNode node = (CommitOrderDependencyNode)e.nextElement(); |
| if (node.hasNotBeenVisited()) { |
| node.setPredecessor(this); |
| node.visit(); |
| } |
| if (node.getPredecessor() == null) { |
| node.setPredecessor(this); |
| } |
| } |
| |
| markVisited(); |
| setFinishingTime(getOwner().getNextTime()); |
| } |
| |
| // Return an enumeration of all mappings for my descriptor, including those inherited |
| public Vector withAllSubclasses(CommitOrderDependencyNode node) { |
| Vector results = new Vector(); |
| results.addElement(node); |
| |
| if (node.getDescriptor().hasInheritance()) { |
| InheritancePolicy policy = node.getDescriptor().getInheritancePolicy(); |
| |
| // For bug 3019934 replace getChildDescriptors with getAllChildDescriptors. |
| List<ClassDescriptor> childDescriptors = new ArrayList<>(); |
| childDescriptors.addAll(policy.getAllChildDescriptors()); |
| |
| // Sort Child Descriptors before adding them to related nodes. |
| Collections.sort(childDescriptors, new DescriptorCompare()); |
| |
| for (ClassDescriptor child : childDescriptors) { |
| results.add(getOwner().nodeFor(child)); |
| } |
| } |
| return results; |
| } |
| } |