solution07 task3
authorjapod@localhost
Fri, 10 Oct 2008 22:10:25 +0200
changeset 57be49855c7fa2
parent 56 a3144e7f9c90
child 58 07c16ec15a25
solution07 task3
task3/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java
task3/solution07/test/org/apidesign/apifest08/test/Task3Test.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/task3/solution07/src/org/apidesign/apifest08/currency/anothervendor/ZigZaggingBidirectionalConvertor.java	Fri Oct 10 22:10:25 2008 +0200
     1.3 @@ -0,0 +1,130 @@
     1.4 +/*
     1.5 + * To change this template, choose Tools | Templates
     1.6 + * and open the template in the editor.
     1.7 + */
     1.8 +
     1.9 +package org.apidesign.apifest08.currency.anothervendor;
    1.10 +
    1.11 +import java.math.BigDecimal;
    1.12 +import java.util.Currency;
    1.13 +import java.util.Iterator;
    1.14 +import org.apidesign.apifest08.currency.Convertor;
    1.15 +import org.apidesign.apifest08.currency.IllegalRequestSubtypeException;
    1.16 +import org.apidesign.apifest08.currency.MonetaryAmount;
    1.17 +
    1.18 +
    1.19 +/**
    1.20 + * A convertor that changes the rate by a step amount on every conversion it performs.
    1.21 + * @author jdvorak
    1.22 + */
    1.23 +public class ZigZaggingBidirectionalConvertor implements Convertor {
    1.24 +
    1.25 +    private final MonetaryAmount srcRateAmount;
    1.26 +    
    1.27 +    private final Currency tgtCurrency;
    1.28 +    
    1.29 +    private final Iterator<BigDecimal> rateIterator;
    1.30 +
    1.31 +    /**
    1.32 +     * Costructor with the precise amounts.
    1.33 +     * @param srcRateAmount
    1.34 +     * @param tgtCurrency
    1.35 +     * @param startAmount
    1.36 +     * @param endAmount
    1.37 +     * @param stepAmount
    1.38 +     */
    1.39 +    public ZigZaggingBidirectionalConvertor( final MonetaryAmount srcRateAmount, final Currency tgtCurrency, final BigDecimal startAmount, final BigDecimal endAmount, final BigDecimal stepAmount ) {
    1.40 +        this.srcRateAmount = srcRateAmount;
    1.41 +        this.tgtCurrency = tgtCurrency;
    1.42 +        this.rateIterator = new ZigZaggingBigDecimalIterator( startAmount, endAmount, stepAmount );
    1.43 +    }
    1.44 +
    1.45 +    /**
    1.46 +     * Do the conversion; updates the rate.
    1.47 +     * @param req
    1.48 +     * @return
    1.49 +     * @throws org.apidesign.apifest08.currency.IllegalRequestSubtypeException
    1.50 +     */
    1.51 +    public synchronized ConversionResult convert( ConversionRequest req ) throws IllegalRequestSubtypeException {
    1.52 +        if ( tgtCurrency.equals( req.getTgtCurrency() ) ) {
    1.53 +            if ( srcRateAmount.getCurrency().equals( req.getSrcAmount().getCurrency() ) ) {
    1.54 +                final BigDecimal tgtRateAmount = rateIterator.next();
    1.55 +                final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( tgtRateAmount ).divide( srcRateAmount.getAmount() );
    1.56 +                return new ConversionResult( new MonetaryAmount( tgtAmount, tgtCurrency ) );
    1.57 +            }
    1.58 +        }
    1.59 +        if ( srcRateAmount.getCurrency().equals( req.getTgtCurrency() ) ) {
    1.60 +            if ( tgtCurrency.equals( req.getSrcAmount().getCurrency() ) ) {
    1.61 +                final BigDecimal tgtRateAmount = rateIterator.next();
    1.62 +                final BigDecimal tgtAmount = req.getSrcAmount().getAmount().multiply( srcRateAmount.getAmount() ).divide( tgtRateAmount );
    1.63 +                return new ConversionResult( new MonetaryAmount( tgtAmount, srcRateAmount.getCurrency() ) );
    1.64 +            }
    1.65 +        }
    1.66 +        return new ConversionResult( null );
    1.67 +    }
    1.68 +
    1.69 +}
    1.70 +
    1.71 +/**
    1.72 + * An iterator that goes zig first, then zag, then zig again, then zag again, ad libitum.
    1.73 + * @author jdvorak
    1.74 + */
    1.75 +class ZigZaggingBigDecimalIterator implements Iterator<BigDecimal> {
    1.76 +
    1.77 +    private BigDecimal zigBounce;
    1.78 +    
    1.79 +    private BigDecimal zagBounce;
    1.80 +    
    1.81 +    private BigDecimal step;
    1.82 +    
    1.83 +    private BigDecimal currentValue;
    1.84 +    
    1.85 +    protected ZigZaggingBigDecimalIterator( final BigDecimal zagBounce, final BigDecimal zigBounce, final BigDecimal step ) {
    1.86 +        this. zigBounce = zigBounce;
    1.87 +        this.zagBounce = zagBounce;
    1.88 +        this.currentValue = zagBounce;
    1.89 +        this.step = step;
    1.90 +        
    1.91 +        if (  zigBounce == null ) {
    1.92 +            throw new NullPointerException( "zigAmount" );
    1.93 +        }
    1.94 +        if ( zagBounce == null ) {
    1.95 +            throw new NullPointerException( "zagAmount" );
    1.96 +        }
    1.97 +        if ( step == null ) {
    1.98 +            throw new NullPointerException( "stepAmount" );
    1.99 +        }
   1.100 +        final int stepSign = step.signum();
   1.101 +        if ( stepSign == 0 ) {
   1.102 +            throw new IllegalArgumentException( "stepAmount can't be zero" );
   1.103 +        }
   1.104 +        if ( stepSign * zigBounce.compareTo( zagBounce ) < 0 ) {
   1.105 +            throw new IllegalArgumentException( "stepAmount shall have the same sign as endAmount - startAmount" );
   1.106 +        }
   1.107 +    }
   1.108 +    
   1.109 +    public boolean hasNext() {
   1.110 +        return true;
   1.111 +    }
   1.112 +
   1.113 +    public BigDecimal next() {
   1.114 +        final BigDecimal result = currentValue;
   1.115 +        
   1.116 +        currentValue = currentValue.add( step );
   1.117 +        final int stepSign = step.signum();
   1.118 +        final int currentMinusZigSign = currentValue.compareTo( zigBounce );
   1.119 +        if ( stepSign * currentMinusZigSign >= 0 ) {
   1.120 +            final BigDecimal temp = zigBounce;
   1.121 +            zigBounce = zagBounce;
   1.122 +            zagBounce = temp;
   1.123 +            step = step.negate();
   1.124 +        }
   1.125 +        
   1.126 +        return result;
   1.127 +    }
   1.128 +
   1.129 +    public void remove() {
   1.130 +        throw new UnsupportedOperationException("Removal is not supported.");
   1.131 +    }
   1.132 +    
   1.133 +}
   1.134 \ No newline at end of file
     2.1 --- a/task3/solution07/test/org/apidesign/apifest08/test/Task3Test.java	Fri Oct 10 22:07:25 2008 +0200
     2.2 +++ b/task3/solution07/test/org/apidesign/apifest08/test/Task3Test.java	Fri Oct 10 22:10:25 2008 +0200
     2.3 @@ -1,7 +1,11 @@
     2.4  package org.apidesign.apifest08.test;
     2.5  
     2.6 +import java.math.BigDecimal;
     2.7 +import java.util.Currency;
     2.8  import junit.framework.TestCase;
     2.9  import org.apidesign.apifest08.currency.Convertor;
    2.10 +import org.apidesign.apifest08.currency.MonetaryAmount;
    2.11 +import org.apidesign.apifest08.currency.anothervendor.ZigZaggingBidirectionalConvertor;
    2.12  
    2.13  /** The exchange rates are not always the same. They are changing. Day by day,
    2.14   * hour by hour, minute by minute. For every bank it is important to always
    2.15 @@ -28,6 +32,10 @@
    2.16      protected void tearDown() throws Exception {
    2.17      }
    2.18  
    2.19 +    protected static final Currency CZK = Currency.getInstance( "CZK" );
    2.20 +    protected static final Currency SKK = Currency.getInstance( "SKK" );
    2.21 +    protected static final Currency USD = Currency.getInstance( "USD" );
    2.22 +
    2.23      // Backward compatibly enhance your existing API to support following
    2.24      // usecases:
    2.25      //
    2.26 @@ -51,7 +59,11 @@
    2.27          // then 1USD = 15.02CZK
    2.28          // and so on and on up to 1USD = 16CZK
    2.29          // and then another round to 15, etc.
    2.30 -        return null;
    2.31 +        final MonetaryAmount oneUSD = new MonetaryAmount( 1, USD );
    2.32 +        final BigDecimal startAmount = new BigDecimal( 16 );
    2.33 +        final BigDecimal endAmount = new BigDecimal( 15 );
    2.34 +        final BigDecimal stepAmount = BigDecimal.ONE.movePointLeft( 2 ).negate();
    2.35 +        return new ContractImposingDelegatingConvertor( new ZigZaggingBidirectionalConvertor( oneUSD, CZK, startAmount, endAmount, stepAmount ) );
    2.36      }
    2.37  
    2.38      public void testFewQueriesForOnlineConvertor() {
    2.39 @@ -64,20 +76,39 @@
    2.40          doFewQueriesForOnlineConvertor(c);
    2.41      }
    2.42  
    2.43 -    static void doFewQueriesForOnlineConvertor(Convertor c) {
    2.44 +    static void doFewQueriesForOnlineConvertor( final Convertor c ) {
    2.45          // convert $5 to CZK using c:
    2.46 +        final Convertor.ConversionResult r1 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 5, USD ), CZK ) );
    2.47 +        final MonetaryAmount a1 = r1.getNetAmount();
    2.48          //assertEquals("Result is 80 CZK");
    2.49 +        assertNotNull( a1 );
    2.50 +        assertEquals( 80.0, a1.getAmount().doubleValue() );
    2.51 +        assertEquals( CZK, a1.getCurrency() );
    2.52  
    2.53          // convert $8 to CZK using c:
    2.54 +        final Convertor.ConversionResult r2 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 8, USD ), CZK ) );
    2.55 +        final MonetaryAmount a2 = r2.getNetAmount();
    2.56          //assertEquals("Result is 127.92 CZK");
    2.57 +        assertNotNull( a2 );
    2.58 +        assertEquals( 12792.0, a2.getAmount().movePointRight( 2 ).doubleValue() );
    2.59 +        assertEquals( CZK, a2.getCurrency() );
    2.60  
    2.61          // convert $1 to CZK using c:
    2.62 +        final Convertor.ConversionResult r3 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 1, USD ), CZK ) );
    2.63 +        final MonetaryAmount a3 = r3.getNetAmount();
    2.64          //assertEquals("Result is 15.98 CZK");
    2.65 +        assertNotNull( a3 );
    2.66 +        assertEquals( 1598.0, a3.getAmount().movePointRight( 2 ).doubleValue() );
    2.67 +        assertEquals( CZK, a3.getCurrency() );
    2.68  
    2.69          // convert 15.97CZK to USD using c:
    2.70 +        final BigDecimal s4 = new BigDecimal( 1597 ).movePointLeft( 2 );
    2.71 +        final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( s4, CZK ), USD ) );
    2.72 +        final MonetaryAmount a4 = r4.getNetAmount();
    2.73          //assertEquals("Result is 1$");
    2.74 -
    2.75 -        fail("Implement me!");
    2.76 +        assertNotNull( a4 );
    2.77 +        assertEquals( 1.0, a4.getAmount().doubleValue() );
    2.78 +        assertEquals( USD, a4.getCurrency() );
    2.79      }
    2.80  
    2.81      /** Join the convertors and show they behave sane.
    2.82 @@ -88,16 +119,26 @@
    2.83              return;
    2.84          }
    2.85          
    2.86 -        Convertor c = Task2Test.merge(
    2.87 +        final Convertor c = Task2Test.merge(
    2.88              createOnlineCZKUSDConvertor(),
    2.89              Task1Test.createSKKtoCZK()
    2.90          );
    2.91  
    2.92 -        // convert 16CZK to SKK using c:
    2.93 +        // convert 16CZK using c:
    2.94 +        final Convertor.ConversionResult r4 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 16, CZK ), SKK ) );
    2.95 +        final MonetaryAmount a4 = r4.getNetAmount();
    2.96          // assertEquals("Result is 20 SKK");
    2.97 +        assertNotNull( a4 );
    2.98 +        assertEquals( 20.0, a4.getAmount().doubleValue() );
    2.99 +        assertEquals( SKK, a4.getCurrency() );
   2.100  
   2.101          // convert 500SKK to CZK using c:
   2.102 +        final Convertor.ConversionResult r5 = c.convert( new Convertor.ConversionRequest( new MonetaryAmount( 500, SKK ), CZK ) );
   2.103 +        final MonetaryAmount a5 = r5.getNetAmount();
   2.104          // assertEquals("Result is 400 CZK");
   2.105 +        assertNotNull( a5 );
   2.106 +        assertEquals( 400.0, a5.getAmount().doubleValue() );
   2.107 +        assertEquals( CZK, a5.getCurrency() );
   2.108  
   2.109          doFewQueriesForOnlineConvertor(c);
   2.110      }