001 /* 002 @license.text@ 003 */ 004 package biz.hammurapi.util; 005 006 import java.lang.reflect.Array; 007 import java.lang.reflect.Method; 008 import java.lang.reflect.UndeclaredThrowableException; 009 import java.util.ArrayList; 010 import java.util.Collection; 011 import java.util.Iterator; 012 import java.util.List; 013 import java.util.Map; 014 015 import biz.hammurapi.convert.ConvertingService; 016 017 018 /** 019 * Implements Visitable contract. Subclasses shall implement visitChildren() method. 020 * @author Pavel Vlasov 021 * @version $Revision: 1.4 $ 022 */ 023 public abstract class VisitableBase implements Visitable, Searchable { 024 025 public boolean accept(Visitor visitor) { 026 if (visitor==null) { 027 return false; 028 } 029 030 if (visitor.visit(this)) { 031 acceptChildren(visitor); 032 if (visitor instanceof PoliteVisitor) { 033 ((PoliteVisitor) visitor).leave(this); 034 } 035 return true; 036 } 037 038 return false; 039 } 040 041 public Object find(final Acceptor acceptor) { 042 final Object[] ret = {null}; 043 accept(new Visitor() { 044 045 public boolean visit(Object target) { 046 if (ret[0]!=null) { 047 return false; 048 } 049 050 if (acceptor.accept(target)) { 051 ret[0] = target; 052 return false; 053 } 054 return true; 055 } 056 057 }); 058 return ret[0]; 059 } 060 061 public Collection findAll(final Acceptor acceptor) { 062 final Collection ret = new ArrayList(); 063 accept(new Visitor() { 064 065 public boolean visit(Object target) { 066 if (acceptor.accept(target)) { 067 ret.add(target); 068 } 069 return true; 070 } 071 072 }); 073 return ret; 074 } 075 076 /** 077 * Override this method to navigate visitor through object constituents. 078 * @param visitor 079 */ 080 protected void acceptChildren(Visitor visitor) { 081 // No functionality 082 } 083 084 /** 085 * Properly handles passing visitor to a child - takes into account that child is visitable and visitor may 086 * be an instance of PoliteVisitor. 087 * @param target Object to be visited by the visitor. 088 * @param visitor 089 * @param child 090 */ 091 public static void object2visitor(Object target, Visitor visitor) { 092 if (visitor!=null && target!=null) { 093 if (target instanceof Visitable) { 094 ((Visitable) target).accept(visitor); 095 } else if (target instanceof Collection) { 096 if (visitor.visit(target)) { 097 Iterator it = ((Collection) target).iterator(); 098 while (it.hasNext()) { 099 object2visitor(it.next(), visitor); 100 } 101 if (visitor instanceof PoliteVisitor) { 102 ((PoliteVisitor) visitor).leave(target); 103 } 104 } 105 } else if (target instanceof Map) { 106 if (visitor.visit(target)) { 107 Iterator it = ((Map) target).entrySet().iterator(); 108 while (it.hasNext()) { 109 Map.Entry entry = (Map.Entry) it.next(); 110 if (visitor.visit(entry)) { 111 object2visitor(entry.getKey(), visitor); 112 object2visitor(entry.getValue(), visitor); 113 if (visitor instanceof PoliteVisitor) { 114 ((PoliteVisitor) visitor).leave(entry); 115 } 116 } 117 } 118 if (visitor instanceof PoliteVisitor) { 119 ((PoliteVisitor) visitor).leave(target); 120 } 121 } 122 } else if (target.getClass().isArray()) { 123 if (visitor.visit(target)) { 124 for (int i=0, l=Array.getLength(target); i<l; ++i) { 125 object2visitor(Array.get(target, i), visitor); 126 } 127 if (visitor instanceof PoliteVisitor) { 128 ((PoliteVisitor) visitor).leave(target); 129 } 130 } 131 } else { 132 Visitable converted = (Visitable) ConvertingService.convert(target, Visitable.class); 133 if (converted == null) { 134 if (visitor.visit(target) && visitor instanceof PoliteVisitor) { 135 ((PoliteVisitor) visitor).leave(target); 136 } 137 } else { 138 converted.accept(visitor); 139 } 140 } 141 } 142 } 143 144 /** 145 * Wraps object into instance of Searchable 146 * @param visitor 147 * @param child 148 */ 149 public static Searchable convert2searchable(final Object object) { 150 return new Searchable() { 151 152 public Object find(final Acceptor acceptor) { 153 final Object[] ret = {null}; 154 object2visitor(object, new Visitor() { 155 156 public boolean visit(Object target) { 157 if (ret[0]!=null) { 158 return false; 159 } 160 161 if (acceptor.accept(target)) { 162 ret[0] = target; 163 return false; 164 } 165 return true; 166 } 167 168 }); 169 return ret[0]; 170 } 171 172 public Collection findAll(final Acceptor acceptor) { 173 final Collection ret = new ArrayList(); 174 object2visitor(object, new Visitor() { 175 176 public boolean visit(Object target) { 177 if (acceptor.accept(target)) { 178 ret.add(target); 179 } 180 return true; 181 } 182 183 }); 184 return ret; 185 } 186 187 }; 188 } 189 190 }