001/*
002 * CREDIT SUISSE IS WILLING TO LICENSE THIS SPECIFICATION TO YOU ONLY UPON THE
003 * CONDITION THAT YOU ACCEPT ALL OF THE TERMS CONTAINED IN THIS AGREEMENT.
004 * PLEASE READ THE TERMS AND CONDITIONS OF THIS AGREEMENT CAREFULLY. BY
005 * DOWNLOADING THIS SPECIFICATION, YOU ACCEPT THE TERMS AND CONDITIONS OF THE
006 * AGREEMENT. IF YOU ARE NOT WILLING TO BE BOUND BY IT, SELECT THE "DECLINE"
007 * BUTTON AT THE BOTTOM OF THIS PAGE. Specification: JSR-354 Money and Currency
008 * API ("Specification") Copyright (c) 2012-2013, Credit Suisse All rights
009 * reserved.
010 */
011package org.javamoney.moneta;
012
013import org.javamoney.moneta.internal.ConfigurableCurrencyUnitProvider;
014
015import javax.money.CurrencyUnit;
016import javax.money.MonetaryException;
017import java.util.Locale;
018import java.util.Objects;
019
020/**
021 * Implementation of {@link javax.money.CurrencyUnit} that allows to create new instances using a fluent API.
022 * Instances created also can be added to the {@link org.javamoney.moneta.internal.ConfigurableCurrencyUnitProvider}
023 * singleton, which publishes the instances, so they are visible from the {@link javax.money.MonetaryCurrencies}
024 * singleton.
025 */
026public final class BuildableCurrencyUnit implements CurrencyUnit, Comparable<CurrencyUnit>{
027
028    /**
029     * The uniqie currency code.
030     */
031    private String currencyCode;
032    /**
033     * The (optional) numeric code.
034     */
035    private int numericCode;
036    /**
037     * The default fraction digits.
038     */
039    private int defaultFractionDigits;
040
041    /**
042     * Constructor, called from the Builder.
043     *
044     * @param builder the builder, never null.
045     */
046    private BuildableCurrencyUnit(Builder builder){
047        Objects.requireNonNull(builder.currencyCode, "currencyCode required");
048        if(builder.numericCode < -1){
049            throw new MonetaryException("numericCode must be >= -1");
050        }
051        if(builder.defaultFractionDigits < 0){
052            throw new MonetaryException("defaultFractionDigits must be >= 0");
053        }
054        this.defaultFractionDigits = builder.defaultFractionDigits;
055        this.numericCode = builder.numericCode;
056        this.currencyCode = builder.currencyCode;
057    }
058
059    @Override
060    public String getCurrencyCode(){
061        return currencyCode;
062    }
063
064    @Override
065    public int getNumericCode(){
066        return numericCode;
067    }
068
069    @Override
070    public int getDefaultFractionDigits(){
071        return defaultFractionDigits;
072    }
073
074    @Override
075    public int compareTo(CurrencyUnit o){
076        return this.currencyCode.compareTo(o.getCurrencyCode());
077    }
078
079    /* (non-Javadoc)
080     * @see java.lang.Object#hashCode()
081     */
082    @Override
083    public int hashCode(){
084        final int prime = 31;
085        int result = 1;
086        result = prime * result + ((currencyCode == null) ? 0 : currencyCode.hashCode());
087        return result;
088    }
089
090    /* (non-Javadoc)
091     * @see java.lang.Object#equals(java.lang.Object)
092     */
093    @Override
094    public boolean equals(Object obj){
095        if(this == obj){
096            return true;
097        }
098        if(obj == null){
099            return false;
100        }
101        if(getClass() != obj.getClass()){
102            return false;
103        }
104        BuildableCurrencyUnit other = (BuildableCurrencyUnit) obj;
105        if(currencyCode == null){
106            if(other.currencyCode != null){
107                return false;
108            }
109        }else if(!currencyCode.equals(other.currencyCode)){
110            return false;
111        }
112        return true;
113    }
114
115    /* (non-Javadoc)
116     * @see java.lang.Object#toString()
117     */
118    @Override
119    public String toString(){
120        return "BuildableCurrencyUnit [currencyCode=" + currencyCode + ", numericCode=" + numericCode +
121                ", defaultFractionDigits=" + defaultFractionDigits + "]";
122    }
123
124
125    /**
126     * Builder for constructing new instances o{@link org.javamoney.moneta.BuildableCurrencyUnit} using a fluent
127     * API.
128     */
129    public static final class Builder{
130        /**
131         * The currency code.
132         */
133        private String currencyCode;
134        /**
135         * The (optional) numeric code.
136         */
137        private int numericCode = -1;
138        /**
139         * The default fraction digits.
140         */
141        private int defaultFractionDigits = 2;
142
143        /**
144         * Creats a new Builder.
145         *
146         * @param currencyCode the (unique) and identifying currency code, not null.
147         */
148        public Builder(String currencyCode){
149            Objects.requireNonNull(currencyCode, "currencyCode required");
150            this.currencyCode = currencyCode;
151        }
152
153        /**
154         * Allows to set the currenc< code, for creating multiple instances, using one Builder.
155         *
156         * @param currencyCode the (unique) and identifying currency code, not null.
157         * @return the Builder, for chaining.
158         * @see javax.money.CurrencyUnit#getCurrencyCode()
159         */
160        public Builder setCurrencyCode(String currencyCode){
161            Objects.requireNonNull(currencyCode, "currencyCode required");
162            this.currencyCode = currencyCode;
163            return this;
164        }
165
166        /**
167         * Set the numeric code (optional).
168         *
169         * @param numericCode The numeric currency code, >= -1. .1 hereby means <i>undefined</i>.
170         * @return the Builder, for chaining.
171         * @see javax.money.CurrencyUnit#getNumericCode()
172         */
173        public Builder setNumericCode(int numericCode){
174            if(numericCode < -1){
175                throw new IllegalArgumentException("numericCode must be >= -1");
176            }
177            this.numericCode = numericCode;
178            return this;
179        }
180
181        /**
182         * Set the default fraction digits.
183         *
184         * @param defaultFractionDigits the default fraction digits, >= 0.
185         * @return
186         * @see javax.money.CurrencyUnit#getDefaultFractionDigits()
187         */
188        public Builder setDefaultFractionDigits(int defaultFractionDigits){
189            if(defaultFractionDigits < 0){
190                throw new IllegalArgumentException("defaultFractionDigits must be >= 0");
191            }
192            this.defaultFractionDigits = defaultFractionDigits;
193            return this;
194        }
195
196        /**
197         * Creates a new instance of {@link org.javamoney.moneta.BuildableCurrencyUnit}.
198         *
199         * @return the new CurrencyUnit instance.
200         * @throws MonetaryException, if creation fails
201         */
202        public BuildableCurrencyUnit create(){
203            return create(false);
204        }
205
206        /**
207         * Creates a new instance of {@link org.javamoney.moneta.BuildableCurrencyUnit} and publishes it so it is
208         * accessible from the {@code MonetaryCurrencies} singleton.
209         *
210         * @param register if {@code true} the instance created is published so it is accessible from
211         *                 the {@code MonetaryCurrencies} singleton.
212         * @return the new CurrencyUnit instance.
213         * @see javax.money.MonetaryCurrencies#getCurrency(String)
214         */
215        public BuildableCurrencyUnit create(boolean register){
216            BuildableCurrencyUnit cu = new BuildableCurrencyUnit(this);
217            if(register){
218                ConfigurableCurrencyUnitProvider.registerCurrencyUnit(cu);
219            }
220            return cu;
221        }
222
223        /**
224         * Creates a new instance of {@link org.javamoney.moneta.BuildableCurrencyUnit} and publishes it so it is
225         * accessible from the {@code MonetaryCurrencies} singleton.
226         *
227         * @param register if {@code true} the instance created is published so it is accessible from
228         *                 the {@code MonetaryCurrencies} singleton.
229         * @param locale   country Locale for making the currency for the given country.
230         * @return the new CurrencyUnit instance.
231         * @see javax.money.MonetaryCurrencies#getCurrency(String)
232         * @see javax.money.MonetaryCurrencies#getCurrency(java.util.Locale)
233         */
234        public BuildableCurrencyUnit create(boolean register, Locale locale){
235            BuildableCurrencyUnit cu = new BuildableCurrencyUnit(this);
236            if(register){
237                ConfigurableCurrencyUnitProvider.registerCurrencyUnit(cu);
238                ConfigurableCurrencyUnitProvider.registerCurrencyUnit(cu, locale);
239            }
240            return cu;
241        }
242    }
243
244}