View Javadoc
1   /*
2    *  jDTAUS Banking API
3    *  Copyright (C) 2005 Christian Schulte
4    *  <cs@schulte.it>
5    *
6    *  This library is free software; you can redistribute it and/or
7    *  modify it under the terms of the GNU Lesser General Public
8    *  License as published by the Free Software Foundation; either
9    *  version 2.1 of the License, or any later version.
10   *
11   *  This library is distributed in the hope that it will be useful,
12   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   *  Lesser General Public License for more details.
15   *
16   *  You should have received a copy of the GNU Lesser General Public
17   *  License along with this library; if not, write to the Free Software
18   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19   *
20   */
21  package org.jdtaus.banking;
22  
23  import java.lang.ref.Reference;
24  import java.lang.ref.SoftReference;
25  import java.text.DecimalFormat;
26  import java.text.ParseException;
27  import java.text.ParsePosition;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.Map;
31  
32  /**
33   * Unique identifier to a particular office (branch) of a german bank.
34   * <p>A Bankleitzahl (BLZ) is a positive integer with a maximum of eight digits. For further information see the
35   * <a href="../../../doc-files/merkblatt_bankleitzahlendatei.pdf">Merkblatt Bankleitzahlendatei</a>. An updated version of the document
36   * may be found at <a href="http://www.bundesbank.de">Deutsche Bundesbank</a>.</p>
37   *
38   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
39   * @version $JDTAUS: Bankleitzahl.java 8725 2012-10-04 21:26:50Z schulte $
40   *
41   * @see BankleitzahlenVerzeichnis
42   */
43  public final class Bankleitzahl extends Number implements Comparable
44  {
45  
46      /**
47       * Constant for the electronic format of a Bankleitzahl.
48       * <p>The electronic format of a Bankleitzahl is an eigth digit number with leading zeros omitted (e.g. 5678).</p>
49       */
50      public static final int ELECTRONIC_FORMAT = 3001;
51  
52      /**
53       * Constant for the letter format of a Bankleitzahl.
54       * <p>The letter format of a Bankleitzahl is an eigth digit number with leading zeros omitted separated by spaces
55       * between the first three digits and the second three digits, and between the second three digits and the last two
56       * digits (e.g. 123 456 78).</p>
57       */
58      public static final int LETTER_FORMAT = 3002;
59  
60      /** Maximum number of digits of a Bankleitzahl. */
61      public static final int MAX_DIGITS = 8;
62  
63      /** Maximum number of characters of a Bankleitzahl. */
64      public static final int MAX_CHARACTERS = 10;
65  
66      /** {@code 10^0..10^7}. */
67      private static final double[] EXP10 =
68      {
69          1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
70      };
71  
72      /** Serial version UID for backwards compatibility with 1.0.x classes. */
73      private static final long serialVersionUID = -3329406998979147668L;
74  
75      /** Used to cache instances. */
76      private static volatile Reference cacheReference = new SoftReference( null );
77  
78      /**
79       * German bank code.
80       * @serial
81       */
82      private int blz;
83  
84      /**
85       * Clearing area code of this Bankleitzahl.
86       * @serial
87       */
88      private int clearingArea;
89  
90      /**
91       * Locality code of this Bankleitzahl.
92       * @serial
93       */
94      private int localityCode;
95  
96      /**
97       * Network code of this Bankleitzahl.
98       * @serial
99       */
100     private int networkCode;
101 
102     /**
103      * Institute code of this Bankleitzahl.
104      * @serial
105      */
106     private int instituteCode;
107 
108     /**
109      * Creates a new {@code Bankleitzahl} instance.
110      *
111      * @param bankCode The integer to create an instance from.
112      *
113      * @throws IllegalArgumentException if {@code bankCode} is negative, zero, greater than 99999999 or its first digit
114      * is either zero or nine.
115      *
116      * @see #checkBankleitzahl(Number)
117      */
118     private Bankleitzahl( final Number bankCode )
119     {
120         if ( !Bankleitzahl.checkBankleitzahl( bankCode ) )
121         {
122             throw new IllegalArgumentException( bankCode.toString() );
123         }
124 
125         final int[] digits = Bankleitzahl.toDigits( bankCode.longValue() );
126         final long lCode = bankCode.longValue();
127 
128         this.clearingArea = digits[7];
129         this.localityCode = (int) Math.floor( lCode / Bankleitzahl.EXP10[5] );
130         this.networkCode = digits[4];
131         this.instituteCode =
132             (int) Math.floor( lCode - digits[7] * Bankleitzahl.EXP10[7] -
133                               digits[6] * Bankleitzahl.EXP10[6] -
134                               digits[5] * Bankleitzahl.EXP10[5] -
135                               digits[4] * Bankleitzahl.EXP10[4] );
136 
137         this.blz = bankCode.intValue();
138     }
139 
140     /**
141      * Parses text from a string to produce a {@code Bankleitzahl}.
142      * <p>The method attempts to parse text starting at the index given by {@code pos}. If parsing succeeds, then the
143      * index of {@code pos} is updated to the index after the last character used (parsing does not necessarily use all
144      * characters up to the end of the string), and the parsed value is returned. The updated {@code pos} can be used to
145      * indicate the starting point for the next call to this method.</p>
146      *
147      * @param bankCode A Bankleitzahl in either electronic or letter format.
148      * @param pos A {@code ParsePosition} object with index and error index information as described above.
149      *
150      * @return The parsed value, or {@code null} if the parse fails.
151      *
152      * @throws NullPointerException if either {@code bankCode} or {@code pos} is {@code null}.
153      */
154     public static Bankleitzahl parse( final String bankCode, final ParsePosition pos )
155     {
156         if ( bankCode == null )
157         {
158             throw new NullPointerException( "bankCode" );
159         }
160         if ( pos == null )
161         {
162             throw new NullPointerException( "pos" );
163         }
164 
165         Bankleitzahl ret = null;
166         boolean sawSpace = false;
167         boolean failed = false;
168         final ParsePosition fmtPos = new ParsePosition( 0 );
169         final int len = bankCode.length();
170         final int startIndex = pos.getIndex();
171         final int maxIndex = startIndex + MAX_CHARACTERS;
172         final StringBuffer digits = new StringBuffer( MAX_DIGITS );
173         int mode = ELECTRONIC_FORMAT;
174         int part = 0;
175         int partStart = 0;
176         int partEnd = 2;
177         int digit = 0;
178         int i = startIndex;
179 
180         for ( ; i < len && i < maxIndex && digits.length() < MAX_DIGITS; i++ )
181         {
182             final char c = bankCode.charAt( i );
183 
184             if ( Character.isDigit( c ) )
185             {
186                 sawSpace = false;
187 
188                 if ( mode == LETTER_FORMAT )
189                 {
190                     if ( digit < partStart || digit > partEnd )
191                     {
192                         failed = true;
193                     }
194                     else
195                     {
196                         digits.append( c );
197                     }
198                 }
199                 else
200                 {
201                     digits.append( c );
202                 }
203 
204                 digit++;
205             }
206             else if ( c == ' ' )
207             {
208                 if ( sawSpace || i == startIndex || ( mode == ELECTRONIC_FORMAT && digit != 3 ) )
209                 {
210                     failed = true;
211                 }
212                 else
213                 {
214                     mode = LETTER_FORMAT;
215                     switch ( part )
216                     {
217                         case 0:
218                             partStart = 3;
219                             partEnd = 5;
220                             break;
221                         case 1:
222                             partStart = 6;
223                             partEnd = 7;
224                             break;
225                         default:
226                             failed = true;
227                             break;
228                     }
229                     part++;
230 
231                     if ( digit < partStart || digit > partEnd )
232                     {
233                         failed = true;
234                     }
235                 }
236 
237                 sawSpace = true;
238             }
239             else
240             {
241                 failed = true;
242             }
243 
244             if ( failed )
245             {
246                 pos.setErrorIndex( i );
247                 break;
248             }
249         }
250 
251         if ( !failed )
252         {
253             final Number num = new DecimalFormat( "########" ).parse( digits.toString(), fmtPos );
254 
255             if ( num != null && fmtPos.getErrorIndex() == -1 )
256             {
257                 final String key = num.toString();
258                 ret = (Bankleitzahl) getCache().get( key );
259 
260                 if ( ret == null )
261                 {
262                     if ( !Bankleitzahl.checkBankleitzahl( num ) )
263                     {
264                         pos.setErrorIndex( startIndex );
265                         ret = null;
266                     }
267                     else
268                     {
269                         pos.setIndex( i );
270                         ret = new Bankleitzahl( num );
271                         getCache().put( key, ret );
272                     }
273                 }
274                 else
275                 {
276                     pos.setIndex( i );
277                 }
278             }
279             else
280             {
281                 pos.setErrorIndex( startIndex );
282             }
283         }
284 
285         return ret;
286     }
287 
288     /**
289      * Parses text from the beginning of the given string to produce a {@code Bankleitzahl}.
290      * <p>Unlike the {@link #parse(String, ParsePosition)} method this method throws a {@code ParseException} if
291      * {@code bankCode} cannot be parsed or is of invalid length.</p>
292      *
293      * @param bankCode A Bankleitzahl in either electronic or letter format.
294      *
295      * @return The parsed value.
296      *
297      * @throws NullPointerException if {@code bankCode} is {@code null}.
298      * @throws ParseException if the parse fails or {@code bankCode} is of invalid length.
299      */
300     public static Bankleitzahl parse( final String bankCode ) throws ParseException
301     {
302         if ( bankCode == null )
303         {
304             throw new NullPointerException( "bankCode" );
305         }
306 
307         Bankleitzahl blz = (Bankleitzahl) getCache().get( bankCode );
308 
309         if ( blz == null )
310         {
311             final ParsePosition pos = new ParsePosition( 0 );
312             blz = Bankleitzahl.parse( bankCode, pos );
313 
314             if ( blz == null || pos.getErrorIndex() != -1 || pos.getIndex() < bankCode.length() )
315             {
316                 throw new ParseException( bankCode, pos.getErrorIndex() != -1 ? pos.getErrorIndex() : pos.getIndex() );
317             }
318             else
319             {
320                 getCache().put( bankCode, blz );
321             }
322         }
323 
324         return blz;
325     }
326 
327     /**
328      * Gets a {@code Bankleitzahl} for a given number.
329      *
330      * @param bankCode A number to get a {@code Bankleitzahl} for.
331      *
332      * @return An instance for {@code bankCode}.
333      *
334      * @throws NullPointerException if {@code bankCode} is {@code null}.
335      * @throws IllegalArgumentException if {@code bankCode} is negative, zero, greater than 99999999 or its first digit
336      * is either zero or nine.
337      *
338      * @see #checkBankleitzahl(Number)
339      */
340     public static Bankleitzahl valueOf( final Number bankCode )
341     {
342         if ( bankCode == null )
343         {
344             throw new NullPointerException( "bankCode" );
345         }
346 
347         final String key = bankCode.toString();
348         Bankleitzahl ret = (Bankleitzahl) getCache().get( key );
349 
350         if ( ret == null )
351         {
352             ret = new Bankleitzahl( bankCode );
353             getCache().put( key, ret );
354         }
355 
356         return ret;
357     }
358 
359     /**
360      * Parses text from the beginning of the given string to produce a {@code Bankleitzahl}.
361      * <p>Unlike the {@link #parse(String)} method this method throws an {@code IllegalArgumentException} if
362      * {@code bankCode} cannot be parsed or is of invalid length.</p>
363      *
364      * @param bankCode A Bankleitzahl in either electronic or letter format.
365      *
366      * @return The parsed value.
367      *
368      * @throws NullPointerException if {@code bankCode} is {@code null}.
369      * @throws IllegalArgumentException if the parse fails or {@code bankCode} is of invalid length.
370      */
371     public static Bankleitzahl valueOf( final String bankCode )
372     {
373         try
374         {
375             return Bankleitzahl.parse( bankCode );
376         }
377         catch ( final ParseException e )
378         {
379             throw (IllegalArgumentException) new IllegalArgumentException( bankCode ).initCause( e );
380         }
381     }
382 
383     /**
384      * Checks a given number to conform to a Bankleitzahl.
385      *
386      * @param bankCode The number to check.
387      *
388      * @return {@code true} if {@code bankCode} is a valid Bankleitzahl; {@code false} if not.
389      */
390     public static boolean checkBankleitzahl( final Number bankCode )
391     {
392         boolean valid = bankCode != null;
393 
394         if ( valid )
395         {
396             final long num = bankCode.longValue();
397             valid = num > 0L && num < 100000000L;
398             if ( valid && num > 9999999 )
399             {
400                 final int[] digits = Bankleitzahl.toDigits( num );
401                 valid = digits[7] != 0 && digits[7] != 9;
402             }
403         }
404 
405         return valid;
406     }
407 
408     /**
409      * Returns this Bankleitzahl as an int value.
410      *
411      * @return This Bankleitzahl as an int value.
412      */
413     public int intValue()
414     {
415         return this.blz;
416     }
417 
418     /**
419      * Returns this Bankleitzahl as a long value.
420      *
421      * @return This Bankleitzahl as a long value.
422      */
423     public long longValue()
424     {
425         return this.blz;
426     }
427 
428     /**
429      * Returns this Bankleitzahl as a float value.
430      *
431      * @return This Bankleitzahl as a float value.
432      */
433     public float floatValue()
434     {
435         return this.blz;
436     }
437 
438     /**
439      * Returns this Bankleitzahl as a double value.
440      *
441      * @return This Bankleitzahl as a double value.
442      */
443     public double doubleValue()
444     {
445         return this.blz;
446     }
447 
448     /**
449      * Gets a flag indicating that this Bankleitzahl provides a clearing area code.
450      *
451      * @return {@code true} if property {@code clearingAreaCode} is supported by this instance; {@code false} if
452      * property {@code clearingAreaCode} is not supported by this instance.
453      *
454      * @see #getClearingAreaCode()
455      */
456     public boolean isClearingAreaCodeSupported()
457     {
458         return this.blz > 9999999;
459     }
460 
461     /**
462      * Gets the clearing area code of this Bankleitzahl.
463      * <p><ol>
464      * <li>Berlin, Brandenburg, Mecklenburg-Vorpommern</li>
465      * <li>Bremen, Hamburg, Niedersachsen, Schleswig-Holstein</li>
466      * <li>Rheinland (Regierungsbezirke Düsseldorf, Köln)</li>
467      * <li>Westfalen</li>
468      * <li>Hessen, Rheinland-Pfalz, Saarland</li>
469      * <li>Baden-Württemberg</li>
470      * <li>Bayern</li>
471      * <li>Sachsen, Sachsen-Anhalt, Thüringen</li>
472      * </ol></p>
473      *
474      * @return Code identifying the clearing area of this Bankleitzahl.
475      *
476      * @throws UnsupportedOperationException if this Bankleitzahl does not provide clearing area information.
477      *
478      * @see #isClearingAreaCodeSupported()
479      *
480      * @deprecated Renamed to {@link #getClearingAreaCode() }.
481      */
482     public int getClearingArea()
483     {
484         return this.getClearingAreaCode();
485     }
486 
487     /**
488      * Gets the clearing area code of this Bankleitzahl.
489      * <p><ol>
490      * <li>Berlin, Brandenburg, Mecklenburg-Vorpommern</li>
491      * <li>Bremen, Hamburg, Niedersachsen, Schleswig-Holstein</li>
492      * <li>Rheinland (Regierungsbezirke Düsseldorf, Köln)</li>
493      * <li>Westfalen</li>
494      * <li>Hessen, Rheinland-Pfalz, Saarland</li>
495      * <li>Baden-Württemberg</li>
496      * <li>Bayern</li>
497      * <li>Sachsen, Sachsen-Anhalt, Thüringen</li>
498      * </ol></p>
499      *
500      * @return Code identifying the clearing area of this Bankleitzahl.
501      *
502      * @throws UnsupportedOperationException if this Bankleitzahl does not provide clearing area information.
503      *
504      * @see #isClearingAreaCodeSupported()
505      */
506     public int getClearingAreaCode()
507     {
508         if ( !this.isClearingAreaCodeSupported() )
509         {
510             throw new UnsupportedOperationException();
511         }
512 
513         return this.clearingArea;
514     }
515 
516     /**
517      * Gets a flag indicating that this Bankleitzahl provides a locality code.
518      *
519      * @return {@code true} if property {@code localityCode} is supported by this instance; {@code false} if property
520      * {@code localityCode} is not supported by this instance.
521      *
522      * @see #getLocalityCode()
523      */
524     public boolean isLocalityCodeSupported()
525     {
526         return this.blz > 99999;
527     }
528 
529     /**
530      * Gets the locality code of this Bankleitzahl.
531      *
532      * @return Locality code of this Bankleitzahl.
533      *
534      * @throws UnsupportedOperationException if this Bankleitzahl does not provide a locality code.
535      *
536      * @see #isLocalityCodeSupported()
537      */
538     public int getLocalityCode()
539     {
540         if ( !this.isLocalityCodeSupported() )
541         {
542             throw new UnsupportedOperationException();
543         }
544 
545         return this.localityCode;
546     }
547 
548     /**
549      * Gets a flag indicating that this Bankleitzahl provides a network code.
550      *
551      * @return {@code true} if property {@code networkCode} is supported by this instance; {@code false} if property
552      * {@code networkCode} is not supported by this instance.
553      *
554      * @see #getNetworkCode()
555      */
556     public boolean isNetworkCodeSupported()
557     {
558         return this.blz > 9999;
559     }
560 
561     /**
562      * Gets the network code of this Bankleitzahl.
563      * <p><table border="0">
564      * <tr>
565      *   <td>0</td>
566      *   <td>Deutsche Bundesbank</td>
567      * </tr>
568      * <tr>
569      *   <td>1 - 3</td>
570      *   <td>
571      * Kreditinstitute, soweit nicht in einer der anderen Gruppen erfasst
572      *   </td>
573      * </tr>
574      * <tr>
575      *   <td>4</td>
576      *   <td>Commerzbank</td>
577      * </tr>
578      * <tr>
579      *   <td>5</td>
580      *   <td>Girozentralen und Sparkassen</td>
581      * </tr>
582      * <tr>
583      *   <td>6 + 9</td>
584      *   <td>
585      * Genossenschaftliche Zentralbanken, Kreditgenossenschaften sowie ehemalige
586      * Genossenschaften
587      *   </td>
588      * </tr>
589      * <tr>
590      *   <td>7</td>
591      *   <td>Deutsche Bank</td>
592      * </tr>
593      * <tr>
594      *   <td>8</td>
595      *   <td>Dresdner Bank</td>
596      * </tr>
597      * </table></p>
598      *
599      * @return Network code of this Bankleitzahl.
600      *
601      * @throws UnsupportedOperationException if this Bankleitzahl does not provide a network code.
602      *
603      * @see #isNetworkCodeSupported()
604      */
605     public int getNetworkCode()
606     {
607         if ( !this.isNetworkCodeSupported() )
608         {
609             throw new UnsupportedOperationException();
610         }
611 
612         return this.networkCode;
613     }
614 
615     /**
616      * Gets the institute code of this Bankleitzahl.
617      *
618      * @return Institute code of this Bankleitzahl.
619      */
620     public int getInstituteCode()
621     {
622         return this.instituteCode;
623     }
624 
625     /**
626      * Formats a Bankleitzahl and appends the resulting text to the given string buffer.
627      *
628      * @param style The style to use ({@code ELECTRONIC_FORMAT} or {@code LETTER_FORMAT}).
629      * @param toAppendTo The buffer to which the formatted text is to be appended.
630      *
631      * @return The value passed in as {@code toAppendTo}.
632      *
633      * @throws NullPointerException if {@code toAppendTo} is {@code null}.
634      * @throws IllegalArgumentException if {@code style} is neither {@code ELECTRONIC_FORMAT} nor {@code LETTER_FORMAT}.
635      *
636      * @see #ELECTRONIC_FORMAT
637      * @see #LETTER_FORMAT
638      */
639     public StringBuffer format( final int style, final StringBuffer toAppendTo )
640     {
641         if ( toAppendTo == null )
642         {
643             throw new NullPointerException( "toAppendTo" );
644         }
645         if ( style != Bankleitzahl.ELECTRONIC_FORMAT && style != Bankleitzahl.LETTER_FORMAT )
646         {
647             throw new IllegalArgumentException( Integer.toString( style ) );
648         }
649 
650         final int[] digits = Bankleitzahl.toDigits( this.blz );
651         for ( int i = digits.length - 1, lastDigit = 0; i >= 0; i-- )
652         {
653             if ( digits[i] != 0 || lastDigit > 0 )
654             {
655                 toAppendTo.append( digits[i] );
656                 lastDigit++;
657             }
658 
659             if ( style == Bankleitzahl.LETTER_FORMAT && ( lastDigit == 3 || lastDigit == 6 ) )
660             {
661                 toAppendTo.append( ' ' );
662             }
663         }
664 
665         return toAppendTo;
666     }
667 
668     /**
669      * Formats a Bankleitzahl to produce a string. Same as
670      * <blockquote>
671      * {@link #format(int, StringBuffer) format<code>(style, new StringBuffer()).toString()</code>}
672      * </blockquote>
673      *
674      * @param style The style to use ({@code ELECTRONIC_FORMAT} or {@code LETTER_FORMAT}).
675      *
676      * @return The formatted string.
677      *
678      * @throws IllegalArgumentException if {@code style} is neither {@code ELECTRONIC_FORMAT} nor {@code LETTER_FORMAT}.
679      *
680      * @see #ELECTRONIC_FORMAT
681      * @see #LETTER_FORMAT
682      */
683     public String format( final int style )
684     {
685         return this.format( style, new StringBuffer() ).toString();
686     }
687 
688     /**
689      * Formats a Bankleitzahl to produce a string. Same as
690      * <blockquote>
691      * {@link #format(int) bankleitzahl.format(ELECTRONIC_FORMAT)}
692      * </blockquote>
693      *
694      * @param bankleitzahl The {@code Bankleitzahl} instance to format.
695      *
696      * @return The formatted string.
697      *
698      * @throws NullPointerException if {@code bankleitzahl} is {@code null}.
699      */
700     public static String toString( final Bankleitzahl bankleitzahl )
701     {
702         if ( bankleitzahl == null )
703         {
704             throw new NullPointerException( "bankleitzahl" );
705         }
706 
707         return bankleitzahl.format( ELECTRONIC_FORMAT );
708     }
709 
710     /**
711      * Creates an array holding the digits of {@code number}.
712      *
713      * @param number The number to return the digits for.
714      *
715      * @return An array holding the digits of {@code number}.
716      */
717     private static int[] toDigits( final long number )
718     {
719         int i;
720         int j;
721         int subst;
722         final int[] ret = new int[ MAX_DIGITS ];
723 
724         for ( i = MAX_DIGITS - 1; i >= 0; i-- )
725         {
726             for ( j = i + 1, subst = 0; j < MAX_DIGITS; j++ )
727             {
728                 subst += ret[j] * EXP10[j];
729             }
730             ret[i] = (int) Math.floor( ( number - subst ) / EXP10[i] );
731         }
732 
733         return ret;
734     }
735 
736     /**
737      * Creates a string representing the properties of the instance.
738      *
739      * @return A string representing the properties of the instance.
740      */
741     private String internalString()
742     {
743         return new StringBuffer( 500 ).append( '{' ).
744             append( "blz=" ).append( this.blz ).
745             append( ", clearingAreaCodeSupported=" ).
746             append( this.isClearingAreaCodeSupported() ).
747             append( ", clearingArea=" ).append( this.clearingArea ).
748             append( ", instituteCode=" ).append( this.instituteCode ).
749             append( ", localityCodeSupported=" ).
750             append( this.isLocalityCodeSupported() ).
751             append( ", localityCode=" ).append( this.localityCode ).
752             append( ", networkCodeSupported=" ).
753             append( this.isNetworkCodeSupported() ).
754             append( ", networkCode=" ).append( this.networkCode ).
755             append( '}' ).toString();
756 
757     }
758 
759     /**
760      * Gets the current cache instance.
761      *
762      * @return Current cache instance.
763      */
764     private static Map getCache()
765     {
766         Map cache = (Map) cacheReference.get();
767         if ( cache == null )
768         {
769             cache = Collections.synchronizedMap( new HashMap( 1024 ) );
770             cacheReference = new SoftReference( cache );
771         }
772 
773         return cache;
774     }
775 
776     /**
777      * Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer
778      * as this object is less than, equal to, or greater than the specified object.<p>
779      *
780      * @param o The Object to be compared.
781      * @return A negative integer, zero, or a positive integer as this object is less than, equal to, or greater than
782      * the specified object.
783      *
784      * @throws NullPointerException if {@code o} is {@code null}.
785      * @throws ClassCastException if the specified object's type prevents it from being compared to this Object.
786      */
787     public int compareTo( final Object o )
788     {
789         if ( o == null )
790         {
791             throw new NullPointerException( "o" );
792         }
793         if ( !( o instanceof Bankleitzahl ) )
794         {
795             throw new ClassCastException( o.getClass().getName() );
796         }
797 
798         int result = 0;
799         final Bankleitzahl that = (Bankleitzahl) o;
800 
801         if ( !this.equals( that ) )
802         {
803             result = this.blz > that.blz
804                      ? 1
805                      : -1;
806         }
807 
808         return result;
809     }
810 
811     /**
812      * Indicates whether some other object is equal to this one.
813      *
814      * @param o The reference object with which to compare.
815      *
816      * @return {@code true} if this object is the same as {@code o}; {@code false} otherwise.
817      */
818     public boolean equals( final Object o )
819     {
820         boolean equal = o == this;
821 
822         if ( !equal && o instanceof Bankleitzahl )
823         {
824             equal = this.blz == ( (Bankleitzahl) o ).blz;
825         }
826 
827         return equal;
828     }
829 
830     /**
831      * Returns a hash code value for this object.
832      *
833      * @return A hash code value for this object.
834      */
835     public int hashCode()
836     {
837         return this.blz;
838     }
839 
840     /**
841      * Returns a string representation of the object.
842      *
843      * @return A string representation of the object.
844      */
845     public String toString()
846     {
847         return super.toString() + this.internalString();
848     }
849 
850 }