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    }