001/*
002 *  jDTAUS Banking API
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.banking;
022
023import java.io.Serializable;
024import java.text.DecimalFormat;
025import java.text.NumberFormat;
026import java.text.ParseException;
027import java.util.Date;
028
029/**
030 * Record of the {@code BankleitzahlenVerzeichnis}.
031 *
032 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
033 * @version $JDTAUS: BankleitzahlInfo.java 8861 2014-01-10 17:09:50Z schulte $
034 *
035 * @see BankleitzahlenVerzeichnis
036 */
037public class BankleitzahlInfo implements Cloneable, Serializable
038{
039
040    /** Serial version UID for backwards compatibility with 1.1.x classes. */
041    private static final long serialVersionUID = -7251689236798391940L;
042
043    /**
044     * index = index of the field in the record line; value = offset the field's value starts in the record line.
045     */
046    private static final int[] FIELD_TO_OFFSET =
047    {
048        0, 8, 9, 67, 72, 107, 134, 139, 150, 152, 158, 159, 160
049    };
050
051    /**
052     * index = index of the field in the record line; value = length of the field's value in the record line.
053     */
054    private static final int[] FIELD_TO_LENGTH =
055    {
056        8, 1, 58, 5, 35, 27, 5, 11, 2, 6, 1, 1, 8
057    };
058
059    /**
060     * index = index of the field in the record line; value = end offset in the record line exclusive.
061     */
062    private static final int[] FIELD_TO_ENDOFFSET =
063    {
064        BankleitzahlInfo.FIELD_TO_OFFSET[0] + BankleitzahlInfo.FIELD_TO_LENGTH[0],
065        BankleitzahlInfo.FIELD_TO_OFFSET[1] + BankleitzahlInfo.FIELD_TO_LENGTH[1],
066        BankleitzahlInfo.FIELD_TO_OFFSET[2] + BankleitzahlInfo.FIELD_TO_LENGTH[2],
067        BankleitzahlInfo.FIELD_TO_OFFSET[3] + BankleitzahlInfo.FIELD_TO_LENGTH[3],
068        BankleitzahlInfo.FIELD_TO_OFFSET[4] + BankleitzahlInfo.FIELD_TO_LENGTH[4],
069        BankleitzahlInfo.FIELD_TO_OFFSET[5] + BankleitzahlInfo.FIELD_TO_LENGTH[5],
070        BankleitzahlInfo.FIELD_TO_OFFSET[6] + BankleitzahlInfo.FIELD_TO_LENGTH[6],
071        BankleitzahlInfo.FIELD_TO_OFFSET[7] + BankleitzahlInfo.FIELD_TO_LENGTH[7],
072        BankleitzahlInfo.FIELD_TO_OFFSET[8] + BankleitzahlInfo.FIELD_TO_LENGTH[8],
073        BankleitzahlInfo.FIELD_TO_OFFSET[9] + BankleitzahlInfo.FIELD_TO_LENGTH[9],
074        BankleitzahlInfo.FIELD_TO_OFFSET[10] + BankleitzahlInfo.FIELD_TO_LENGTH[10],
075        BankleitzahlInfo.FIELD_TO_OFFSET[11] + BankleitzahlInfo.FIELD_TO_LENGTH[11],
076        BankleitzahlInfo.FIELD_TO_OFFSET[12] + BankleitzahlInfo.FIELD_TO_LENGTH[12]
077    };
078
079    /**
080     * Bankleitzahl (german bank code).
081     * @serial
082     */
083    private Bankleitzahl bankCode;
084
085    /**
086     * Specifies if this record identifies a bank which is to be used for transactions.
087     * @serial
088     */
089    private boolean headOffice;
090
091    /**
092     * The name of the bank.
093     * @serial
094     */
095    private String name;
096
097    /**
098     * Postal code of the city the bank is resident.
099     * @serial
100     */
101    private int postalCode = -1;
102
103    /**
104     * City the bank resides at.
105     * @serial
106     */
107    private String city;
108
109    /**
110     * Description of the bank including information regarding the city the bank resides.
111     * @serial
112     */
113    private String description;
114
115    /**
116     * Institute number for PAN.
117     * @serial
118     */
119    private int panInstituteNumber = -1;
120
121    /**
122     * SWIFT Bank Identifier Code.
123     * @serial
124     */
125    private String bic;
126
127    /**
128     * Label for the algorithm used for validating account numbers.
129     * @serial
130     */
131    private String validationLabel;
132
133    /**
134     * The serial number of the record.
135     * @serial
136     */
137    private Integer serialNumber;
138
139    /**
140     * Label indicating changes of the record to previous files.
141     * @serial
142     */
143    private char changeLabel;
144
145    /**
146     * Indicates if this record will be deleted in upcoming files.
147     * @serial
148     */
149    private boolean markedForDeletion;
150
151    /**
152     * Bankleitzahl of the bank the record is replaced with.
153     * @serial
154     */
155    private Bankleitzahl replacingBankCode;
156
157    /**
158     * Label of the rule used for generating international bank account numbers.
159     * @serial
160     * @since 1.15
161     */
162    private Integer ibanRuleLabel;
163
164    /**
165     * Version of the rule used for generating international bank account numbers.
166     * @serial
167     * @since 1.15
168     */
169    private Integer ibanRuleVersion;
170
171    /**
172     * The date the record got created at.
173     * @since 1.15
174     */
175    private Date creationDate;
176
177    /**
178     * The date the record got modified at.
179     * @since 1.15
180     */
181    private Date modificationDate;
182
183    /**
184     * The date the record got deleted at.
185     * @since 1.15
186     */
187    private Date deletionDate;
188
189    /** Creates a new {@code BankleitzahlInfo} instance. */
190    public BankleitzahlInfo()
191    {
192        super();
193    }
194
195    /**
196     * Getter for property {@code bankCode}.
197     *
198     * @return The german bank code identifying the bank (field 1).
199     */
200    public Bankleitzahl getBankCode()
201    {
202        return this.bankCode;
203    }
204
205    /**
206     * Setter for property {@code bankCode}.
207     *
208     * @param value The german bank code identifying the bank (field 1).
209     */
210    public void setBankCode( final Bankleitzahl value )
211    {
212        this.bankCode = value;
213    }
214
215    /**
216     * Getter for property {@code headOffice}.
217     *
218     * @return {@code true} if this record specifies a bank which is to be used for transactions; {@code false} if this
219     * record specifies a branch office of a bank not to be used for transactions but sharing a bank code (field 2).
220     */
221    public boolean isHeadOffice()
222    {
223        return this.headOffice;
224    }
225
226    /**
227     * Setter for property {@code headOffice}.
228     *
229     * @param value {@code true} if this record specifies a bank which is to be used for transactions; {@code false} if
230     * this record specifies a branch office of a bank not to be used for transactions but sharing a bank code
231     * (field 2).
232     */
233    public void setHeadOffice( final boolean value )
234    {
235        this.headOffice = value;
236    }
237
238    /**
239     * Getter for property {@code name}.
240     *
241     * @return The name of the bank (field 3).
242     */
243    public String getName()
244    {
245        return this.name;
246    }
247
248    /**
249     * Setter for property {@code name}.
250     *
251     * @param value The name of the bank (field 3).
252     */
253    public void setName( final String value )
254    {
255        this.name = value;
256    }
257
258    /**
259     * Getter for property {@code postalCode}.
260     *
261     * @return The postal code of the city the bank is resident (field 4).
262     */
263    public int getPostalCode()
264    {
265        return this.postalCode;
266    }
267
268    /**
269     * Setter for property {@code postalCode}.
270     *
271     * @param value The postal code of the city the bank is resident (field 4).
272     */
273    public void setPostalCode( final int value )
274    {
275        this.postalCode = value;
276    }
277
278    /**
279     * Getter for property {@code city}.
280     *
281     * @return The city the bank resides at (field 5).
282     */
283    public String getCity()
284    {
285        return this.city;
286    }
287
288    /**
289     * Setter for property {@code city}.
290     *
291     * @param value The city the bank resides at (field 5).
292     */
293    public void setCity( final String value )
294    {
295        this.city = value;
296    }
297
298    /**
299     * Getter for property {@code description}.
300     *
301     * @return A description of the bank including information regarding the city the bank resides to be used for
302     * displaying on e.g. invoices (field 6).
303     */
304    public String getDescription()
305    {
306        return this.description;
307    }
308
309    /**
310     * Setter for property {@code description}.
311     *
312     * @param value A description of the bank including information regarding the city the bank resides to be used for
313     * displaying on e.g. invoices (field 6).
314     */
315    public void setDescription( final String value )
316    {
317        this.description = value;
318    }
319
320    /**
321     * Getter for property {@code panInstituteNumber}.
322     *
323     * @return The institute number for PAN or {@code 0} if no number is available (field 7).
324     */
325    public int getPanInstituteNumber()
326    {
327        return this.panInstituteNumber;
328    }
329
330    /**
331     * Setter for property {@code panInstituteNumber}.
332     *
333     * @param value The institute number for PAN or {@code 0} if no number is available (field 7).
334     */
335    public void setPanInstituteNumber( final int value )
336    {
337        this.panInstituteNumber = value;
338    }
339
340    /**
341     * Getter for property {@code bic}.
342     *
343     * @return The SWIFT Bank Identifier Code (field 8).
344     */
345    public String getBic()
346    {
347        return this.bic;
348    }
349
350    /**
351     * Setter for property {@code bic}.
352     *
353     * @param value The SWIFT Bank Identifier Code (field 8).
354     */
355    public void setBic( final String value )
356    {
357        this.bic = value;
358    }
359
360    /**
361     * Getter for property {@code validationLabel}.
362     *
363     * @return The label for the algorithm to be used for validating account numbers (field 9).
364     */
365    public String getValidationLabel()
366    {
367        return this.validationLabel;
368    }
369
370    /**
371     * Setter for property {@code validationLabel}.
372     *
373     * @param value The label for the algorithm to be used for validating account numbers (field 9).
374     */
375    public void setValidationLabel( final String value )
376    {
377        this.validationLabel = value;
378    }
379
380    /**
381     * Getter for property {@code serialNumber}.
382     *
383     * @return The serial number of the record (field 10).
384     */
385    public Integer getSerialNumber()
386    {
387        return this.serialNumber;
388    }
389
390    /**
391     * Setter for property {@code serialNumber}.
392     *
393     * @param value The serial number of the record (field 10).
394     */
395    public void setSerialNumber( final Integer value )
396    {
397        this.serialNumber = value;
398    }
399
400    /**
401     * Getter for property {@code changeLabel}.
402     *
403     * @return The label used to indicate changes of the record since previous files (field 11).
404     */
405    public char getChangeLabel()
406    {
407        return this.changeLabel;
408    }
409
410    /**
411     * Setter for property {@code changeLabel}.
412     *
413     * @param value The label used to indicate changes of the record since previous files (field 11).
414     */
415    public void setChangeLabel( final char value )
416    {
417        this.changeLabel = value;
418    }
419
420    /**
421     * Getter for property {@code markedForDeletion}.
422     *
423     * @return {@code true} if this record will be deleted from upcoming files; {@code false} if not (field 12).
424     */
425    public boolean isMarkedForDeletion()
426    {
427        return this.markedForDeletion;
428    }
429
430    /**
431     * Setter for property {@code markedForDeletion}.
432     *
433     * @param value {@code true} if this record will be deleted from upcoming files; {@code false} if not (field 12).
434     */
435    public void setMarkedForDeletion( final boolean value )
436    {
437        this.markedForDeletion = value;
438    }
439
440    /**
441     * Getter for property {@code replacingBankCode}.
442     *
443     * @return The bank code of the bank replacing this bank if this record is marked for deletion or {@code null} if no
444     * replacing bank code is specified or the record is not to be deleted (field 13).
445     */
446    public Bankleitzahl getReplacingBankCode()
447    {
448        return this.replacingBankCode;
449    }
450
451    /**
452     * Setter for property {@code replacingBankCode}.
453     *
454     * @param value The bank code of the bank replacing this bank if this record is marked for deletion or {@code null}
455     * if no replacing bank code is specified or the record is not to be deleted (field 13).
456     */
457    public void setReplacingBankCode( final Bankleitzahl value )
458    {
459        this.replacingBankCode = value;
460    }
461
462    /**
463     * Getter for property {@code ibanRuleLabel}.
464     *
465     * @return The label of the rule to use for generating international bank account numbers or {@code null}, if
466     * generating an IBAN for an account at the bank identified by the bank code of this record is not supported
467     * (field 14).
468     *
469     * @since 1.15
470     */
471    public Integer getIbanRuleLabel()
472    {
473        return this.ibanRuleLabel;
474    }
475
476    /**
477     * Setter for property {@code ibanRuleLabel}.
478     *
479     * @param value The label of the algorithm to use for generating international bank account numbers or {@code null},
480     * if generating an IBAN for an account at the bank identified by the bank code of this record should not be
481     * supported (field 14).
482     *
483     * @since 1.15
484     */
485    public void setIbanRuleLabel( final Integer value )
486    {
487        this.ibanRuleLabel = value;
488    }
489
490    /**
491     * Getter for property {@code ibanRuleVersion}.
492     *
493     * @return The version of the rule to use for generating international bank account numbers or {@code null}, if
494     * generating an IBAN for an account at the bank identified by the bank code of this record is not supported
495     * (field 14).
496     *
497     * @since 1.15
498     */
499    public Integer getIbanRuleVersion()
500    {
501        return this.ibanRuleVersion;
502    }
503
504    /**
505     * Setter for property {@code ibanRuleVersion}.
506     *
507     * @param value The label of the rule to use for generating international bank account numbers or {@code null},
508     * if generating an IBAN for an account at the bank identified by the bank code of this record should not be
509     * supported (field 14).
510     *
511     * @since 1.15
512     */
513    public void setIbanRuleVersion( final Integer value )
514    {
515        this.ibanRuleVersion = value;
516    }
517
518    /**
519     * Getter for property {@code creationDate}.
520     *
521     * @return The date the record got created at.
522     *
523     * @since 1.15
524     */
525    public Date getCreationDate()
526    {
527        return (Date) ( this.creationDate != null ? this.creationDate.clone() : null );
528    }
529
530    /**
531     * Setter for property {@code creationDate}.
532     *
533     * @param value The new date the record got created at.
534     *
535     * @since 1.15
536     */
537    public void setCreationDate( final Date value )
538    {
539        this.creationDate = (Date) ( value != null ? value.clone() : null );
540    }
541
542    /**
543     * Getter for property {@code modificationDate}.
544     *
545     * @return The date the record got modified at.
546     *
547     * @since 1.15
548     */
549    public Date getModificationDate()
550    {
551        return (Date) ( this.modificationDate != null ? this.modificationDate.clone() : null );
552    }
553
554    /**
555     * Setter for property {@code modificationDate}.
556     *
557     * @param value The new date the record got modified at.
558     *
559     * @since 1.15
560     */
561    public void setModificationDate( final Date value )
562    {
563        this.modificationDate = (Date) ( value != null ? value.clone() : null );
564    }
565
566    /**
567     * Getter for property {@code deletionDate}.
568     *
569     * @return The date the record got deleted at.
570     *
571     * @since 1.15
572     */
573    public Date getDeletionDate()
574    {
575        return (Date) ( this.deletionDate != null ? this.deletionDate.clone() : null );
576    }
577
578    /**
579     * Setter for property {@code deletionDate}.
580     *
581     * @param value The new date the record got deleted at.
582     *
583     * @since 1.15
584     */
585    public void setDeletionDate( final Date value )
586    {
587        this.deletionDate = (Date) ( value != null ? value.clone() : null );
588    }
589
590    /**
591     * Parses text from a Bankleitzahlendatei to initialize the instance.
592     * <p>This method may be used for reading records from the german Bankleitzahlendatei as published by
593     * <a href="http://www.bundesbank.de/index.en.php">Deutsche Bundesbank</a>.
594     * It supports reading the format as of june 2006.</p>
595     *
596     * @param line A line from a Bankleitzahlendatei to parse.
597     *
598     * @throws NullPointerException if {@code text} is {@code null}.
599     * @throws IllegalArgumentException if the parse fails.
600     *
601     * @deprecated As of 1.15, please use class {@link org.jdtaus.banking.util.BankleitzahlenDatei}.
602     */
603    public void parse( final String line )
604    {
605        if ( line == null )
606        {
607            throw new NullPointerException( "line" );
608        }
609
610        Number blz;
611        String field;
612        final NumberFormat plzFmt = new DecimalFormat( "00000" );
613        final NumberFormat serFmt = new DecimalFormat( "000000" );
614        final NumberFormat blzFmt = new DecimalFormat( "00000000" );
615
616        try
617        {
618            // Field 1
619            this.bankCode = Bankleitzahl.parse( line.substring( FIELD_TO_OFFSET[0], FIELD_TO_ENDOFFSET[0] ).trim() );
620            // Field 2
621            this.headOffice = "1".equals( line.substring( FIELD_TO_OFFSET[1], FIELD_TO_ENDOFFSET[1] ) );
622            // Field 3
623            this.name = line.substring( FIELD_TO_OFFSET[2], FIELD_TO_ENDOFFSET[2] ).trim();
624            // Field 4
625            this.postalCode =
626                plzFmt.parse( line.substring( FIELD_TO_OFFSET[3], FIELD_TO_ENDOFFSET[3] ).trim() ).intValue();
627
628            // Field 5
629            this.city = line.substring( FIELD_TO_OFFSET[4], FIELD_TO_ENDOFFSET[4] ).trim();
630            // Field 6
631            this.description = line.substring( FIELD_TO_OFFSET[5], FIELD_TO_ENDOFFSET[5] ).trim();
632            // Field 7
633            field = line.substring( FIELD_TO_OFFSET[6], FIELD_TO_ENDOFFSET[6] ).trim();
634            this.panInstituteNumber = field.length() > 0 ? plzFmt.parse( field ).intValue() : 0;
635            // Field 8
636            this.bic = line.substring( FIELD_TO_OFFSET[7], FIELD_TO_ENDOFFSET[7] ).trim();
637            // Field 9
638            this.validationLabel = line.substring( FIELD_TO_OFFSET[8], FIELD_TO_ENDOFFSET[8] ).trim();
639            // Field 10
640            this.serialNumber = new Integer(
641                serFmt.parse( line.substring( FIELD_TO_OFFSET[9], FIELD_TO_ENDOFFSET[9] ).trim() ).intValue() );
642
643            // Field 11
644            this.changeLabel = line.substring( FIELD_TO_OFFSET[10], FIELD_TO_ENDOFFSET[10] ).toCharArray()[0];
645            // Field 12
646            this.markedForDeletion = "1".equals( line.substring( FIELD_TO_OFFSET[11], FIELD_TO_ENDOFFSET[11] ) );
647            // Field 13
648            blz = blzFmt.parse( line.substring( FIELD_TO_OFFSET[12], FIELD_TO_ENDOFFSET[12] ).trim() );
649            if ( blz.intValue() != 0 )
650            {
651                this.replacingBankCode = Bankleitzahl.valueOf( blz );
652            }
653            else
654            {
655                this.replacingBankCode = null;
656            }
657        }
658        catch ( final ParseException e )
659        {
660            throw (IllegalArgumentException) new IllegalArgumentException( line ).initCause( e );
661        }
662        catch ( final IndexOutOfBoundsException e )
663        {
664            throw (IllegalArgumentException) new IllegalArgumentException( line ).initCause( e );
665        }
666    }
667
668    /**
669     * Creates and returns a copy of this object.
670     *
671     * @return A clone of this instance.
672     */
673    public Object clone()
674    {
675        try
676        {
677            return super.clone();
678        }
679        catch ( final CloneNotSupportedException e )
680        {
681            throw new AssertionError( e );
682        }
683    }
684
685    /**
686     * Indicates whether some other object is equal to this one.
687     *
688     * @param o The reference object with which to compare.
689     *
690     * @return {@code true} if this object is the same as {@code o}; {@code false} otherwise.
691     */
692    public boolean equals( final Object o )
693    {
694        boolean ret = o == this;
695
696        if ( !ret && o instanceof BankleitzahlInfo )
697        {
698            final BankleitzahlInfo that = (BankleitzahlInfo) o;
699            ret = this.serialNumber == null ? that.serialNumber == null : this.serialNumber.equals( that.serialNumber );
700        }
701
702        return ret;
703    }
704
705    /**
706     * Returns a hash code value for this object.
707     *
708     * @return A hash code value for this object.
709     */
710    public int hashCode()
711    {
712        return this.serialNumber == null ? 0 : this.serialNumber.intValue();
713    }
714
715    /**
716     * Returns a string representation of the object.
717     *
718     * @return A string representation of the object.
719     */
720    public String toString()
721    {
722        return super.toString() + this.internalString();
723    }
724
725    /**
726     * Creates a string representing the properties of the instance.
727     *
728     * @return a string representing the properties of the instance.
729     */
730    private String internalString()
731    {
732        return new StringBuffer( 500 ).append( '{' ).
733            append( "headOffice=" ).append( this.headOffice ).
734            append( ", bankCode=" ).append( this.bankCode ).
735            append( ", name=" ).append( this.name ).
736            append( ", bic=" ).append( this.bic ).
737            append( ", changeLabel=" ).append( this.changeLabel ).
738            append( ", city=" ).append( this.city ).
739            append( ", markedForDeletion=" ).append( this.markedForDeletion ).
740            append( ", panInstituteNumber=" ).append( this.panInstituteNumber ).
741            append( ", postalCode=" ).append( this.postalCode ).
742            append( ", replacingBankCode=" ).append( this.replacingBankCode ).
743            append( ", serialNumber=" ).append( this.serialNumber ).
744            append( ", description=" ).append( this.description ).
745            append( ", validationLabel=" ).append( this.validationLabel ).
746            append( ", ibanRuleLabel=" ).append( this.ibanRuleLabel ).
747            append( ", ibanRuleVersion=" ).append( this.ibanRuleVersion ).
748            append( ", creationDate=" ).append( this.creationDate ).
749            append( ", modificationDate=" ).append( this.modificationDate ).
750            append( ", deletionDate=" ).append( this.deletionDate ).
751            append( '}' ).toString();
752
753    }
754
755}