blob: d479901284a318a6faba9bedd42b2ba43e737aca [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1998, 2012 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.db.model.handles;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.persistence.tools.db.model.ELNode;
import org.eclipse.persistence.tools.utility.iterator.EmptyIterator;
import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
import org.eclipse.persistence.tools.utility.model.listener.CollectionChangeListener;
import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
import org.eclipse.persistence.tools.utility.node.Node;
import org.eclipse.persistence.tools.utility.node.Problem;
/**
* Handles are used to isolate the painful bits of code
* necessary to correctly handle references to model objects.
*
* All handles should subclass this abstract class.
*
* @version 2.6
*/
@SuppressWarnings("nls")
public abstract class MWHandle implements ELNode {
/** Containment hierarchy. */
private ELNode parent; // pseudo-final
/** This is used to synchronize the model when a node is removed. */
private NodeReferenceScrubber scrubber; // pseudo-final
/** A handle is dirty when the path to its node changes. */
private volatile boolean dirty;
// ********** constructors **********
/**
* default constructor - for TopLink use only
*/
protected MWHandle() {
super();
// a new object is dirty, by definition
this.dirty = true;
}
protected MWHandle(ELNode parent, NodeReferenceScrubber scrubber) {
this();
this.setParent(parent);
this.setScrubberInternal(scrubber);
}
// ********** containment hierarchy (parent/children) **********
@Override
public final Node getParent() {
return this.parent;
}
/**
* Set the object's parent in the containment hierarchy.
* Most objects must have a parent.
*/
public final void setParent(Node parent) {
if (parent == null) {
throw new NullPointerException();
}
this.parent = (ELNode) parent;
}
// handles do not have children
@Override
public final Iterator<Node> children() {
return EmptyIterator.instance();
}
// handles do not have children
public final void setChildBackpointers() {
// do nothing
}
@Override
public final boolean isDescendantOf(Node node) {
return (this == node) || this.parent.isDescendantOf(node);
}
@Override
public final void addBranchReferencesTo(Collection branchReferences) {
Node node = this.node();
if (node != null) {
branchReferences.add(new SimpleReference(this, node));
}
}
// handles do not have children
@Override
public final void addAllNodesTo(Collection nodes) {
nodes.add(this);
}
// ********** dirty flag support **********
@Override
public final boolean isDirtyBranch() {
return this.dirty;
}
@Override
public final void markBranchDirty() {
throw new IllegalStateException("handles shouldn't have children");
}
@Override
public final void markEntireBranchDirty() {
this.markDirty();
}
@Override
public final void cascadeMarkEntireBranchClean() {
this.dirty = false;
}
@Override
public final void markBranchCleanIfPossible() {
throw new IllegalStateException("handles shouldn't have children");
}
private void markDirty() {
this.dirty = true;
this.parent.markBranchDirty();
}
// ********** convenience methods **********
@Override
public final ELNode getMWParent() {
return this.parent;
}
// ********** model synchronization support **********
/**
* Returns the node referenced by the handle.
*/
protected abstract Node node();
/**
* If the handle's node has been renamed, or it is a descendant of
* a node that has been renamed, the handle must mark its branch
* dirty so that the handle is saved with the new name.
*/
@Override
public void nodeRenamed(Node node) {
if ((this.node() != null) && this.node().isDescendantOf(node)) {
this.markDirty();
}
}
/**
* If the handle's node has been removed, or it is a descendant of
* a node that has been removed, notify the scrubber.
*/
@Override
public final void nodeRemoved(Node removedNode) {
if ((this.node() != null) && this.node().isDescendantOf(removedNode)) {
this.scrubber.nodeReferenceRemoved(this.node(), this);
}
}
/**
* Subclasses will probably implement something like
* #setScrubber(NodeReferenceScrubber) that returns 'this'
*/
protected final void setScrubberInternal(NodeReferenceScrubber scrubber) {
if (scrubber == null) {
throw new NullPointerException();
}
this.scrubber = scrubber;
}
// ********** post-read methods **********
/**
* Override this method if there are objects in the hierarchy
* that depend on this handle being resolved before postProjectBuild().
* Do not override unless the handle is for a class or class sub-object
* (attribute, method, etc.)
*/
public void resolveClassHandles() {
// do nothing
}
/**
* Override this method if there are objects in the hierarchy
* that depend on this handle being resolved before postProjectBuild().
* Do not override unless the handle is for a descriptor or descriptor sub-object
* (mapping, xml data field, etc.)
*/
public void resolveDescriptorHandles() {
// do nothing
}
/**
* Override this method if there are objects in the hierarchy
* that depend on this handle being resolved before postProjectBuild().
* Do not override unless the handle is for a meta data object or sub-object
* (field, schema component, etc.)
*/
public void resolveMetadataHandles() {
// do nothing
}
/**
* Override this method if there are objects in the hierarchy
* that depend on this handle being resolved before postProjectBuild().
* Do not override unless the handle is for a meta data object or sub-object
* (column, schema component, etc.)
*/
public void resolveColumnHandles() {
// do nothing
}
/**
* Override this method if there are objects in the hierarchy
* that depend on this handle being resolved before postProjectBuild().
* Do not override unless the handle is for a meta data object or sub-object
* (field, schema component, etc.)
*/
public void resolveReferenceHandles() {
// do nothing
}
/**
* Override this method if there are objects in the hierarchy
* that depend on this handle being resolved before postProjectBuild().
* Do not override unless the handle is for a meta data object or sub-object
* (field, schema component, etc.)
*/
public void resolveMethodHandles() {
// do nothing
}
public void postProjectBuild() {
if (this.scrubber == null) {
throw new NullPointerException("This handle's 'scrubber' should have been set by its parent upon creation.");
}
}
// ********** display methods **********
/**
* handles are not displayed
*/
@Override
public final String displayString() {
throw new UnsupportedOperationException();
}
// ********** standard methods **********
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(" (");
this.toString(sb);
sb.append(')');
return sb.toString();
}
public abstract void toString(StringBuffer sb);
// ************ Abstract, unused behavior *************
@Override
public Node root() {
return null;
}
@Override
public Validator getValidator() {
return null;
}
@Override
public void setValidator(Validator validator) {
}
@Override
public void validateBranch() {
}
@Override
public boolean validateBranchInternal() {
return false;
}
@Override
public ListIterator<Problem> branchProblems() {
return null;
}
@Override
public int branchProblemsSize() {
return 0;
}
@Override
public boolean hasBranchProblems() {
return false;
}
@Override
public boolean containsBranchProblem(Problem problem) {
return false;
}
@Override
public void rebuildBranchProblems() {
}
@Override
public void addBranchProblemsTo(List<Problem> branchProblems) {
}
@Override
public void clearAllBranchProblems() {
}
@Override
public boolean clearAllBranchProblemsInternal() {
return false;
}
@Override
public String comment() {
return null;
}
@Override
public void setComment(String comment) {
}
@Override
public void addChangeListener(ChangeListener listener) {
}
@Override
public void removeChangeListener(ChangeListener listener) {
}
@Override
public void addStateChangeListener(StateChangeListener listener) {
}
@Override
public void removeStateChangeListener(StateChangeListener listener) {
}
@Override
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
}
@Override
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
}
@Override
public void addCollectionChangeListener(String collectionName,
CollectionChangeListener listener) {
}
@Override
public void removeCollectionChangeListener(String collectionName,
CollectionChangeListener listener) {
}
@Override
public void addListChangeListener(String listName,
ListChangeListener listener) {
}
@Override
public void removeListChangeListener(String listName,
ListChangeListener listener) {
}
// ********** member interface **********
/**
* This interface defines the method called by a handle when the node the
* handle references has been removed from the project. Typically the
* handle's parent will implement an adapter that will call the appropriate
* method to either remove or clear the handle. The handle itself will
* continue to hold the reference node - it is up to the parent to
* synchronize appropriately.
*/
public interface NodeReferenceScrubber {
/**
* The specified node is no longer referenced by the specified handle.
*/
void nodeReferenceRemoved(Node node, MWHandle handle);
NodeReferenceScrubber NULL_INSTANCE = new NodeReferenceScrubber() {
@Override
public void nodeReferenceRemoved(Node node, MWHandle handle) {
// do nothing
}
@Override
public String toString() {
return "NullReferenceScrubber";
}
};
}
}