001/*
002 *  jDTAUS Banking RI DTAUS
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.dtaus.ri.zka;
022
023import java.io.IOException;
024import java.util.Arrays;
025import java.util.Currency;
026import java.util.Date;
027import java.util.HashMap;
028import java.util.Iterator;
029import java.util.LinkedList;
030import java.util.List;
031import java.util.Map;
032import org.jdtaus.banking.dtaus.Header;
033import org.jdtaus.banking.dtaus.LogicalFile;
034import org.jdtaus.banking.dtaus.LogicalFileType;
035import org.jdtaus.banking.dtaus.spi.CurrencyCounter;
036import org.jdtaus.banking.dtaus.spi.HeaderValidator;
037import org.jdtaus.banking.dtaus.spi.IllegalHeaderException;
038import org.jdtaus.banking.messages.CurrencyConstraintMessage;
039import org.jdtaus.banking.messages.IllegalCurrencyMessage;
040import org.jdtaus.banking.messages.IllegalDateMessage;
041import org.jdtaus.banking.messages.IllegalScheduleMessage;
042import org.jdtaus.banking.messages.TextschluesselConstraintMessage;
043import org.jdtaus.banking.spi.CurrencyMapper;
044import org.jdtaus.banking.spi.UnsupportedCurrencyException;
045import org.jdtaus.core.container.ContainerFactory;
046import org.jdtaus.core.container.PropertyException;
047import org.jdtaus.core.logging.spi.Logger;
048import org.jdtaus.core.messages.MandatoryPropertyMessage;
049import org.jdtaus.core.text.Message;
050
051/**
052 * jDTAUS Banking SPI {@code HeaderValidator} implementation.
053 *
054 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
055 * @version $JDTAUS: DefaultHeaderValidator.java 8661 2012-09-27 11:29:58Z schulte $
056 */
057public final class DefaultHeaderValidator implements HeaderValidator
058{
059
060    /** Value of property {@code maxScheduleDays} in milliseconds. */
061    private long maxScheduleDaysMillis = Long.MIN_VALUE;
062
063    public IllegalHeaderException assertValidHeader( final Header header, IllegalHeaderException result )
064    {
065        if ( header == null )
066        {
067            throw new NullPointerException( "header" );
068        }
069
070        this.assertValidProperties();
071        final List messages = new LinkedList();
072        final Map properties = new HashMap( 20 );
073
074        if ( header.getCreateDate() == null )
075        {
076            properties.put( Header.PROP_CREATEDATE, new MandatoryPropertyMessage() );
077        }
078        else if ( !this.checkDate( header.getCreateDate() ) )
079        {
080            properties.put( Header.PROP_CREATEDATE, new IllegalDateMessage(
081                header.getCreateDate(), new Date( this.getMinDateMillis() ), new Date( this.getMaxDateMillis() ) ) );
082
083        }
084
085        if ( header.getExecutionDate() != null && !this.checkDate( header.getExecutionDate() ) )
086        {
087            properties.put( Header.PROP_EXECUTIONDATE, new IllegalDateMessage(
088                header.getExecutionDate(), new Date( this.getMinDateMillis() ), new Date( this.getMaxDateMillis() ) ) );
089
090        }
091        if ( header.getType() == null )
092        {
093            properties.put( Header.PROP_TYPE, new MandatoryPropertyMessage() );
094        }
095        else if ( header.getType().isSendByBank() && header.getBankData() == null )
096        {
097            properties.put( Header.PROP_BANKDATA, new MandatoryPropertyMessage() );
098        }
099
100        if ( header.getCustomer() == null || header.getCustomer().isEmpty() )
101        {
102            properties.put( Header.PROP_CUSTOMER, new MandatoryPropertyMessage() );
103        }
104        if ( header.getBank() == null )
105        {
106            properties.put( Header.PROP_BANK, new MandatoryPropertyMessage() );
107        }
108        if ( header.getAccount() == null )
109        {
110            properties.put( Header.PROP_ACCOUNT, new MandatoryPropertyMessage() );
111        }
112        if ( header.getCurrency() == null )
113        {
114            properties.put( Header.PROP_CURRENCY, new MandatoryPropertyMessage() );
115        }
116
117        if ( header.getCreateDate() != null )
118        {
119            if ( header.getCurrency() != null )
120            {
121                try
122                {
123                    this.getCurrencyMapper().getDtausCode( header.getCurrency(), header.getCreateDate() );
124                }
125                catch ( UnsupportedCurrencyException ex )
126                {
127                    if ( this.getLogger().isDebugEnabled() )
128                    {
129                        this.getLogger().debug( ex.toString() );
130                    }
131
132                    properties.put( Header.PROP_CURRENCY, new IllegalCurrencyMessage(
133                        header.getCurrency().getCurrencyCode(), header.getCreateDate() ) );
134
135                }
136            }
137
138            if ( !this.checkSchedule( header.getCreateDate(), header.getExecutionDate() ) )
139            {
140                messages.add( new IllegalScheduleMessage(
141                    header.getCreateDate(), header.getExecutionDate(), this.getMaxScheduleDays() ) );
142
143            }
144        }
145
146        if ( properties.size() > 0 || messages.size() > 0 )
147        {
148            if ( result == null )
149            {
150                result = new IllegalHeaderException();
151            }
152
153            for ( Iterator it = properties.entrySet().iterator(); it.hasNext(); )
154            {
155                final Map.Entry entry = (Map.Entry) it.next();
156                result.addMessage( (String) entry.getKey(), (Message) entry.getValue() );
157            }
158            for ( Iterator it = messages.iterator(); it.hasNext(); )
159            {
160                result.addMessage( (Message) it.next() );
161            }
162        }
163
164        return result;
165    }
166
167    public IllegalHeaderException assertValidHeader(
168        final LogicalFile lFile, final Header header, final CurrencyCounter counter, IllegalHeaderException result )
169        throws IOException
170    {
171        if ( lFile == null )
172        {
173            throw new NullPointerException( "lFile" );
174        }
175        if ( header == null )
176        {
177            throw new NullPointerException( "header" );
178        }
179        if ( counter == null )
180        {
181            throw new NullPointerException( "counter" );
182        }
183
184        this.assertValidProperties();
185
186        IllegalHeaderException e = this.assertValidHeader( header, result );
187        final LogicalFileType oldLabel = lFile.getHeader().getType();
188        final LogicalFileType newLabel = header.getType();
189
190        if ( newLabel != null )
191        {
192            if ( oldLabel != null && lFile.getChecksum().getTransactionCount() > 0
193                 && ( ( oldLabel.isDebitAllowed() && !newLabel.isDebitAllowed() )
194                      || ( oldLabel.isRemittanceAllowed() && !newLabel.isRemittanceAllowed() ) ) )
195            {
196                if ( e == null )
197                {
198                    e = new IllegalHeaderException();
199                }
200
201                e.addMessage( Header.PROP_TYPE, new TextschluesselConstraintMessage(
202                    newLabel, lFile.getTransaction( 0 ).getType() ) );
203
204            }
205        }
206
207        if ( header.getCreateDate() != null )
208        {
209            final Currency[] oldCurrencies =
210                this.getCurrencyMapper().getDtausCurrencies( lFile.getHeader().getCreateDate() );
211
212            final Currency[] newCurrencies = this.getCurrencyMapper().getDtausCurrencies( header.getCreateDate() );
213
214            if ( !Arrays.equals( oldCurrencies, newCurrencies ) )
215            {
216                final Currency[] current = counter.getCurrencies();
217                for ( int i = current.length - 1; i >= 0; i-- )
218                {
219                    boolean currencyKept = false;
220
221                    for ( int j = newCurrencies.length - 1; j >= 0; j-- )
222                    {
223                        if ( newCurrencies[j].getCurrencyCode().equals( current[i].getCurrencyCode() ) )
224                        {
225                            currencyKept = true;
226                            break;
227                        }
228                    }
229
230                    if ( !currencyKept )
231                    {
232                        if ( e == null )
233                        {
234                            e = new IllegalHeaderException();
235                        }
236
237                        e.addMessage( new CurrencyConstraintMessage(
238                            current[i].getCurrencyCode(), header.getCreateDate() ) );
239
240                    }
241                }
242            }
243        }
244
245        return e;
246    }
247
248    /**
249     * Gets the value of property {@code maxScheduleDays} in milliseconds.
250     *
251     * @return the value of property {@code maxScheduleDays} in milliseconds.
252     */
253    private long getMaxScheduleDaysMillis()
254    {
255        if ( this.maxScheduleDaysMillis < 0L )
256        {
257            this.maxScheduleDaysMillis = this.getMaxScheduleDays() * 86400000L;
258        }
259
260        return this.maxScheduleDaysMillis;
261    }
262
263    /**
264     * Checks configured properties.
265     *
266     * @throws PropertyException for illegal property values.
267     */
268    private void assertValidProperties()
269    {
270        if ( this.getMinDateMillis() < 0L )
271        {
272            throw new PropertyException( "minDateMillis", Long.toString( this.getMinDateMillis() ) );
273        }
274        if ( this.getMaxDateMillis() < 0L || this.getMinDateMillis() > this.getMaxDateMillis() )
275        {
276            throw new PropertyException( "maxDateMillis", Long.toString( this.getMaxDateMillis() ) );
277        }
278        if ( this.getMaxScheduleDays() < 0 )
279        {
280            throw new PropertyException( "maxScheduleDays", Integer.toString( this.getMaxScheduleDays() ) );
281        }
282    }
283
284    /**
285     * Checks a given date.
286     *
287     * @param date instance to check.
288     *
289     * @return {@code true} if {@code date} is legal; {@code false} if not.
290     */
291    private boolean checkDate( final Date date )
292    {
293        boolean valid = false;
294
295        if ( date != null )
296        {
297            final long millis = date.getTime();
298            valid = millis >= this.getMinDateMillis() && millis <= this.getMaxDateMillis();
299        }
300
301        return valid;
302    }
303
304    /**
305     * Checks a given schedule.
306     *
307     * @param createDate file creation date to check.
308     * @param executionDate file execution date to check.
309     *
310     * @return {@code true} if {@code createDate} and {@code executionDate} is a legal combination; {@code false} if
311     * not.
312     */
313    private boolean checkSchedule( final Date createDate, final Date executionDate )
314    {
315        boolean valid = createDate != null;
316
317        if ( valid )
318        {
319            final long createMillis = createDate.getTime();
320            if ( executionDate != null )
321            {
322                final long executionMillis = executionDate.getTime();
323                valid = executionMillis >= createMillis
324                        && executionMillis <= createMillis + this.getMaxScheduleDaysMillis();
325
326            }
327        }
328
329        return valid;
330    }
331
332    //--Constructors------------------------------------------------------------
333
334// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausConstructors
335    // This section is managed by jdtaus-container-mojo.
336
337    /** Standard implementation constructor <code>org.jdtaus.banking.dtaus.ri.zka.DefaultHeaderValidator</code>. */
338    public DefaultHeaderValidator()
339    {
340        super();
341    }
342
343// </editor-fold>//GEN-END:jdtausConstructors
344
345    //------------------------------------------------------------Constructors--
346    //--Dependencies------------------------------------------------------------
347
348// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausDependencies
349    // This section is managed by jdtaus-container-mojo.
350
351    /**
352     * Gets the configured <code>CurrencyMapper</code> implementation.
353     *
354     * @return The configured <code>CurrencyMapper</code> implementation.
355     */
356    private CurrencyMapper getCurrencyMapper()
357    {
358        return (CurrencyMapper) ContainerFactory.getContainer().
359            getDependency( this, "CurrencyMapper" );
360
361    }
362
363    /**
364     * Gets the configured <code>Logger</code> implementation.
365     *
366     * @return The configured <code>Logger</code> implementation.
367     */
368    private Logger getLogger()
369    {
370        return (Logger) ContainerFactory.getContainer().
371            getDependency( this, "Logger" );
372
373    }
374
375// </editor-fold>//GEN-END:jdtausDependencies
376
377    //------------------------------------------------------------Dependencies--
378    //--Properties--------------------------------------------------------------
379
380// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:jdtausProperties
381    // This section is managed by jdtaus-container-mojo.
382
383    /**
384     * Gets the value of property <code>minDateMillis</code>.
385     *
386     * @return Timestamp any date is not allowed to precede.
387     */
388    private long getMinDateMillis()
389    {
390        return ( (java.lang.Long) ContainerFactory.getContainer().
391            getProperty( this, "minDateMillis" ) ).longValue();
392
393    }
394
395    /**
396     * Gets the value of property <code>maxScheduleDays</code>.
397     *
398     * @return Maximum number of days allowed for a schedule.
399     */
400    private int getMaxScheduleDays()
401    {
402        return ( (java.lang.Integer) ContainerFactory.getContainer().
403            getProperty( this, "maxScheduleDays" ) ).intValue();
404
405    }
406
407    /**
408     * Gets the value of property <code>maxDateMillis</code>.
409     *
410     * @return Timestamp any date is not allowed to follow.
411     */
412    private long getMaxDateMillis()
413    {
414        return ( (java.lang.Long) ContainerFactory.getContainer().
415            getProperty( this, "maxDateMillis" ) ).longValue();
416
417    }
418
419// </editor-fold>//GEN-END:jdtausProperties
420
421    //--------------------------------------------------------------Properties--
422}