All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdtaus.banking.Bankleitzahl Maven / Gradle / Ivy

There is a newer version: 1.16
Show newest version
/*
 *  jDTAUS Banking API
 *  Copyright (c) 2005 Christian Schulte
 *
 *  Christian Schulte, Haldener Strasse 72, 58095 Hagen, Germany
 *   (+49 2331 3543887)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
package org.jdtaus.banking;

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Unique identifier to a particular office (branch) of a german bank.
 * 

A Bankleitzahl (BLZ) is a positive integer with a maximum of eight digits. For further information see the * * Bankleitzahlen Richtlinie. An updated version of the document may be found at * Deutsche Bundesbank.

* * @author Christian Schulte * @version $Id: Bankleitzahl.java 8322 2009-12-03 22:59:51Z schulte2005 $ * * @see BankleitzahlenVerzeichnis */ public final class Bankleitzahl extends Number implements Comparable { /** * Constant for the electronic format of a Bankleitzahl. *

The electronic format of a Bankleitzahl is an eigth digit number with leading zeros omitted (e.g. 5678).

*/ public static final int ELECTRONIC_FORMAT = 3001; /** * Constant for the letter format of a Bankleitzahl. *

The letter format of a Bankleitzahl is an eigth digit number with leading zeros omitted separated by spaces * between the first three digits and the second three digits, and between the second three digits and the last two * digits (e.g. 123 456 78).

*/ public static final int LETTER_FORMAT = 3002; /** Maximum number of digits of a Bankleitzahl. */ public static final int MAX_DIGITS = 8; /** Maximum number of characters of a Bankleitzahl. */ public static final int MAX_CHARACTERS = 10; /** {@code 10^0..10^7}. */ private static final double[] EXP10 = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; /** Serial version UID for backwards compatibility with 1.0.x classes. */ private static final long serialVersionUID = -3329406998979147668L; /** Used to cache instances. */ private static volatile Reference cacheReference = new SoftReference( null ); /** * German bank code. * @serial */ private int blz; /** * Clearing area code of this Bankleitzahl. * @serial */ private int clearingArea; /** * Locality code of this Bankleitzahl. * @serial */ private int localityCode; /** * Network code of this Bankleitzahl. * @serial */ private int networkCode; /** * Institute code of this Bankleitzahl. * @serial */ private int instituteCode; /** * Creates a new {@code Bankleitzahl} instance. * * @param bankCode The integer to create an instance from. * * @throws IllegalArgumentException if {@code bankCode} is negative, zero, greater than 99999999 or its first digit * is either zero or nine. * * @see #checkBankleitzahl(Number) */ private Bankleitzahl( final Number bankCode ) { if ( !Bankleitzahl.checkBankleitzahl( bankCode ) ) { throw new IllegalArgumentException( bankCode.toString() ); } final int[] digits = Bankleitzahl.toDigits( bankCode.longValue() ); final long lCode = bankCode.longValue(); this.clearingArea = digits[7]; this.localityCode = (int) Math.floor( lCode / Bankleitzahl.EXP10[5] ); this.networkCode = digits[4]; this.instituteCode = (int) Math.floor( lCode - digits[7] * Bankleitzahl.EXP10[7] - digits[6] * Bankleitzahl.EXP10[6] - digits[5] * Bankleitzahl.EXP10[5] - digits[4] * Bankleitzahl.EXP10[4] ); this.blz = bankCode.intValue(); } /** * Parses text from a string to produce a {@code Bankleitzahl}. *

The method attempts to parse text starting at the index given by {@code pos}. If parsing succeeds, then the * index of {@code pos} is updated to the index after the last character used (parsing does not necessarily use all * characters up to the end of the string), and the parsed value is returned. The updated {@code pos} can be used to * indicate the starting point for the next call to this method.

* * @param bankCode A Bankleitzahl in either electronic or letter format. * @param pos A {@code ParsePosition} object with index and error index information as described above. * * @return The parsed value, or {@code null} if the parse fails. * * @throws NullPointerException if either {@code bankCode} or {@code pos} is {@code null}. */ public static Bankleitzahl parse( final String bankCode, final ParsePosition pos ) { if ( bankCode == null ) { throw new NullPointerException( "bankCode" ); } if ( pos == null ) { throw new NullPointerException( "pos" ); } Bankleitzahl ret = null; boolean sawSpace = false; boolean failed = false; final ParsePosition fmtPos = new ParsePosition( 0 ); final int len = bankCode.length(); final int startIndex = pos.getIndex(); final int maxIndex = startIndex + MAX_CHARACTERS; final StringBuffer digits = new StringBuffer( MAX_DIGITS ); int mode = ELECTRONIC_FORMAT; int part = 0; int partStart = 0; int partEnd = 2; int digit = 0; int i = startIndex; for ( ; i < len && i < maxIndex && digits.length() < MAX_DIGITS; i++ ) { final char c = bankCode.charAt( i ); if ( Character.isDigit( c ) ) { sawSpace = false; if ( mode == LETTER_FORMAT ) { if ( digit < partStart || digit > partEnd ) { failed = true; } else { digits.append( c ); } } else { digits.append( c ); } digit++; } else if ( c == ' ' ) { if ( sawSpace || i == startIndex || ( mode == ELECTRONIC_FORMAT && digit != 3 ) ) { failed = true; } else { mode = LETTER_FORMAT; switch ( part ) { case 0: partStart = 3; partEnd = 5; break; case 1: partStart = 6; partEnd = 7; break; default: failed = true; break; } part++; if ( digit < partStart || digit > partEnd ) { failed = true; } } sawSpace = true; } else { failed = true; } if ( failed ) { pos.setErrorIndex( i ); break; } } if ( !failed ) { final Number num = new DecimalFormat( "########" ).parse( digits.toString(), fmtPos ); if ( num != null && fmtPos.getErrorIndex() == -1 ) { final String key = num.toString(); ret = (Bankleitzahl) getCache().get( key ); if ( ret == null ) { if ( !Bankleitzahl.checkBankleitzahl( num ) ) { pos.setErrorIndex( startIndex ); ret = null; } else { pos.setIndex( i ); ret = new Bankleitzahl( num ); getCache().put( key, ret ); } } else { pos.setIndex( i ); } } else { pos.setErrorIndex( startIndex ); } } return ret; } /** * Parses text from the beginning of the given string to produce a {@code Bankleitzahl}. *

Unlike the {@link #parse(String, ParsePosition)} method this method throws a {@code ParseException} if * {@code bankCode} cannot be parsed or is of invalid length.

* * @param bankCode A Bankleitzahl in either electronic or letter format. * * @return The parsed value. * * @throws NullPointerException if {@code bankCode} is {@code null}. * @throws ParseException if the parse fails or {@code bankCode} is of invalid length. */ public static Bankleitzahl parse( final String bankCode ) throws ParseException { if ( bankCode == null ) { throw new NullPointerException( "bankCode" ); } Bankleitzahl blz = (Bankleitzahl) getCache().get( bankCode ); if ( blz == null ) { final ParsePosition pos = new ParsePosition( 0 ); blz = Bankleitzahl.parse( bankCode, pos ); if ( blz == null || pos.getErrorIndex() != -1 || pos.getIndex() < bankCode.length() ) { throw new ParseException( bankCode, pos.getErrorIndex() != -1 ? pos.getErrorIndex() : pos.getIndex() ); } else { getCache().put( bankCode, blz ); } } return blz; } /** * Gets a {@code Bankleitzahl} for a given number. * * @param bankCode A number to get a {@code Bankleitzahl} for. * * @return An instance for {@code bankCode}. * * @throws NullPointerException if {@code bankCode} is {@code null}. * @throws IllegalArgumentException if {@code bankCode} is negative, zero, greater than 99999999 or its first digit * is either zero or nine. * * @see #checkBankleitzahl(Number) */ public static Bankleitzahl valueOf( final Number bankCode ) { if ( bankCode == null ) { throw new NullPointerException( "bankCode" ); } final String key = bankCode.toString(); Bankleitzahl ret = (Bankleitzahl) getCache().get( key ); if ( ret == null ) { ret = new Bankleitzahl( bankCode ); getCache().put( key, ret ); } return ret; } /** * Parses text from the beginning of the given string to produce a {@code Bankleitzahl}. *

Unlike the {@link #parse(String)} method this method throws an {@code IllegalArgumentException} if * {@code bankCode} cannot be parsed or is of invalid length.

* * @param bankCode A Bankleitzahl in either electronic or letter format. * * @return The parsed value. * * @throws NullPointerException if {@code bankCode} is {@code null}. * @throws IllegalArgumentException if the parse fails or {@code bankCode} is of invalid length. */ public static Bankleitzahl valueOf( final String bankCode ) { try { return Bankleitzahl.parse( bankCode ); } catch ( final ParseException e ) { throw (IllegalArgumentException) new IllegalArgumentException( bankCode ).initCause( e ); } } /** * Checks a given number to conform to a Bankleitzahl. * * @param bankCode The number to check. * * @return {@code true} if {@code bankCode} is a valid Bankleitzahl; {@code false} if not. */ public static boolean checkBankleitzahl( final Number bankCode ) { boolean valid = bankCode != null; if ( valid ) { final long num = bankCode.longValue(); valid = num > 0L && num < 100000000L; if ( valid && num > 9999999 ) { final int[] digits = Bankleitzahl.toDigits( num ); valid = digits[7] != 0 && digits[7] != 9; } } return valid; } /** * Returns this Bankleitzahl as an int value. * * @return This Bankleitzahl as an int value. */ public int intValue() { return this.blz; } /** * Returns this Bankleitzahl as a long value. * * @return This Bankleitzahl as a long value. */ public long longValue() { return this.blz; } /** * Returns this Bankleitzahl as a float value. * * @return This Bankleitzahl as a float value. */ public float floatValue() { return this.blz; } /** * Returns this Bankleitzahl as a double value. * * @return This Bankleitzahl as a double value. */ public double doubleValue() { return this.blz; } /** * Gets a flag indicating that this Bankleitzahl provides a clearing area code. * * @return {@code true} if property {@code clearingAreaCode} is supported by this instance; {@code false} if * property {@code clearingAreaCode} is not supported by this instance. * * @see #getClearingAreaCode() */ public boolean isClearingAreaCodeSupported() { return this.blz > 9999999; } /** * Gets the clearing area code of this Bankleitzahl. *

    *
  1. Berlin, Brandenburg, Mecklenburg-Vorpommern
  2. *
  3. Bremen, Hamburg, Niedersachsen, Schleswig-Holstein
  4. *
  5. Rheinland (Regierungsbezirke Düsseldorf, Köln)
  6. *
  7. Westfalen
  8. *
  9. Hessen, Rheinland-Pfalz, Saarland
  10. *
  11. Baden-Württemberg
  12. *
  13. Bayern
  14. *
  15. Sachsen, Sachsen-Anhalt, Thüringen
  16. *

* * @return Code identifying the clearing area of this Bankleitzahl. * * @throws UnsupportedOperationException if this Bankleitzahl does not provide clearing area information. * * @see #isClearingAreaCodeSupported() * * @deprecated Renamed to {@link #getClearingAreaCode() }. */ public int getClearingArea() { return this.getClearingAreaCode(); } /** * Gets the clearing area code of this Bankleitzahl. *

    *
  1. Berlin, Brandenburg, Mecklenburg-Vorpommern
  2. *
  3. Bremen, Hamburg, Niedersachsen, Schleswig-Holstein
  4. *
  5. Rheinland (Regierungsbezirke Düsseldorf, Köln)
  6. *
  7. Westfalen
  8. *
  9. Hessen, Rheinland-Pfalz, Saarland
  10. *
  11. Baden-Württemberg
  12. *
  13. Bayern
  14. *
  15. Sachsen, Sachsen-Anhalt, Thüringen
  16. *

* * @return Code identifying the clearing area of this Bankleitzahl. * * @throws UnsupportedOperationException if this Bankleitzahl does not provide clearing area information. * * @see #isClearingAreaCodeSupported() */ public int getClearingAreaCode() { if ( !this.isClearingAreaCodeSupported() ) { throw new UnsupportedOperationException(); } return this.clearingArea; } /** * Gets a flag indicating that this Bankleitzahl provides a locality code. * * @return {@code true} if property {@code localityCode} is supported by this instance; {@code false} if property * {@code localityCode} is not supported by this instance. * * @see #getLocalityCode() */ public boolean isLocalityCodeSupported() { return this.blz > 99999; } /** * Gets the locality code of this Bankleitzahl. * * @return Locality code of this Bankleitzahl. * * @throws UnsupportedOperationException if this Bankleitzahl does not provide a locality code. * * @see #isLocalityCodeSupported() */ public int getLocalityCode() { if ( !this.isLocalityCodeSupported() ) { throw new UnsupportedOperationException(); } return this.localityCode; } /** * Gets a flag indicating that this Bankleitzahl provides a network code. * * @return {@code true} if property {@code networkCode} is supported by this instance; {@code false} if property * {@code networkCode} is not supported by this instance. * * @see #getNetworkCode() */ public boolean isNetworkCodeSupported() { return this.blz > 9999; } /** * Gets the network code of this Bankleitzahl. *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * *
0Deutsche Bundesbank
1 - 3 * Kreditinstitute, soweit nicht in einer der anderen Gruppen erfasst *
4Commerzbank
5Girozentralen und Sparkassen
6 + 9 * Genossenschaftliche Zentralbanken, Kreditgenossenschaften sowie ehemalige * Genossenschaften *
7Deutsche Bank
8Dresdner Bank

* * @return Network code of this Bankleitzahl. * * @throws UnsupportedOperationException if this Bankleitzahl does not provide a network code. * * @see #isNetworkCodeSupported() */ public int getNetworkCode() { if ( !this.isNetworkCodeSupported() ) { throw new UnsupportedOperationException(); } return this.networkCode; } /** * Gets the institute code of this Bankleitzahl. * * @return Institute code of this Bankleitzahl. */ public int getInstituteCode() { return this.instituteCode; } /** * Formats a Bankleitzahl and appends the resulting text to the given string buffer. * * @param style The style to use ({@code ELECTRONIC_FORMAT} or {@code LETTER_FORMAT}). * @param toAppendTo The buffer to which the formatted text is to be appended. * * @return The value passed in as {@code toAppendTo}. * * @throws NullPointerException if {@code toAppendTo} is {@code null}. * @throws IllegalArgumentException if {@code style} is neither {@code ELECTRONIC_FORMAT} nor {@code LETTER_FORMAT}. * * @see #ELECTRONIC_FORMAT * @see #LETTER_FORMAT */ public StringBuffer format( final int style, final StringBuffer toAppendTo ) { if ( toAppendTo == null ) { throw new NullPointerException( "toAppendTo" ); } if ( style != Bankleitzahl.ELECTRONIC_FORMAT && style != Bankleitzahl.LETTER_FORMAT ) { throw new IllegalArgumentException( Integer.toString( style ) ); } final int[] digits = Bankleitzahl.toDigits( this.blz ); for ( int i = digits.length - 1, lastDigit = 0; i >= 0; i-- ) { if ( digits[i] != 0 || lastDigit > 0 ) { toAppendTo.append( digits[i] ); lastDigit++; } if ( style == Bankleitzahl.LETTER_FORMAT && ( lastDigit == 3 || lastDigit == 6 ) ) { toAppendTo.append( ' ' ); } } return toAppendTo; } /** * Formats a Bankleitzahl to produce a string. Same as *
* {@link #format(int, StringBuffer) format(style, new StringBuffer()).toString()} *
* * @param style The style to use ({@code ELECTRONIC_FORMAT} or {@code LETTER_FORMAT}). * * @return The formatted string. * * @throws IllegalArgumentException if {@code style} is neither {@code ELECTRONIC_FORMAT} nor {@code LETTER_FORMAT}. * * @see #ELECTRONIC_FORMAT * @see #LETTER_FORMAT */ public String format( final int style ) { return this.format( style, new StringBuffer() ).toString(); } /** * Formats a Bankleitzahl to produce a string. Same as *
* {@link #format(int) bankleitzahl.format(ELECTRONIC_FORMAT)} *
* * @param bankleitzahl The {@code Bankleitzahl} instance to format. * * @return The formatted string. * * @throws NullPointerException if {@code bankleitzahl} is {@code null}. */ public static String toString( final Bankleitzahl bankleitzahl ) { if ( bankleitzahl == null ) { throw new NullPointerException( "bankleitzahl" ); } return bankleitzahl.format( ELECTRONIC_FORMAT ); } /** * Creates an array holding the digits of {@code number}. * * @param number The number to return the digits for. * * @return An array holding the digits of {@code number}. */ private static int[] toDigits( final long number ) { int i; int j; int subst; final int[] ret = new int[ MAX_DIGITS ]; for ( i = MAX_DIGITS - 1; i >= 0; i-- ) { for ( j = i + 1, subst = 0; j < MAX_DIGITS; j++ ) { subst += ret[j] * EXP10[j]; } ret[i] = (int) Math.floor( ( number - subst ) / EXP10[i] ); } return ret; } /** * Creates a string representing the properties of the instance. * * @return A string representing the properties of the instance. */ private String internalString() { return new StringBuffer( 500 ).append( '{' ). append( "blz=" ).append( this.blz ). append( ", clearingAreaCodeSupported=" ). append( this.isClearingAreaCodeSupported() ). append( ", clearingArea=" ).append( this.clearingArea ). append( ", instituteCode=" ).append( this.instituteCode ). append( ", localityCodeSupported=" ). append( this.isLocalityCodeSupported() ). append( ", localityCode=" ).append( this.localityCode ). append( ", networkCodeSupported=" ). append( this.isNetworkCodeSupported() ). append( ", networkCode=" ).append( this.networkCode ). append( '}' ).toString(); } /** * Gets the current cache instance. * * @return Current cache instance. */ private static Map getCache() { Map cache = (Map) cacheReference.get(); if ( cache == null ) { cache = Collections.synchronizedMap( new HashMap( 1024 ) ); cacheReference = new SoftReference( cache ); } return cache; } /** * Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer * as this object is less than, equal to, or greater than the specified object.

* * @param o The Object to be compared. * @return A negative integer, zero, or a positive integer as this object is less than, equal to, or greater than * the specified object. * * @throws NullPointerException if {@code o} is {@code null}. * @throws ClassCastException if the specified object's type prevents it from being compared to this Object. */ public int compareTo( final Object o ) { if ( o == null ) { throw new NullPointerException( "o" ); } if ( !( o instanceof Bankleitzahl ) ) { throw new ClassCastException( o.getClass().getName() ); } int result = 0; final Bankleitzahl that = (Bankleitzahl) o; if ( !this.equals( that ) ) { result = this.blz > that.blz ? 1 : -1; } return result; } /** * Indicates whether some other object is equal to this one. * * @param o The reference object with which to compare. * * @return {@code true} if this object is the same as {@code o}; {@code false} otherwise. */ public boolean equals( final Object o ) { boolean equal = o == this; if ( !equal && o instanceof Bankleitzahl ) { equal = this.blz == ( (Bankleitzahl) o ).blz; } return equal; } /** * Returns a hash code value for this object. * * @return A hash code value for this object. */ public int hashCode() { return this.blz; } /** * Returns a string representation of the object. * * @return A string representation of the object. */ public String toString() { return super.toString() + this.internalString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy