1   /*
2    * $Header: /home/projects/jaxen/scm/jaxen/src/java/test/org/jaxen/test/ExprComparator.java,v 1.1 2007/01/06 15:48:58 elharo Exp $
3    * $Revision: 1.1 $
4    * $Date: 2007/01/06 15:48:58 $
5    *
6    * ====================================================================
7    *
8    * Copyright 2007 Ryan Gustafson
9    * All rights reserved.
10   *
11   * Redistribution and use in source and binary forms, with or without
12   * modification, are permitted provided that the following conditions are
13   * met:
14   * 
15   *   * Redistributions of source code must retain the above copyright
16   *     notice, this list of conditions and the following disclaimer.
17   * 
18   *   * Redistributions in binary form must reproduce the above copyright
19   *     notice, this list of conditions and the following disclaimer in the
20   *     documentation and/or other materials provided with the distribution.
21   * 
22   *   * Neither the name of the Jaxen Project nor the names of its
23   *     contributors may be used to endorse or promote products derived 
24   *     from this software without specific prior written permission.
25   * 
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
27   * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
29   * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
30   * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   *
38   * ====================================================================
39   * This software consists of voluntary contributions made by many 
40   * individuals on behalf of the Jaxen Project and was originally 
41   * created by bob mcwhirter <bob@werken.com> and 
42   * James Strachan <jstrachan@apache.org>.  For more information on the 
43   * Jaxen Project, please see <http://www.jaxen.org/>.
44   * 
45   * $Id: ExprComparator.java,v 1.1 2007/01/06 15:48:58 elharo Exp $
46   */
47  
48  package org.jaxen.test;
49  
50  import java.util.Comparator;
51  import java.util.List;
52  
53  import org.jaxen.expr.AdditiveExpr;
54  import org.jaxen.expr.AllNodeStep;
55  import org.jaxen.expr.CommentNodeStep;
56  import org.jaxen.expr.EqualityExpr;
57  import org.jaxen.expr.FilterExpr;
58  import org.jaxen.expr.FunctionCallExpr;
59  import org.jaxen.expr.LiteralExpr;
60  import org.jaxen.expr.LocationPath;
61  import org.jaxen.expr.LogicalExpr;
62  import org.jaxen.expr.MultiplicativeExpr;
63  import org.jaxen.expr.NameStep;
64  import org.jaxen.expr.NumberExpr;
65  import org.jaxen.expr.PathExpr;
66  import org.jaxen.expr.Predicate;
67  import org.jaxen.expr.ProcessingInstructionNodeStep;
68  import org.jaxen.expr.RelationalExpr;
69  import org.jaxen.expr.TextNodeStep;
70  import org.jaxen.expr.UnaryExpr;
71  import org.jaxen.expr.UnionExpr;
72  import org.jaxen.expr.VariableReferenceExpr;
73  
74  
75  class ExprComparator implements Comparator {
76  
77      public static final Comparator EXPR_COMPARATOR = new ExprComparator();
78  
79  	private static final int TYPE_ADDITIVE_EXPR = 1;
80  	private static final int TYPE_ALL_NODE_STEP = 2;
81  	private static final int TYPE_COMMENT_NODE_STEP = 3;
82  	private static final int TYPE_EQUALITY_EXPR = 4;
83  	private static final int TYPE_FILTER_EXPR = 5;
84  	private static final int TYPE_FUNCTION_CALL_EXPR = 6;
85  	private static final int TYPE_LITERAL_EXPR = 7;
86  	private static final int TYPE_LOCATION_PATH = 8;
87  	private static final int TYPE_LOGICAL_EXP = 9;
88  	private static final int TYPE_MULTIPLICATIVE_EXPR = 10;
89  	private static final int TYPE_NAME_STEP = 11;
90  	private static final int TYPE_NUMBER_EXPR = 12;
91  	private static final int TYPE_PATH_EXPR = 13;
92  	private static final int TYPE_PREDICATE = 14;
93  	private static final int TYPE_PROCESSING_INSTRUCTION_NODE_STEP = 15;
94  	private static final int TYPE_RELATIONAL_EXPR = 16;
95  	private static final int TYPE_TEXT_NODE_STEP = 17;
96  	private static final int TYPE_UNARY_EXPR = 18;
97  	private static final int TYPE_UNION_EXPR = 19;
98  	private static final int TYPE_VARIABLE_REFERENCE_EXPR = 20;
99  
100 	private ExprComparator()
101 	{
102 	}
103 
104 	public int compare(Object o1, Object o2)
105 	{
106 		int type1 = getType(o1);
107 		int type2 = getType(o2);
108 
109 		int cmp;
110 		if (type1 == type2)
111 		{
112 			switch (type1)
113 			{
114 				case TYPE_ADDITIVE_EXPR:
115 					AdditiveExpr additiveExpr1 = (AdditiveExpr)o1;
116 					AdditiveExpr additiveExpr2 = (AdditiveExpr)o2;
117 					cmp = additiveExpr1.getOperator().compareTo(additiveExpr2.getOperator());
118 					if (cmp == 0)
119 					{
120 						cmp = compare(additiveExpr1.getLHS(), additiveExpr2.getLHS());
121 						if (cmp == 0)
122 						{
123 							cmp = compare(additiveExpr1.getRHS(), additiveExpr2.getRHS());
124 						}
125 					}
126 					break;
127 				case TYPE_ALL_NODE_STEP:
128 					AllNodeStep allNodeStep1 = (AllNodeStep)o1;
129 					AllNodeStep allNodeStep2 = (AllNodeStep)o2;
130 					cmp = allNodeStep1.getAxis() - allNodeStep2.getAxis();
131 					if (cmp == 0)
132 					{
133 						cmp = compareLists(allNodeStep1.getPredicates(), allNodeStep2.getPredicates());
134 					}
135 					break;
136 				case TYPE_COMMENT_NODE_STEP:
137 					CommentNodeStep commentNodeStep1 = (CommentNodeStep)o1;
138 					CommentNodeStep commentNodeStep2 = (CommentNodeStep)o2;
139 					cmp = commentNodeStep1.getAxis() - commentNodeStep2.getAxis();
140 					if (cmp == 0)
141 					{
142 						cmp = compareLists(commentNodeStep1.getPredicates(), commentNodeStep2.getPredicates());
143 					}
144 					break;
145 				case TYPE_EQUALITY_EXPR:
146 					EqualityExpr equalityExpr1 = (EqualityExpr)o1;
147 					EqualityExpr equalityExpr2 = (EqualityExpr)o2;
148 					cmp = equalityExpr1.getOperator().compareTo(equalityExpr2.getOperator());
149 					if (cmp == 0)
150 					{
151 						cmp = compare(equalityExpr1.getLHS(), equalityExpr1.getLHS());
152 						if (cmp == 0)
153 						{
154 							cmp = compare(equalityExpr1.getRHS(), equalityExpr1.getRHS());
155 						}
156 					}
157 					break;
158 				case TYPE_FILTER_EXPR:
159 					if (true)
160 						throw new RuntimeException("Not yet implemented!");
161 					break;
162 				case TYPE_FUNCTION_CALL_EXPR:
163 					FunctionCallExpr functionCallExpr1 = (FunctionCallExpr)o1;
164 					FunctionCallExpr functionCallExpr2 = (FunctionCallExpr)o2;
165 					cmp = compareStrings(functionCallExpr1.getPrefix(), functionCallExpr2.getPrefix());
166 					if (cmp == 0)
167 					{
168 						cmp = functionCallExpr1.getFunctionName().compareTo(functionCallExpr2.getFunctionName());
169 						if (cmp == 0)
170 						{
171 							cmp = compareLists(functionCallExpr1.getParameters(), functionCallExpr2.getParameters());
172 						}
173 					}
174 					break;
175 				case TYPE_LITERAL_EXPR:
176 					LiteralExpr literalExpr1 = (LiteralExpr)o1;
177 					LiteralExpr literalExpr2 = (LiteralExpr)o2;
178 					cmp = literalExpr1.getLiteral().compareTo(literalExpr2.getLiteral());
179 					break;
180 				case TYPE_LOCATION_PATH:
181 					LocationPath locationPath1 = (LocationPath)o1;
182 					LocationPath locationPath2 = (LocationPath)o2;
183 					if (locationPath1.isAbsolute() == locationPath2.isAbsolute())
184 					{
185 						cmp = compareLists(locationPath1.getSteps(), locationPath2.getSteps());
186 					}
187 					else if (locationPath1.isAbsolute())
188 					{
189 						cmp = 1;
190 					}
191 					else
192 					{
193 						cmp = -1;
194 					}
195 					break;
196 				case TYPE_LOGICAL_EXP:
197 					LogicalExpr logicalExpr1 = (LogicalExpr)o1;
198 					LogicalExpr logicalExpr2 = (LogicalExpr)o2;
199 					cmp = logicalExpr1.getOperator().compareTo(logicalExpr2.getOperator());
200 					if (cmp == 0)
201 					{
202 						cmp = compare(logicalExpr1.getLHS(), logicalExpr2.getLHS());
203 						if (cmp == 0)
204 						{
205 							cmp = compare(logicalExpr1.getRHS(), logicalExpr2.getRHS());
206 						}
207 					}
208 					break;
209 				case TYPE_MULTIPLICATIVE_EXPR:
210 					MultiplicativeExpr multiplicativeExpr1 = (MultiplicativeExpr)o1;
211 					MultiplicativeExpr multiplicativeExpr2 = (MultiplicativeExpr)o2;
212 					cmp = multiplicativeExpr1.getOperator().compareTo(multiplicativeExpr2.getOperator());
213 					if (cmp == 0)
214 					{
215 						cmp = compare(multiplicativeExpr1.getLHS(), multiplicativeExpr2.getLHS());
216 						if (cmp == 0)
217 						{
218 							cmp = compare(multiplicativeExpr1.getRHS(), multiplicativeExpr2.getRHS());
219 						}
220 					}
221 					break;
222 				case TYPE_NAME_STEP:
223 					NameStep nameStep1 = (NameStep)o1;
224 					NameStep nameStep2 = (NameStep)o2;
225 					cmp = nameStep1.getAxis() - nameStep2.getAxis();
226 					if (cmp == 0)
227 					{
228 						cmp = compareStrings(nameStep1.getPrefix(), nameStep2.getPrefix());
229 
230 						if (cmp == 0)
231 						{
232 							cmp = nameStep1.getLocalName().compareTo(nameStep2.getLocalName());
233 							if (cmp == 0)
234 							{
235 								cmp = compareLists(nameStep1.getPredicates(), nameStep2.getPredicates());
236 							}
237 						}
238 					}
239 					break;
240 				case TYPE_NUMBER_EXPR:
241 					NumberExpr numberExpr1 = (NumberExpr)o1;
242 					NumberExpr numberExpr2 = (NumberExpr)o2;
243 					cmp = new Double(numberExpr1.getNumber().doubleValue()).compareTo(new Double(numberExpr2.getNumber().doubleValue()));
244 					break;
245 				case TYPE_PATH_EXPR:
246 					PathExpr pathExpr1 = (PathExpr)o1;
247 					PathExpr pathExpr2 = (PathExpr)o2;
248 					cmp = compare(pathExpr1.getLocationPath(), pathExpr2.getLocationPath());
249 					if (cmp == 0)
250 					{
251 						cmp = compare(pathExpr1.getFilterExpr(), pathExpr2.getFilterExpr());
252 					}
253 					break;
254 				case TYPE_PREDICATE:
255 					Predicate predicate1 = (Predicate)o1;
256 					Predicate predicate2 = (Predicate)o2;
257 					cmp = compare(predicate1.getExpr(), predicate2.getExpr());
258 					break;
259 				case TYPE_PROCESSING_INSTRUCTION_NODE_STEP:
260 					ProcessingInstructionNodeStep processingInstructionNodeStep1 = (ProcessingInstructionNodeStep)o1;
261 					ProcessingInstructionNodeStep processingInstructionNodeStep2 = (ProcessingInstructionNodeStep)o2;
262 					cmp = processingInstructionNodeStep1.getAxis() - processingInstructionNodeStep2.getAxis();
263 					if (cmp == 0)
264 					{
265 						cmp = compareStrings(processingInstructionNodeStep1.getName(), processingInstructionNodeStep2.getName());
266 						if (cmp == 0)
267 						{
268 							cmp = compareLists(processingInstructionNodeStep1.getPredicates(), processingInstructionNodeStep2.getPredicates());
269 						}
270 					}
271 					break;
272 				case TYPE_RELATIONAL_EXPR:
273 					RelationalExpr relationalExpr1 = (RelationalExpr)o1;
274 					RelationalExpr relationalExpr2 = (RelationalExpr)o2;
275 					cmp = relationalExpr1.getOperator().compareTo(relationalExpr2.getOperator());
276 					if (cmp == 0)
277 					{
278 						cmp = compare(relationalExpr1.getLHS(), relationalExpr2.getLHS());
279 						if (cmp == 0)
280 						{
281 							cmp = compare(relationalExpr1.getRHS(), relationalExpr2.getRHS());
282 						}
283 					}
284 					break;
285 				case TYPE_TEXT_NODE_STEP:
286 					TextNodeStep textNodeStep1 = (TextNodeStep)o1;
287 					TextNodeStep textNodeStep2 = (TextNodeStep)o2;
288 					cmp = textNodeStep1.getAxis() - textNodeStep2.getAxis();
289 					if (cmp == 0)
290 					{
291 						cmp = compareLists(textNodeStep1.getPredicates(), textNodeStep2.getPredicates());
292 					}
293 					break;
294 				case TYPE_UNARY_EXPR:
295 					UnaryExpr unaryExpr1 = (UnaryExpr)o1;
296 					UnaryExpr unaryExpr2 = (UnaryExpr)o2;
297 					cmp = compare(unaryExpr1.getExpr(), unaryExpr2.getExpr());
298 					break;
299 				case TYPE_UNION_EXPR:
300 					if (true)
301 						throw new RuntimeException("Not yet implemented!");
302 					break;
303 				case TYPE_VARIABLE_REFERENCE_EXPR:
304 					VariableReferenceExpr variableReferenceExpr1 = (VariableReferenceExpr)o1;
305 					VariableReferenceExpr variableReferenceExpr2 = (VariableReferenceExpr)o2;
306 					cmp = compareStrings(variableReferenceExpr1.getPrefix(), variableReferenceExpr2.getPrefix());
307 					if (cmp == 0)
308 					{
309 						cmp = variableReferenceExpr1.getVariableName().compareTo(variableReferenceExpr2.getVariableName());
310 					}
311 					break;
312 				default:
313 					throw new IllegalArgumentException("Unhandled type: " + type1);
314 			}
315 		}
316 		else
317 		{
318 			cmp = type1 - type2;
319 		}
320 		return cmp;
321 	}
322 
323 	private int compareStrings(String s1, String s2)
324 	{
325 		int cmp;
326 		if (s1 == s2)
327 		{
328 			cmp = 0;
329 		}
330 		else if (s1 == null)
331 		{
332 			cmp = -1;
333 		}
334 		else if (s2 == null)
335 		{
336 			cmp = 1;
337 		}
338 		else
339 		{
340 			cmp = s1.compareTo(s2);
341 		}
342 		return cmp;
343 	}
344 
345 	private int compareLists(List list1, List list2)
346 	{
347 		int cmp;
348 		if (list1 == list2)
349 		{
350 			cmp = 0;
351 		}
352 		else if (list1 == null)
353 		{
354 			cmp = -1;
355 		}
356 		else if (list2 == null)
357 		{
358 			cmp = 1;
359 		}
360 		else
361 		{
362 			cmp = list1.size() - list2.size();
363 			if (cmp == 0)
364 			{
365 				for (int i = 0; i < list1.size() && cmp == 0; i++)
366 				{
367 					cmp = compare(list1.get(i), list2.get(i));
368 				}
369 			}
370 		}
371 		return cmp;
372 	}
373 
374 	private int getType(Object node)
375 	{
376 		if (node instanceof AdditiveExpr)
377 		{
378 			return TYPE_ADDITIVE_EXPR;
379 		}
380 		else if (node instanceof AllNodeStep)
381 		{
382 			return TYPE_ALL_NODE_STEP;
383 		}
384 		else if (node instanceof CommentNodeStep)
385 		{
386 			return TYPE_COMMENT_NODE_STEP;
387 		}
388 		else if (node instanceof EqualityExpr)
389 		{
390 			return TYPE_EQUALITY_EXPR;
391 		}
392 		else if (node instanceof FilterExpr)
393 		{
394 			return TYPE_FILTER_EXPR;
395 		}
396 		else if (node instanceof FunctionCallExpr)
397 		{
398 			return TYPE_FUNCTION_CALL_EXPR;
399 		}
400 		else if (node instanceof LiteralExpr)
401 		{
402 			return TYPE_LITERAL_EXPR;
403 		}
404 		else if (node instanceof LocationPath)
405 		{
406 			return TYPE_LOCATION_PATH;
407 		}
408 		else if (node instanceof LogicalExpr)
409 		{
410 			return TYPE_LOGICAL_EXP;
411 		}
412 		else if (node instanceof MultiplicativeExpr)
413 		{
414 			return TYPE_MULTIPLICATIVE_EXPR;
415 		}
416 		else if (node instanceof NameStep)
417 		{
418 			return TYPE_NAME_STEP;
419 		}
420 		else if (node instanceof NumberExpr)
421 		{
422 			return TYPE_NUMBER_EXPR;
423 		}
424 		else if (node instanceof PathExpr)
425 		{
426 			return TYPE_PATH_EXPR;
427 		}
428 		else if (node instanceof Predicate)
429 		{
430 			return TYPE_PREDICATE;
431 		}
432 		else if (node instanceof ProcessingInstructionNodeStep)
433 		{
434 			return TYPE_PROCESSING_INSTRUCTION_NODE_STEP;
435 		}
436 		else if (node instanceof RelationalExpr)
437 		{
438 			return TYPE_RELATIONAL_EXPR;
439 		}
440 		else if (node instanceof TextNodeStep)
441 		{
442 			return TYPE_TEXT_NODE_STEP;
443 		}
444 		else if (node instanceof UnaryExpr)
445 		{
446 			return TYPE_UNARY_EXPR;
447 		}
448 		else if (node instanceof UnionExpr)
449 		{
450 			return TYPE_UNION_EXPR;
451 		}
452 		else if (node instanceof VariableReferenceExpr)
453 		{
454 			return TYPE_VARIABLE_REFERENCE_EXPR;
455 		}
456 		else
457 		{
458 			throw new IllegalArgumentException("Unknown Jaxen AST node type: " + node);
459 		}
460 	}
461 }