View Javadoc

1   /* ====================================================================
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 2002-2003 The Apache Software Foundation.  All rights
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution, if
20   *    any, must include the following acknowledgement:
21   *       "This product includes software developed by the
22   *        Apache Software Foundation (http://www.apache.org/)."
23   *    Alternately, this acknowledgement may appear in the software itself,
24   *    if and wherever such third-party acknowledgements normally appear.
25   *
26   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
27   *    Foundation" must not be used to endorse or promote products derived
28   *    from this software without prior written permission. For written
29   *    permission, please contact apache@apache.org.
30   *
31   * 5. Products derived from this software may not be called "Apache"
32   *    nor may "Apache" appear in their names without prior written
33   *    permission of the Apache Software Foundation.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.apache.org/>.
53   */
54  package net.sf.composite.util;
55  
56  import java.lang.reflect.AccessibleObject;
57  import java.lang.reflect.Field;
58  import java.lang.reflect.Modifier;
59  
60  /***
61   * <em>This class was copied from <a href="http://jakarta.apache.org/commons/lang">Apache Jakarta Commons Lang</a> 2.0.</em>
62   * 
63   * <p>
64   * Assists in implementing {@link Object#hashCode()}methods.
65   * </p>
66   * 
67   * <p>
68   * This class enables a good <code>hashCode</code> method to be built for any
69   * class. It follows the rules laid out in the book <a
70   * href="http://java.sun.com/docs/books/effective/index.html">Effective Java
71   * </a> by Joshua Bloch. Writing a good <code>hashCode</code> method is
72   * actually quite difficult. This class aims to simplify the process.
73   * </p>
74   * 
75   * <p>
76   * All relevant fields from the object should be included in the
77   * <code>hashCode</code> method. Derived fields may be excluded. In general,
78   * any field used in the <code>equals</code> method must be used in the
79   * <code>hashCode</code> method.
80   * </p>
81   * 
82   * <p>
83   * To use this class write code as follows:
84   * </p>
85   * 
86   * <pre>
87   * 
88   *  
89   *   public class Person {
90   *     String name;
91   *     int age;
92   *     boolean isSmoker;
93   *     ...
94   *  
95   *     public int hashCode() {
96   *       // you pick a hard-coded, randomly chosen, non-zero, odd number
97   *       // ideally different for each class
98   *       return new HashCodeBuilder(17, 37).
99   *         append(name).
100  *         append(age).
101  *         append(smoker).
102  *         toHashCode();
103  *     }
104  *   }
105  *   
106  *  
107  * </pre>
108  * 
109  * <p>
110  * If required, the superclass <code>hashCode()</code> can be added using
111  * {@link #appendSuper}.
112  * </p>
113  * 
114  * <p>
115  * Alternatively, there is a method that uses reflection to determine the fields
116  * to test. Because these fields are usually private, the method,
117  * <code>reflectionHashCode</code>, uses
118  * <code>AccessibleObject.setAccessible</code> to change the visibility of the
119  * fields. This will fail under a security manager, unless the appropriate
120  * permissions are set up correctly. It is also slower than testing explicitly.
121  * </p>
122  * 
123  * <p>
124  * A typical invocation for this method would look like:
125  * </p>
126  * 
127  * <pre>
128  * public int hashCode() {
129  * 	return HashCodeBuilder.reflectionHashCode(this);
130  * }
131  * </pre>
132  * 
133  * @author Stephen Colebourne
134  * @author Gary Gregory
135  * @author Pete Gieser
136  * @since 1.0
137  * @version $Id: HashCodeBuilder.java,v 1.1 2005/03/16 19:32:58 sgarlatm Exp $
138  */
139 public class HashCodeBuilder {
140 
141     /***
142      * Constant to use in building the hashCode.
143      */
144     private final int iConstant;
145     /***
146      * Running total of the hashCode.
147      */
148     private int iTotal = 0;
149 
150     /***
151      * <p>Constructor.</p>
152      *
153      * <p>This constructor uses two hard coded choices for the constants
154      * needed to build a <code>hashCode</code>.</p>
155      */
156     public HashCodeBuilder() {
157         super();
158         iConstant = 37;
159         iTotal = 17;
160     }
161 
162     /***
163      * <p>Constructor.</p>
164      *
165      * <p>Two randomly chosen, non-zero, odd numbers must be passed in.
166      * Ideally these should be different for each class, however this is
167      * not vital.</p>
168      *
169      * <p>Prime numbers are preferred, especially for the multiplier.</p>
170      *
171      * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
172      * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
173      * @throws IllegalArgumentException if the number is zero or even
174      */
175     public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
176         super();
177         if (initialNonZeroOddNumber == 0) {
178             throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
179         }
180         if (initialNonZeroOddNumber % 2 == 0) {
181             throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
182         }
183         if (multiplierNonZeroOddNumber == 0) {
184             throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
185         }
186         if (multiplierNonZeroOddNumber % 2 == 0) {
187             throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
188         }
189         iConstant = multiplierNonZeroOddNumber;
190         iTotal = initialNonZeroOddNumber;
191     }
192 
193     //-------------------------------------------------------------------------
194 
195     /***
196      * <p>This method uses reflection to build a valid hash code.</p>
197      *
198      * <p>This constructor uses two hard coded choices for the constants
199      * needed to build a hash code.</p>
200      *
201      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
202      * fields. This means that it will throw a security exception if run under
203      * a security manager, if the permissions are not set up correctly. It is
204      * also not as efficient as testing explicitly.</p>
205      *
206      * <p>Transient members will be not be used, as they are likely derived
207      * fields, and not part of the value of the <code>Object</code>.</p>
208      *
209      * <p>Static fields will not be tested. Superclass fields will be included.</p>
210      *
211      * @param object  the Object to create a <code>hashCode</code> for
212      * @return int hash code
213      * @throws IllegalArgumentException if the object is <code>null</code>
214      */
215     public static int reflectionHashCode(Object object) {
216         return reflectionHashCode(17, 37, object, false, null);
217     }
218 
219     /***
220      * <p>This method uses reflection to build a valid hash code.</p>
221      *
222      * <p>This constructor uses two hard coded choices for the constants needed
223      * to build a hash code.</p>
224      *
225      * <p> It uses <code>AccessibleObject.setAccessible</code> to gain access to private
226      * fields. This means that it will throw a security exception if run under
227      * a security manager, if the permissions are not set up correctly. It is
228      * also not as efficient as testing explicitly.</p>
229      *
230      * <P>If the TestTransients parameter is set to <code>true</code>, transient
231      * members will be tested, otherwise they are ignored, as they are likely
232      * derived fields, and not part of the value of the <code>Object</code>.</p>
233      *
234      * <p>Static fields will not be tested. Superclass fields will be included.</p>
235      *
236      * @param object  the Object to create a <code>hashCode</code> for
237      * @param testTransients  whether to include transient fields
238      * @return int hash code
239      * @throws IllegalArgumentException if the object is <code>null</code>
240      */
241     public static int reflectionHashCode(Object object, boolean testTransients) {
242         return reflectionHashCode(17, 37, object, testTransients, null);
243     }
244 
245     /***
246      * <p>This method uses reflection to build a valid hash code.</p>
247      *
248      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
249      * fields. This means that it will throw a security exception if run under
250      * a security manager, if the permissions are not set up correctly. It is
251      * also not as efficient as testing explicitly.</p>
252      *
253      * <p>Transient members will be not be used, as they are likely derived
254      * fields, and not part of the value of the <code>Object</code>.</p>
255      *
256      * <p>Static fields will not be tested. Superclass fields will be included.</p>
257      *
258      * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
259      * these should be different for each class, however this is not vital.
260      * Prime numbers are preferred, especially for the multiplier.</p>
261      *
262      * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
263      * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
264      * @param object  the Object to create a <code>hashCode</code> for
265      * @return int hash code
266      * @throws IllegalArgumentException if the Object is <code>null</code>
267      * @throws IllegalArgumentException if the number is zero or even
268      */
269     public static int reflectionHashCode(
270             int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
271         return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
272     }
273 
274     /***
275      * <p>This method uses reflection to build a valid hash code.</p>
276      *
277      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
278      * fields. This means that it will throw a security exception if run under
279      * a security manager, if the permissions are not set up correctly. It is also
280      * not as efficient as testing explicitly.</p>
281      *
282      * <p>If the TestTransients parameter is set to <code>true</code>, transient
283      * members will be tested, otherwise they are ignored, as they are likely
284      * derived fields, and not part of the value of the <code>Object</code>.</p>
285      *
286      * <p>Static fields will not be tested. Superclass fields will be included.</p>
287      *
288      * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
289      * these should be different for each class, however this is not vital.
290      * Prime numbers are preferred, especially for the multiplier.</p>
291      *
292      * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
293      * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
294      * @param object  the Object to create a <code>hashCode</code> for
295      * @param testTransients  whether to include transient fields
296      * @return int hash code
297      * @throws IllegalArgumentException if the Object is <code>null</code>
298      * @throws IllegalArgumentException if the number is zero or even
299      */
300     public static int reflectionHashCode(
301             int initialNonZeroOddNumber, int multiplierNonZeroOddNumber,
302             Object object, boolean testTransients) {
303         return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
304     }
305             
306     /***
307      * <p>This method uses reflection to build a valid hash code.</p>
308      *
309      * <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
310      * fields. This means that it will throw a security exception if run under
311      * a security manager, if the permissions are not set up correctly. It is also
312      * not as efficient as testing explicitly.</p>
313      *
314      * <p>If the TestTransients parameter is set to <code>true</code>, transient
315      * members will be tested, otherwise they are ignored, as they are likely
316      * derived fields, and not part of the value of the <code>Object</code>.</p>
317      *
318      * <p>Static fields will not be included. Superclass fields will be included
319      * up to and including the specified superclass. A null superclass is treated
320      * as java.lang.Object.</p>
321      *
322      * <p>Two randomly chosen, non-zero, odd numbers must be passed in. Ideally
323      * these should be different for each class, however this is not vital.
324      * Prime numbers are preferred, especially for the multiplier.</p>
325      *
326      * @param initialNonZeroOddNumber  a non-zero, odd number used as the initial value
327      * @param multiplierNonZeroOddNumber  a non-zero, odd number used as the multiplier
328      * @param object  the Object to create a <code>hashCode</code> for
329      * @param testTransients  whether to include transient fields
330      * @param reflectUpToClass  the superclass to reflect up to (inclusive),
331      *  may be <code>null</code>
332      * @return int hash code
333      * @throws IllegalArgumentException if the Object is <code>null</code>
334      * @throws IllegalArgumentException if the number is zero or even
335      * @since 2.0
336      */
337     public static int reflectionHashCode(
338         int initialNonZeroOddNumber,
339         int multiplierNonZeroOddNumber,
340         Object object,
341         boolean testTransients,
342         Class reflectUpToClass) {
343 
344         if (object == null) {
345             throw new IllegalArgumentException("The object to build a hash code for must not be null");
346         }
347         HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
348         Class clazz = object.getClass();
349         reflectionAppend(object, clazz, builder, testTransients);
350         while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
351             clazz = clazz.getSuperclass();
352             reflectionAppend(object, clazz, builder, testTransients);
353         }
354         return builder.toHashCode();
355     }
356 
357     /***
358      * <p>Appends the fields and values defined by the given object of the
359      * given <code>Class</code>.</p>
360      * 
361      * @param object  the object to append details of
362      * @param clazz  the class to append details of
363      * @param builder  the builder to append to
364      * @param useTransients  whether to use transient fields
365      */
366     private static void reflectionAppend(Object object, Class clazz, HashCodeBuilder builder, boolean useTransients) {
367         Field[] fields = clazz.getDeclaredFields();
368         AccessibleObject.setAccessible(fields, true);
369         for (int i = 0; i < fields.length; i++) {
370             Field f = fields[i];
371             if ((f.getName().indexOf('$') == -1)
372                 && (useTransients || !Modifier.isTransient(f.getModifiers()))
373                 && (!Modifier.isStatic(f.getModifiers()))) {
374                 try {
375                     builder.append(f.get(object));
376                 } catch (IllegalAccessException e) {
377                     //this can't happen. Would get a Security exception instead
378                     //throw a runtime exception in case the impossible happens.
379                     throw new InternalError("Unexpected IllegalAccessException");
380                 }
381             }
382         }
383     }
384 
385     //-------------------------------------------------------------------------
386 
387     /***
388      * <p>Adds the result of super.hashCode() to this builder.</p>
389      *
390      * @param superHashCode  the result of calling <code>super.hashCode()</code>
391      * @return this HashCodeBuilder, used to chain calls.
392      * @since 2.0
393      */
394     public HashCodeBuilder appendSuper(int superHashCode) {
395         iTotal = iTotal * iConstant + superHashCode;
396         return this;
397     }
398 
399     //-------------------------------------------------------------------------
400 
401     /***
402      * <p>Append a <code>hashCode</code> for an <code>Object</code>.</p>
403      *
404      * @param object  the Object to add to the <code>hashCode</code>
405      * @return this
406      */
407     public HashCodeBuilder append(Object object) {
408         if (object == null) {
409             iTotal = iTotal * iConstant;
410 
411         } else {
412             if (object.getClass().isArray() == false) {
413                 //the simple case, not an array, just the element
414                 iTotal = iTotal * iConstant + object.hashCode();
415 
416             } else {
417                 //'Switch' on type of array, to dispatch to the correct handler
418                 // This handles multi dimensional arrays
419                 if (object instanceof long[]) {
420                     append((long[]) object);
421                 } else if (object instanceof int[]) {
422                     append((int[]) object);
423                 } else if (object instanceof short[]) {
424                     append((short[]) object);
425                 } else if (object instanceof char[]) {
426                     append((char[]) object);
427                 } else if (object instanceof byte[]) {
428                     append((byte[]) object);
429                 } else if (object instanceof double[]) {
430                     append((double[]) object);
431                 } else if (object instanceof float[]) {
432                     append((float[]) object);
433                 } else if (object instanceof boolean[]) {
434                     append((boolean[]) object);
435                 } else {
436                     // Not an array of primitives
437                     append((Object[]) object);
438                 }
439             }
440         }
441         return this;
442     }
443 
444     /***
445      * <p>Append a <code>hashCode</code> for a <code>long</code>.</p>
446      *
447      * @param value  the long to add to the <code>hashCode</code>
448      * @return this
449      */
450     public HashCodeBuilder append(long value) {
451         iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
452         return this;
453     }
454 
455     /***
456      * <p>Append a <code>hashCode</code> for an <code>int</code>.</p>
457      *
458      * @param value  the int to add to the <code>hashCode</code>
459      * @return this
460      */
461     public HashCodeBuilder append(int value) {
462         iTotal = iTotal * iConstant + value;
463         return this;
464     }
465 
466     /***
467      * <p>Append a <code>hashCode</code> for a <code>short</code>.</p>
468      *
469      * @param value  the short to add to the <code>hashCode</code>
470      * @return this
471      */
472     public HashCodeBuilder append(short value) {
473         iTotal = iTotal * iConstant + value;
474         return this;
475     }
476 
477     /***
478      * <p>Append a <code>hashCode</code> for a <code>char</code>.</p>
479      *
480      * @param value  the char to add to the <code>hashCode</code>
481      * @return this
482      */
483     public HashCodeBuilder append(char value) {
484         iTotal = iTotal * iConstant + value;
485         return this;
486     }
487 
488     /***
489      * <p>Append a <code>hashCode</code> for a <code>byte</code>.</p>
490      *
491      * @param value  the byte to add to the <code>hashCode</code>
492      * @return this
493      */
494     public HashCodeBuilder append(byte value) {
495         iTotal = iTotal * iConstant + value;
496         return this;
497     }
498 
499     /***
500      * <p>Append a <code>hashCode</code> for a <code>double</code>.</p>
501      *
502      * @param value  the double to add to the <code>hashCode</code>
503      * @return this
504      */
505     public HashCodeBuilder append(double value) {
506         return append(Double.doubleToLongBits(value));
507     }
508 
509     /***
510      * <p>Append a <code>hashCode</code> for a <code>float</code>.</p>
511      *
512      * @param value  the float to add to the <code>hashCode</code>
513      * @return this
514      */
515     public HashCodeBuilder append(float value) {
516         iTotal = iTotal * iConstant + Float.floatToIntBits(value);
517         return this;
518     }
519 
520     /***
521      * <p>Append a <code>hashCode</code> for a <code>boolean</code>.</p>
522      *
523      * @param value  the boolean to add to the <code>hashCode</code>
524      * @return this
525      */
526     public HashCodeBuilder append(boolean value) {
527         iTotal = iTotal * iConstant + (value ? 0 : 1);
528         return this;
529     }
530 
531     /***
532      * <p>Append a <code>hashCode</code> for an <code>Object</code> array.</p>
533      *
534      * @param array  the array to add to the <code>hashCode</code>
535      * @return this
536      */
537     public HashCodeBuilder append(Object[] array) {
538         if (array == null) {
539             iTotal = iTotal * iConstant;
540         } else {
541             for (int i = 0; i < array.length; i++) {
542                 append(array[i]);
543             }
544         }
545         return this;
546     }
547 
548     /***
549      * <p>Append a <code>hashCode</code> for a <code>long</code> array.</p>
550      *
551      * @param array  the array to add to the <code>hashCode</code>
552      * @return this
553      */
554     public HashCodeBuilder append(long[] array) {
555         if (array == null) {
556             iTotal = iTotal * iConstant;
557         } else {
558             for (int i = 0; i < array.length; i++) {
559                 append(array[i]);
560             }
561         }
562         return this;
563     }
564 
565     /***
566      * <p>Append a <code>hashCode</code> for an <code>int</code> array.</p>
567      *
568      * @param array  the array to add to the <code>hashCode</code>
569      * @return this
570      */
571     public HashCodeBuilder append(int[] array) {
572         if (array == null) {
573             iTotal = iTotal * iConstant;
574         } else {
575             for (int i = 0; i < array.length; i++) {
576                 append(array[i]);
577             }
578         }
579         return this;
580     }
581 
582     /***
583      * <p>Append a <code>hashCode</code> for a <code>short</code> array.</p>
584      *
585      * @param array  the array to add to the <code>hashCode</code>
586      * @return this
587      */
588     public HashCodeBuilder append(short[] array) {
589         if (array == null) {
590             iTotal = iTotal * iConstant;
591         } else {
592             for (int i = 0; i < array.length; i++) {
593                 append(array[i]);
594             }
595         }
596         return this;
597     }
598 
599     /***
600      * <p>Append a <code>hashCode</code> for a <code>char</code> array.</p>
601      *
602      * @param array  the array to add to the <code>hashCode</code>
603      * @return this
604      */
605     public HashCodeBuilder append(char[] array) {
606         if (array == null) {
607             iTotal = iTotal * iConstant;
608         } else {
609             for (int i = 0; i < array.length; i++) {
610                 append(array[i]);
611             }
612         }
613         return this;
614     }
615 
616     /***
617      * <p>Append a <code>hashCode</code> for a <code>byte</code> array.</p>
618      *
619      * @param array  the array to add to the <code>hashCode</code>
620      * @return this
621      */
622     public HashCodeBuilder append(byte[] array) {
623         if (array == null) {
624             iTotal = iTotal * iConstant;
625         } else {
626             for (int i = 0; i < array.length; i++) {
627                 append(array[i]);
628             }
629         }
630         return this;
631     }
632 
633     /***
634      * <p>Append a <code>hashCode</code> for a <code>double</code> array.</p>
635      *
636      * @param array  the array to add to the <code>hashCode</code>
637      * @return this
638      */
639     public HashCodeBuilder append(double[] array) {
640         if (array == null) {
641             iTotal = iTotal * iConstant;
642         } else {
643             for (int i = 0; i < array.length; i++) {
644                 append(array[i]);
645             }
646         }
647         return this;
648     }
649 
650     /***
651      * <p>Append a <code>hashCode</code> for a <code>float</code> array.</p>
652      *
653      * @param array  the array to add to the <code>hashCode</code>
654      * @return this
655      */
656     public HashCodeBuilder append(float[] array) {
657         if (array == null) {
658             iTotal = iTotal * iConstant;
659         } else {
660             for (int i = 0; i < array.length; i++) {
661                 append(array[i]);
662             }
663         }
664         return this;
665     }
666 
667     /***
668      * <p>Append a <code>hashCode</code> for a <code>boolean</code> array.</p>
669      *
670      * @param array  the array to add to the <code>hashCode</code>
671      * @return this
672      */
673     public HashCodeBuilder append(boolean[] array) {
674         if (array == null) {
675             iTotal = iTotal * iConstant;
676         } else {
677             for (int i = 0; i < array.length; i++) {
678                 append(array[i]);
679             }
680         }
681         return this;
682     }
683 
684     /***
685      * <p>Return the computed <code>hashCode</code>.</p>
686      *
687      * @return <code>hashCode</code> based on the fields appended
688      */
689     public int toHashCode() {
690         return iTotal;
691     }
692 
693 }