/** * ModelWalker.java * * @author Charles Groves */ package edu.sc.seis.sod.validator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import edu.sc.seis.sod.validator.documenter.SchemaDocumenter; import edu.sc.seis.sod.validator.model.Choice; import edu.sc.seis.sod.validator.model.Definition; import edu.sc.seis.sod.validator.model.Form; import edu.sc.seis.sod.validator.model.GenitorForm; import edu.sc.seis.sod.validator.model.Group; import edu.sc.seis.sod.validator.model.Interleave; import edu.sc.seis.sod.validator.model.MultigenitorForm; import edu.sc.seis.sod.validator.model.NamedElement; public class ModelWalker { public ModelWalker(Form root) { populateMapCaches(root); defsToInstance.put(root.getDef(), root); } public Collection<Definition> getContainingDefs(Definition def) { if(!defsToContainment.containsKey(def)) { defsToContainment.put(def, new HashSet<Definition>()); } ArrayList out = new ArrayList<Definition>(); out.addAll(defsToContainment.get(def)); Collections.sort(out, new Comparator<Definition>() { @Override public int compare(Definition o1, Definition o2) { return o1.getName().compareTo(o2.getName()); } }); return out; } public Form getInstance(Form root, Definition def) { return (Form)defsToInstance.get(def); } private Map<Definition, Set<Definition>> defsToContainment = new HashMap<Definition, Set<Definition>>(); private Map<Definition, Form> defsToInstance = new HashMap<Definition, Form>(); private void populateMapCaches(Form root) { if(root.isFromDef() && root.getParent() != null) { Definition def = root.getDef(); if(!defsToContainment.containsKey(def)) { defsToContainment.put(def, new HashSet<Definition>()); } defsToInstance.put(root.getDef(), root); defsToContainment.get(def).add(SchemaDocumenter.getNearestDef(root.getParent())); } if(!isSelfReferential(root) && (getLineage(root).length <= 9)) { if(root instanceof GenitorForm) { populateMapCaches(((GenitorForm)root).getChild()); } else if(root instanceof MultigenitorForm) { MultigenitorForm multiRoot = (MultigenitorForm)root; Form[] kids = multiRoot.getChildren(); for(int i = 0; i < kids.length; i++) { populateMapCaches(kids[i]); } } } } public static boolean isSelfReferential(Form f) { return isSelfReferential(f, null); } public static boolean isSelfReferential(Form f, Form root) { if(f.isFromDef() && !f.equals(root)) { return lineageContainsRefTo(f, f.getDef(), root); } return false; } public static boolean requiresSelfReferentiality(Form f) { if(f.getMin() == 0) return false; if(isSelfReferential(f)) return true; if(f instanceof NamedElement) { NamedElement el = (NamedElement)f; Form kid = el.getChild(); return requiresSelfReferentiality(kid); } else if(f instanceof Choice) { Choice c = (Choice)f; Form[] kids = c.getChildren(); for(int i = 0; i < kids.length; i++) { if(!requiresSelfReferentiality(kids[i])) return false; } return true; } else if(f instanceof Interleave || f instanceof Group) { MultigenitorForm multi = (MultigenitorForm)f; Form[] kids = multi.getChildren(); for(int i = 0; i < kids.length; i++) { if(requiresSelfReferentiality(kids[i])) { return true; } } return false; } return false; } public static boolean lineageContainsRefTo(Form f, Definition def) { return lineageContainsRefTo(f, def, null); } public static boolean lineageContainsRefTo(Form f, Definition def, Form root) { Form parent = f.getParent(); if(parent == null || def == null || f.equals(root)) { return false; } if(def.equals(parent.getDef())) { return true; } return lineageContainsRefTo(parent, def, root); } public static NamedElement getDescendantTowards(NamedElement parent, NamedElement result) { Form child = parent.getChild(); if(child instanceof NamedElement && isTowards(child, result)) { return (NamedElement)child; } else if(child instanceof MultigenitorForm) { return getDescendantTowards((MultigenitorForm)child, result); } return null; } private static NamedElement getDescendantTowards(MultigenitorForm f, NamedElement result) { Form[] kids = f.getChildren(); for(int i = 0; i < kids.length; i++) { if(kids[i] instanceof NamedElement && isTowards(kids[i], result)) { return (NamedElement)kids[i]; } else if(kids[i] instanceof MultigenitorForm) { NamedElement subresult = getDescendantTowards((MultigenitorForm)kids[i], result); if(subresult != null) { return subresult; } } } return null; } public static boolean isTowards(Form parent, Form result) { //System.out.println("isTowards called"); //System.out.println("PARENT=" + ModelUtil.toString(parent)); // System.out.println("RESULT=" + ModelUtil.toString(result)); boolean b = parent.isAncestorOf(result, parent) || parent.equals(result); //System.out.println("isTowards: " + b); return b; } public static int getDistance(Form base, Form result) { return getDistance(base, base, result); } private static int getDistance(Form initialBase, Form base, Form result) { if(result == null) { return -1; } if(result.equals(base)) { return 0; } if(base.isFromDef() && base != initialBase) { Form[] lineageToInitial = getLineage(base.getParent(), initialBase); for(int i = 0; i < lineageToInitial.length; i++) { Form cur = lineageToInitial[i]; if(cur.isFromDef() && cur.getDef().equals(base.getDef())) { return -1; } } } if(base instanceof MultigenitorForm) { MultigenitorForm mgf = (MultigenitorForm)base; int minDist = Integer.MAX_VALUE; for(int i = 0; i < mgf.getChildren().length; i++) { Form cur = mgf.getChildren()[i]; int curDist = getDistance(initialBase, cur, result); if(curDist < minDist && curDist > -1) { minDist = curDist; } } if(minDist < Integer.MAX_VALUE) { return minDist; } } else if(base instanceof GenitorForm) { GenitorForm gf = (GenitorForm)base; int subDist = getDistance(initialBase, gf.getChild(), result); if(subDist > -1) { return subDist + 1; } } return -1; } public static NamedElement[] getSiblings(NamedElement brother) { Form parent = brother.getParent(); if(parent == null) { return new NamedElement[] {brother}; } while(!(parent instanceof NamedElement)) { parent = parent.getParent(); } return ((NamedElement)parent).getElementalChildren(); } public static Form[] getLineage(Form f) { return getLineage(f, null); } public static Form[] getLineage(Form child, Form parent) { List lineageList = new ArrayList(); Form temp = child; while(temp != parent) { lineageList.add(temp); temp = temp.getParent(); } return (Form[])lineageList.toArray(new Form[0]); } public static boolean isInLineage(Form parent, Form result) { Form[] lineage = getLineage(result); for(int i = 0; i < lineage.length; i++) { if(lineage[i].equals(parent)) { return true; } } return false; } public static String getNamespaceFromAncestors(Form f) { String ns = null; Form temp = f; do { ns = temp.getNamespace(); temp = temp.getParent(); } while(temp != null && ns == null); return ns; } }