diff --git a/core/src/org/sbml/jsbml/ASTNode.java b/core/src/org/sbml/jsbml/ASTNode.java index e1f966ad4..dbe9f162f 100644 --- a/core/src/org/sbml/jsbml/ASTNode.java +++ b/core/src/org/sbml/jsbml/ASTNode.java @@ -5056,4 +5056,15 @@ public void canonicalize() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/AbstractSBase.java b/core/src/org/sbml/jsbml/AbstractSBase.java index 5f070d223..988b75b0f 100644 --- a/core/src/org/sbml/jsbml/AbstractSBase.java +++ b/core/src/org/sbml/jsbml/AbstractSBase.java @@ -3492,4 +3492,16 @@ public String toSBML() { } } -} + /** + * Accepts a generic visitor to traverse this SBase component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + @Override + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/Annotation.java b/core/src/org/sbml/jsbml/Annotation.java index 821eb8b6b..c55e7e566 100644 --- a/core/src/org/sbml/jsbml/Annotation.java +++ b/core/src/org/sbml/jsbml/Annotation.java @@ -940,4 +940,15 @@ public void unsetNonRDFannotation() { } } -} + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/CVTerm.java b/core/src/org/sbml/jsbml/CVTerm.java index bbaa1ff8e..93a80db91 100644 --- a/core/src/org/sbml/jsbml/CVTerm.java +++ b/core/src/org/sbml/jsbml/CVTerm.java @@ -28,6 +28,7 @@ import javax.swing.tree.TreeNode; import javax.xml.stream.XMLStreamException; +import org.sbml.jsbml.CVTerm.Qualifier; import org.sbml.jsbml.util.StringTools; import org.sbml.jsbml.util.TreeNodeAdapter; import org.sbml.jsbml.util.TreeNodeChangeEvent; @@ -1405,4 +1406,15 @@ public void setUnknownQualifierName(String unknownQualifierName) { this.unknownQualifierName = unknownQualifierName; } -} + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/Creator.java b/core/src/org/sbml/jsbml/Creator.java index 6641fe760..675832313 100644 --- a/core/src/org/sbml/jsbml/Creator.java +++ b/core/src/org/sbml/jsbml/Creator.java @@ -550,4 +550,15 @@ public void unsetOrganization() { firePropertyChange(TreeNodeChangeEvent.organization, oldValue, organisation); } -} + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/History.java b/core/src/org/sbml/jsbml/History.java index cf461eb7b..14ddcdc03 100644 --- a/core/src/org/sbml/jsbml/History.java +++ b/core/src/org/sbml/jsbml/History.java @@ -506,4 +506,16 @@ public String toString() { } return result.toString(); } -} + + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/TreeNodeVisitor.java b/core/src/org/sbml/jsbml/TreeNodeVisitor.java new file mode 100644 index 000000000..cfdebd284 --- /dev/null +++ b/core/src/org/sbml/jsbml/TreeNodeVisitor.java @@ -0,0 +1,32 @@ +package org.sbml.jsbml; + +import org.sbml.jsbml.util.TreeNodeWithChangeSupport; + +/** + * A generic visitor interface for traversing the JSBML tree structure. + * This allows external classes to operate on SBML components without + * modifying the core classes. + * + * @param The return type of the visitor operations. Note that this generic + * type may also be {@link Void} if nothing is to be returned. + * @author Deepak Yadav + */ +public interface TreeNodeVisitor { + + /** + * Primary traversal method for core SBML components. + * + * @param sbase the core SBML element to visit + * @return a result of type T + */ + T visit(SBase sbase); + + /** + * Fallback traversal method for auxiliary nodes (e.g., annotations, notes) + * that do not inherit from SBase but do inherit from TreeNodeWithChangeSupport. + * + * @param node the tree node to visit + * @return a result of type T + */ + T visit(TreeNodeWithChangeSupport node); +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/ext/AbstractASTNodePlugin.java b/core/src/org/sbml/jsbml/ext/AbstractASTNodePlugin.java index 62c88c6f2..b1db4c17b 100644 --- a/core/src/org/sbml/jsbml/ext/AbstractASTNodePlugin.java +++ b/core/src/org/sbml/jsbml/ext/AbstractASTNodePlugin.java @@ -31,6 +31,7 @@ import org.sbml.jsbml.AbstractTreeNode; import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.SBase; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.util.TreeNodeChangeEvent; /** @@ -355,4 +356,16 @@ public Map writeXMLAttributes() { return new TreeMap(); } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + @Override + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/ext/AbstractSBasePlugin.java b/core/src/org/sbml/jsbml/ext/AbstractSBasePlugin.java index f519da627..fdd9aa165 100644 --- a/core/src/org/sbml/jsbml/ext/AbstractSBasePlugin.java +++ b/core/src/org/sbml/jsbml/ext/AbstractSBasePlugin.java @@ -30,6 +30,7 @@ import org.sbml.jsbml.AbstractTreeNode; import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.SBase; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.util.TreeNodeChangeEvent; /** @@ -327,4 +328,16 @@ public Map writeXMLAttributes() { return new TreeMap(); } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + @Override + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTBoolean.java b/core/src/org/sbml/jsbml/math/ASTBoolean.java index fa74e205e..f0596ee8b 100644 --- a/core/src/org/sbml/jsbml/math/ASTBoolean.java +++ b/core/src/org/sbml/jsbml/math/ASTBoolean.java @@ -24,6 +24,7 @@ import org.sbml.jsbml.ASTNode.Type; import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.math.compiler.FormulaCompiler; @@ -197,4 +198,15 @@ public String toMathML() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTCSymbolAvogadroNode.java b/core/src/org/sbml/jsbml/math/ASTCSymbolAvogadroNode.java index 341f146cd..160266998 100644 --- a/core/src/org/sbml/jsbml/math/ASTCSymbolAvogadroNode.java +++ b/core/src/org/sbml/jsbml/math/ASTCSymbolAvogadroNode.java @@ -24,6 +24,7 @@ import org.sbml.jsbml.ASTNode; import org.sbml.jsbml.ASTNode.Type; import org.sbml.jsbml.PropertyUndefinedError; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.util.Maths; @@ -316,4 +317,15 @@ public void setName(String name) { firePropertyChange(TreeNodeChangeEvent.name, old, this.name); } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTCSymbolDelayNode.java b/core/src/org/sbml/jsbml/math/ASTCSymbolDelayNode.java index 8bb4d90d3..a8a1ad486 100644 --- a/core/src/org/sbml/jsbml/math/ASTCSymbolDelayNode.java +++ b/core/src/org/sbml/jsbml/math/ASTCSymbolDelayNode.java @@ -25,6 +25,7 @@ import org.sbml.jsbml.ASTNode.Type; import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.math.compiler.FormulaCompiler; @@ -289,4 +290,15 @@ public String toMathML() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTCSymbolTimeNode.java b/core/src/org/sbml/jsbml/math/ASTCSymbolTimeNode.java index 20745646b..75f095f77 100644 --- a/core/src/org/sbml/jsbml/math/ASTCSymbolTimeNode.java +++ b/core/src/org/sbml/jsbml/math/ASTCSymbolTimeNode.java @@ -25,6 +25,7 @@ import org.sbml.jsbml.ASTNode.Type; import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.math.compiler.FormulaCompiler; @@ -313,4 +314,15 @@ public String toMathML() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTCiFunctionNode.java b/core/src/org/sbml/jsbml/math/ASTCiFunctionNode.java index e3244463b..1d8291da5 100644 --- a/core/src/org/sbml/jsbml/math/ASTCiFunctionNode.java +++ b/core/src/org/sbml/jsbml/math/ASTCiFunctionNode.java @@ -28,6 +28,7 @@ import org.sbml.jsbml.Model; import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.math.compiler.FormulaCompiler; @@ -367,4 +368,15 @@ public String toMathML() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTCiNumberNode.java b/core/src/org/sbml/jsbml/math/ASTCiNumberNode.java index a31815aac..e6ce4384b 100644 --- a/core/src/org/sbml/jsbml/math/ASTCiNumberNode.java +++ b/core/src/org/sbml/jsbml/math/ASTCiNumberNode.java @@ -31,6 +31,7 @@ import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.QuantityWithUnit; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.math.compiler.FormulaCompiler; @@ -383,4 +384,15 @@ public String toMathML() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTCnNumberNode.java b/core/src/org/sbml/jsbml/math/ASTCnNumberNode.java index 2c355842a..d5abddd3e 100644 --- a/core/src/org/sbml/jsbml/math/ASTCnNumberNode.java +++ b/core/src/org/sbml/jsbml/math/ASTCnNumberNode.java @@ -26,6 +26,7 @@ import org.sbml.jsbml.Model; import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.Unit; import org.sbml.jsbml.UnitDefinition; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; @@ -388,4 +389,15 @@ public void unsetUnits() { firePropertyChange(TreeNodeChangeEvent.units, oldValue, null); } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTConstantNumber.java b/core/src/org/sbml/jsbml/math/ASTConstantNumber.java index b1e2b10f1..f017c2416 100644 --- a/core/src/org/sbml/jsbml/math/ASTConstantNumber.java +++ b/core/src/org/sbml/jsbml/math/ASTConstantNumber.java @@ -24,6 +24,7 @@ import org.sbml.jsbml.ASTNode.Type; import org.sbml.jsbml.PropertyUndefinedError; import org.sbml.jsbml.SBMLException; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.math.compiler.FormulaCompiler; @@ -219,4 +220,15 @@ public String toMathML() { } } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTFunction.java b/core/src/org/sbml/jsbml/math/ASTFunction.java index 748da5730..9b4e03619 100644 --- a/core/src/org/sbml/jsbml/math/ASTFunction.java +++ b/core/src/org/sbml/jsbml/math/ASTFunction.java @@ -28,6 +28,7 @@ import org.sbml.jsbml.CallableSBase; import org.sbml.jsbml.MathContainer; import org.sbml.jsbml.PropertyUndefinedError; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.util.TreeNodeChangeEvent; @@ -519,4 +520,15 @@ public void swapChildren(ASTFunction that) { listOfNodes = swap; } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/math/ASTUnknown.java b/core/src/org/sbml/jsbml/math/ASTUnknown.java index 6425b7bf2..9a205c809 100644 --- a/core/src/org/sbml/jsbml/math/ASTUnknown.java +++ b/core/src/org/sbml/jsbml/math/ASTUnknown.java @@ -29,6 +29,7 @@ import org.sbml.jsbml.ASTNode.Type; import org.sbml.jsbml.MathContainer; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.math.compiler.ASTNode2Compiler; import org.sbml.jsbml.math.compiler.ASTNode2Value; import org.sbml.jsbml.util.TreeNodeChangeListener; @@ -620,4 +621,15 @@ public boolean addAllChangeListeners( return false; } + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + } diff --git a/core/src/org/sbml/jsbml/util/TreeNodeAdapter.java b/core/src/org/sbml/jsbml/util/TreeNodeAdapter.java index 9df0fd805..121647d88 100644 --- a/core/src/org/sbml/jsbml/util/TreeNodeAdapter.java +++ b/core/src/org/sbml/jsbml/util/TreeNodeAdapter.java @@ -32,6 +32,7 @@ import org.sbml.jsbml.AbstractTreeNode; import org.sbml.jsbml.ListOf; +import org.sbml.jsbml.TreeNodeVisitor; /** *

@@ -296,4 +297,15 @@ public String toString() { return super.toString(); } -} + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/util/TreeNodeWithChangeSupport.java b/core/src/org/sbml/jsbml/util/TreeNodeWithChangeSupport.java index 5bb6c6991..039d96baa 100644 --- a/core/src/org/sbml/jsbml/util/TreeNodeWithChangeSupport.java +++ b/core/src/org/sbml/jsbml/util/TreeNodeWithChangeSupport.java @@ -28,6 +28,7 @@ import javax.swing.tree.TreeNode; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.util.filters.Filter; /** @@ -321,4 +322,13 @@ public void firePropertyChange(String propertyName, Object oldValue, public boolean addAllChangeListeners( Collection listeners, boolean recursive); -} + /** + * Accepts a generic visitor to traverse this node. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor); + +} \ No newline at end of file diff --git a/core/src/org/sbml/jsbml/xml/XMLNode.java b/core/src/org/sbml/jsbml/xml/XMLNode.java index dc29d3575..bcec7bf92 100644 --- a/core/src/org/sbml/jsbml/xml/XMLNode.java +++ b/core/src/org/sbml/jsbml/xml/XMLNode.java @@ -28,6 +28,7 @@ import javax.xml.stream.XMLStreamException; import org.sbml.jsbml.JSBML; +import org.sbml.jsbml.TreeNodeVisitor; import org.sbml.jsbml.xml.parsers.SBMLRDFAnnotationParser; import org.sbml.jsbml.xml.parsers.XMLNodeWriter; import org.sbml.jsbml.xml.stax.SBMLReader; @@ -768,4 +769,15 @@ public List getChildElements(String elementName, String elementURI) return foundNodes; } -} + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + +} \ No newline at end of file diff --git a/core/test/org/sbml/jsbml/TreeNodeVisitorTest.java b/core/test/org/sbml/jsbml/TreeNodeVisitorTest.java new file mode 100644 index 000000000..81385ae74 --- /dev/null +++ b/core/test/org/sbml/jsbml/TreeNodeVisitorTest.java @@ -0,0 +1,53 @@ +package org.sbml.jsbml; + +import org.junit.Test; +import org.sbml.jsbml.util.TreeNodeWithChangeSupport; +import static org.junit.Assert.assertEquals; + +/** + * Tests for the {@link TreeNodeVisitor} scaffolding. + * Ensures the generic Visitor Pattern interfaces can be implemented and traversed. + * + * @author Deepak Yadav + */ +public class TreeNodeVisitorTest { + + /** + * A simple dummy implementation to prove the generic interface works. + * We use Integer as our to act as a visit counter. + */ + class DummyVisitor implements TreeNodeVisitor { + int nodesVisited = 0; + + @Override + public Integer visit(SBase sbase) { + nodesVisited++; + return nodesVisited; + } + + @Override + public Integer visit(TreeNodeWithChangeSupport node) { + nodesVisited++; + return nodesVisited; + } + } + + @Test + public void testVisitorAcceptance() { + // Instantiate our custom visitor + DummyVisitor visitor = new DummyVisitor(); + + // ASTNode is one of the core components that received the accept() method in PR #312 + ASTNode dummyNode = new ASTNode(ASTNode.Type.PLUS); + + // Execute the accept method. This proves that ASTNode can take a TreeNodeVisitor, + // route it to the correct visit() method, and return the generic type. + Integer result = dummyNode.accept(visitor); + + // Verify the visitor successfully entered the node and updated its internal state + assertEquals("Visitor should have recorded exactly 1 visit", 1, visitor.nodesVisited); + + // Verify that the accept() method successfully returned the (Integer) value + assertEquals("The accept method should return the value from the visitor", Integer.valueOf(1), result); + } +} \ No newline at end of file diff --git a/extensions/render/src/org/sbml/jsbml/ext/render/RelAbsVector.java b/extensions/render/src/org/sbml/jsbml/ext/render/RelAbsVector.java index 0740a34d5..e2ad2ef54 100644 --- a/extensions/render/src/org/sbml/jsbml/ext/render/RelAbsVector.java +++ b/extensions/render/src/org/sbml/jsbml/ext/render/RelAbsVector.java @@ -22,6 +22,8 @@ import javax.swing.tree.TreeNode; import org.sbml.jsbml.AbstractTreeNode; +import org.sbml.jsbml.TreeNodeVisitor; +import org.sbml.jsbml.ext.layout.BoundingBox; /** * Implements the RelAbsVector-datatype defined in the render-specification: @@ -327,4 +329,17 @@ public int getChildCount() { public boolean getAllowsChildren() { return false; } + + /** + * Accepts a generic visitor to traverse this component. + * + * @param the return type of the visitor + * @param visitor the visitor implementation + * @return the result of the visitor operation + */ + @Override + public T accept(TreeNodeVisitor visitor) { + return visitor.visit(this); + } + }