001package org.biopax.paxtools.controller; 002 003import org.apache.commons.logging.Log; 004import org.apache.commons.logging.LogFactory; 005import org.biopax.paxtools.model.BioPAXElement; 006import org.biopax.paxtools.model.Model; 007import org.biopax.paxtools.util.Filter; 008 009import java.util.HashSet; 010import java.util.Set; 011 012/** 013 * This is an all-in-one Traverser/Visitor combination 014 * to use when deep recursive visiting is required. 015 * Unlike {@link Traverser}, it keeps track of where current 016 * object is in the model and whether it's been already visited, 017 * which helps prevent infinite loops. 018 * Like it's for the {@link Traverser}, there is no any 019 * particular order in which it processes properties. 020 * 021 * @see Fetcher 022 * @see Traverser 023 * @see Visitor 024 * 025 * @author rodch 026 */ 027public abstract class AbstractTraverser extends Traverser implements Visitor 028{ 029 private final static Log log = LogFactory.getLog(AbstractTraverser.class); 030 protected final Set<BioPAXElement> visited; 031 032 public AbstractTraverser(EditorMap editorMap, 033 @SuppressWarnings("rawtypes") Filter<PropertyEditor>... filters) 034 { 035 super(editorMap, null, filters); 036 setVisitor(this); 037 visited = new HashSet<BioPAXElement>(); 038 } 039 040 /** 041 * This is to implement a real action here: 042 * do something, return or even to continue (traverse) 043 * into the child (range) element's properties if it's a BioPAX object. 044 * 045 * @param range property value 046 * @param domain parent/owner BioPAX element 047 * @param model the BioPAX model of interest 048 * @param editor the property editor 049 */ 050 protected abstract void visit(Object range, BioPAXElement domain, Model model, PropertyEditor<?,?> editor); 051 052 /** 053 * Calls the protected abstract method visit that is to be 054 * implemented in subclasses of this abstract class. 055 * 056 * @param domain BioPAX Element 057 * @param range property value (can be BioPAX element, primitive, enum, string) 058 * @param model the BioPAX model of interest 059 * @param editor parent's property PropertyEditor 060 */ 061 public void visit(BioPAXElement domain, Object range, Model model, PropertyEditor<?,?> editor) { 062 // actions 063 visit(range, domain, model, editor); 064 } 065 066 067 @Override 068 public <D extends BioPAXElement> void traverse(D element, Model model) { 069 if(visited.add(element)) { 070 super.traverse(element, model);//calls visit method for each property value, taking prop. filters into acc. 071 } else { 072 log.debug("Escaped a loop: again " + element.getRDFId()); 073 } 074 } 075 076 077 /** 078 * Clears the internal set of traversed biopax objects. 079 * Apply if you're re-using the same traverser instance but 080 * start over from a different root biopax element. 081 */ 082 public void reset() { 083 visited.clear(); 084 } 085}