View Javadoc

1   // Copyright (c) 2002 Cunningham & Cunningham, Inc.
2   // Released under the terms of the GNU General Public License version 2 or later.
3   
4   package fit;
5   
6   import java.util.*;
7   
8   abstract public class RowFixture extends ColumnFixture {
9   
10      public Object results[];
11      public List missing = new LinkedList();
12      public List surplus = new LinkedList();
13  
14  
15      public void doRows(Parse rows) {
16          try {
17              bind(rows.parts);
18              results = query();
19              match(list(rows.more), list(results), 0);
20              Parse last = rows.last();
21              last.more = buildRows(surplus.toArray());
22              mark(last.more, "surplus");
23              mark(missing.iterator(), "missing");
24          } catch (Exception e) {
25              exception (rows.leaf(), e);
26          }
27      }
28  
29      abstract public Object[] query() throws Exception;  // get rows to be compared
30      abstract public Class getTargetClass();             // get expected type of row
31  
32      protected void match(List expected, List computed, int col) {
33          if (col >= columnBindings.length) {
34              check (expected, computed);
35          } else if (columnBindings[col] == null) {
36              match (expected, computed, col+1);
37          } else {
38              Map eMap = eSort(expected, col);
39              Map cMap = cSort(computed, col);
40              Set keys = union(eMap.keySet(),cMap.keySet());
41              for (Iterator i=keys.iterator(); i.hasNext(); ) {
42                  Object key = i.next();
43                  List eList = (List)eMap.get(key);
44                  List cList = (List)cMap.get(key);
45                  if (eList == null) {
46                      surplus.addAll(cList);
47                  } else if (cList == null) {
48                      missing.addAll(eList);
49                  } else if (eList.size()==1 && cList.size()==1) {
50                      check(eList, cList);
51                  } else {
52                      match(eList, cList, col+1);
53                  }
54              }
55          }
56      }
57  
58      protected List list (Parse rows) {
59          List result = new LinkedList();
60          while (rows != null) {
61              result.add(rows);
62              rows = rows.more;
63          }
64          return result;
65      }
66  
67      protected List list (Object[] rows) {
68          List result = new LinkedList();
69          for (int i=0; i<rows.length; i++) {
70              result.add(rows[i]);
71          }
72          return result;
73      }
74  
75      protected Map eSort(List list, int col) {
76          TypeAdapter a = columnBindings[col];
77          Map result = new HashMap(list.size());
78          for (Iterator i=list.iterator(); i.hasNext(); ) {
79              Parse row = (Parse) i.next();
80              Parse cell = row.parts.at(col);
81              try {
82                  Object key = a.parse(cell.text());
83                  bin(result, key, row);
84              } catch (Exception e) {
85                  exception(cell, e);
86                  for (Parse rest=cell.more; rest!=null; rest=rest.more) {
87                      ignore(rest);
88                  }
89              }
90          }
91          return result;
92      }
93  
94      protected Map cSort(List list, int col) {
95          TypeAdapter a = columnBindings[col];
96          Map result = new HashMap(list.size());
97          for (Iterator i=list.iterator(); i.hasNext(); ) {
98              Object row = i.next();
99              try {
100                 a.target = row;
101                 Object key = a.get();
102                 bin(result, key, row);
103             } catch (Exception e) {
104                 // surplus anything with bad keys, including null
105                 surplus.add(row);
106             }
107         }
108         return result;
109     }
110 
111     protected void bin (Map map, Object key, Object row) {
112         if (key.getClass().isArray()) {
113             key = Arrays.asList((Object[])key);
114         }
115         if (map.containsKey(key)) {
116             ((List)map.get(key)).add(row);
117         } else {
118             List list = new LinkedList();
119             list.add(row);
120             map.put(key, list);
121         }
122     }
123 
124     protected Set union (Set a, Set b) {
125         Set result = new HashSet();
126         result.addAll(a);
127         result.addAll(b);
128         return result;
129     }
130 
131     protected void check (List eList, List cList) {
132         if (eList.size()==0) {
133             surplus.addAll(cList);
134             return;
135         }
136         if (cList.size()==0) {
137             missing.addAll(eList);
138             return;
139         }
140         Parse row = (Parse)eList.remove(0);
141         Parse cell = row.parts;
142         Object obj = cList.remove(0);
143         for (int i=0; i<columnBindings.length && cell!=null; i++) {
144             TypeAdapter a = columnBindings[i];
145             if (a != null) {
146                 a.target = obj;
147             }
148             check(cell, a);
149             cell = cell.more;
150         }
151         check (eList, cList);
152     }
153 
154     protected void mark(Parse rows, String message) {
155         String annotation = label(message);
156         while (rows != null) {
157             wrong(rows.parts);
158             rows.parts.addToBody(annotation);
159             rows = rows.more;
160         }
161     }
162 
163     protected void mark(Iterator rows, String message) {
164         String annotation = label(message);
165         while (rows.hasNext()) {;
166             Parse row = (Parse)rows.next();
167             wrong(row.parts);
168             row.parts.addToBody(annotation);
169         }
170     }
171 
172     protected Parse buildRows(Object[] rows) {
173         Parse root = new Parse(null ,null, null, null);
174         Parse next = root;
175         for (int i=0; i<rows.length; i++) {
176             next = next.more = new Parse("tr", null, buildCells(rows[i]), null);
177         }
178         return root.more;
179     }
180 
181     protected Parse buildCells(Object row) {
182         if (row == null) {
183             Parse nil = new Parse("td", "null", null, null);
184             nil.addToTag(" colspan="+columnBindings.length);
185             return nil;
186         }
187         Parse root = new Parse(null, null, null, null);
188         Parse next = root;
189         for (int i=0; i<columnBindings.length; i++) {
190             next = next.more = new Parse("td", "&nbsp;", null, null);
191             TypeAdapter a = columnBindings[i];
192             if (a == null) {
193                 ignore (next);
194             } else {
195                 try {
196                     a.target = row;
197                     info(next, a.toString(a.get()));
198                 } catch (Exception e) {
199                     exception(next, e);
200                 }
201             }
202         }
203         return root.more;
204     }
205 }