<commit_before>/*
 * Copyright (c) 2012, 2014, <NAME> (<NAME>), <NAME>. Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.javamoney.moneta;

import org.javamoney.moneta.internal.MoneyAmountFactory;
import org.javamoney.moneta.spi.AbstractMoney;
import org.javamoney.moneta.spi.DefaultNumberValue;
import org.javamoney.moneta.spi.MonetaryConfig;

import javax.money.*;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Default immutable implementation of {@link MonetaryAmount} based
 * on {@link BigDecimal} for the numeric representation.
 * <p/>
 * As required by {@link MonetaryAmount} this class is final, thread-safe,
 * immutable and serializable.
 * <p/>
 * This class can be configured with an arbitrary {@link MonetaryContext}. The
 * default {@link MonetaryContext} used models by default the same settings as
 * {@link MathContext#DECIMAL64} . This default {@link MonetaryContext} can also
 * be reconfigured by adding a file {@code /javamoney.properties} to the
 * classpath, with the following content:
 * <p/>
 * <pre>
 * # Default MathContext for Money
 * #-------------------------------
 * # Custom MonetaryContext, overrides default entries from
 * # org.javamoney.moneta.Money.monetaryContext
 * # RoundingMode hereby is optional (default = HALF_EVEN)
 * org.javamoney.moneta.Money.defaults.precision=256
 * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN
 * </pre>
 *
 * @author <NAME>
 * @author <NAME>
 * @version 0.7
 */
public final class Money extends AbstractMoney implements Serializable{

    /**
     * serialVersionUID.
     */
    private static final long serialVersionUID = -7565813772046251748L;

    /**
     * The default {@link MonetaryContext} applied, if not set explicitly on
     * creation.
     */
    public static final MonetaryContext DEFAULT_MONETARY_CONTEXT = initDefaultMathContext();

    /**
     * The numeric part of this amount.
     */
    private BigDecimal number;

    /**
     * Required for deserialization only.
     */
    private Money(){
    }

    /**
     * Creates a new instance os {@link Money}.
     *
     * @param currency the currency, not null.
     * @param number   the amount, not null.
     * @throws ArithmeticException If the number exceeds the capabilities of the default
     *                             {@link MonetaryContext}.
     */
    private Money(BigDecimal number, CurrencyUnit currency){
        this(number, currency, null);
    }

    /**
     * Evaluates the default {@link MonetaryContext} to be used for
     * {@link Money}. The default {@link MonetaryContext} can be configured by
     * adding a file {@code /javamoney.properties} from the classpath with the
     * following content:
     * <p/>
     * <pre>
     * # Default MathContext for Money
     * #-------------------------------
     * # Custom MathContext, overrides entries from org.javamoney.moneta.Money.mathContext
     * # RoundingMode hereby is optional (default = HALF_EVEN)
     * org.javamoney.moneta.Money.defaults.precision=256
     * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN
     * </pre>
     * <p/>
     * Hereby the roundingMode constants are the same as defined on
     * {@link RoundingMode}.
     *
     * @return default MonetaryContext, never {@code null}.
     */
    private static MonetaryContext initDefaultMathContext(){
        InputStream is = null;
        try{
            Map<String,String> config = MonetaryConfig.getConfig();
            String value = config.get("org.javamoney.moneta.Money.defaults.precision");
            if(value != null){
                int prec = Integer.parseInt(value);
                value = config.get("org.javamoney.moneta.Money.defaults.roundingMode");
                RoundingMode rm =
                        value != null ? RoundingMode.valueOf(value.toUpperCase(Locale.ENGLISH)) : RoundingMode.HALF_UP;
                MonetaryContext mc =
                        new MonetaryContext.Builder().setPrecision(prec).setAttribute(rm).setAmountType(Money.class).create();
                Logger.getLogger(Money.class.getName())
                        .info("Using custom MathContext: precision=" + prec + ", roundingMode=" + rm); // TODO why info?
                return mc;
            }else{
                MonetaryContext.Builder builder = new MonetaryContext.Builder(Money.class);
                value = config.get("org.javamoney.moneta.Money.defaults.mathContext");
                if(value != null){
                    switch(value.toUpperCase(Locale.ENGLISH)){
                        case "DECIMAL32":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL32"); // TODO why info?
                            builder.setAttribute(MathContext.DECIMAL32);
                            break;
                        case "DECIMAL64":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL64"); // TODO why info?
                            builder.setAttribute(MathContext.DECIMAL64);
                            break;
                        case "DECIMAL128":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL128"); // TODO why info?
                            builder.setAttribute(MathContext.DECIMAL128);
                            break;
                        case "UNLIMITED":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.UNLIMITED");
                            builder.setAttribute(MathContext.UNLIMITED);
                            break;
                    }
                }else{
                    Logger.getLogger(Money.class.getName()).info("Using default MathContext.DECIMAL64"); // TODO why info?
                    builder.setAttribute(MathContext.DECIMAL64);
                }
                return builder.create();
            }
        }
        catch(Exception e){
            Logger.getLogger(Money.class.getName())
                    .log(Level.SEVERE, "Error evaluating default NumericContext, using default (NumericContext.NUM64).",
                         e);
            return new MonetaryContext.Builder(Money.class).setAttribute(MathContext.DECIMAL64).create();
        }
        finally{
            if(is != null){<commit_msg>OPEN - task 2: Adjust to API changes  http://github.com/JavaMoney/javamoney-examples/issues/issue/2<commit_after>/*
 * Copyright (c) 2012, 2014, <NAME> (<NAME>), <NAME>. Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.javamoney.moneta;

import org.javamoney.moneta.internal.MoneyAmountFactory;
import org.javamoney.moneta.spi.AbstractMoney;
import org.javamoney.moneta.spi.DefaultNumberValue;
import org.javamoney.moneta.spi.MonetaryConfig;

import javax.money.*;
import java.io.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Default immutable implementation of {@link MonetaryAmount} based
 * on {@link BigDecimal} as numeric representation.
 * <p/>
 * As required by {@link MonetaryAmount} this class is final, thread-safe,
 * immutable and serializable.
 * <p/>
 * This class can be configured with an arbitrary {@link MonetaryContext}. The
 * default {@link MonetaryContext} used models by default the same settings as
 * {@link MathContext#DECIMAL64} . This default {@link MonetaryContext} can also
 * be reconfigured by adding a file {@code /javamoney.properties} to the
 * classpath, with the following content:
 * <p/>
 * <pre>
 * # Default MathContext for Money
 * #-------------------------------
 * # Custom MonetaryContext, overrides default entries from
 * # org.javamoney.moneta.Money.monetaryContext
 * # RoundingMode hereby is optional (default = HALF_EVEN)
 * org.javamoney.moneta.Money.defaults.precision=256
 * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN
 * </pre>
 *
 * @author <NAME>
 * @author <NAME>
 * @version 0.7
 */
public final class Money extends AbstractMoney implements Serializable{

    /**
     * serialVersionUID.
     */
    private static final long serialVersionUID = -7565813772046251748L;

    /**
     * The default {@link MonetaryContext} applied, if not set explicitly on
     * creation.
     */
    public static final MonetaryContext DEFAULT_MONETARY_CONTEXT = initDefaultMathContext();

    /**
     * The numeric part of this amount.
     */
    private BigDecimal number;

    /**
     * Required for deserialization only.
     */
    private Money(){
    }

    /**
     * Creates a new instance os {@link Money}.
     *
     * @param currency the currency, not null.
     * @param number   the amount, not null.
     * @throws ArithmeticException If the number exceeds the capabilities of the default
     *                             {@link MonetaryContext}.
     */
    private Money(BigDecimal number, CurrencyUnit currency){
        this(number, currency, null);
    }

    /**
     * Evaluates the default {@link MonetaryContext} to be used for
     * {@link Money}. The default {@link MonetaryContext} can be configured by
     * adding a file {@code /javamoney.properties} from the classpath with the
     * following content:
     * <p/>
     * <pre>
     * # Default MathContext for Money
     * #-------------------------------
     * # Custom MathContext, overrides entries from org.javamoney.moneta.Money.mathContext
     * # RoundingMode hereby is optional (default = HALF_EVEN)
     * org.javamoney.moneta.Money.defaults.precision=256
     * org.javamoney.moneta.Money.defaults.roundingMode=HALF_EVEN
     * </pre>
     * <p/>
     * Hereby the roundingMode constants are the same as defined on
     * {@link RoundingMode}.
     *
     * @return default MonetaryContext, never {@code null}.
     */
    private static MonetaryContext initDefaultMathContext(){
        InputStream is = null;
        try{
            Map<String,String> config = MonetaryConfig.getConfig();
            String value = config.get("org.javamoney.moneta.Money.defaults.precision");
            if(value != null){
                int prec = Integer.parseInt(value);
                value = config.get("org.javamoney.moneta.Money.defaults.roundingMode");
                RoundingMode rm =
                        value != null ? RoundingMode.valueOf(value.toUpperCase(Locale.ENGLISH)) : RoundingMode.HALF_UP;
                MonetaryContext mc =
                        new MonetaryContext.Builder().setPrecision(prec).setAttribute(rm).setAmountType(Money.class).create();
                Logger.getLogger(Money.class.getName())
                        .info("Using custom MathContext: precision=" + prec + ", roundingMode=" + rm);
                return mc;
            }else{
                MonetaryContext.Builder builder = new MonetaryContext.Builder(Money.class);
                value = config.get("org.javamoney.moneta.Money.defaults.mathContext");
                if(value != null){
                    switch(value.toUpperCase(Locale.ENGLISH)){
                        case "DECIMAL32":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL32");
                            builder.setAttribute(MathContext.DECIMAL32);
                            break;
                        case "DECIMAL64":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL64");
                            builder.setAttribute(MathContext.DECIMAL64);
                            break;
                        case "DECIMAL128":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.DECIMAL128");
                            builder.setAttribute(MathContext.DECIMAL128);
                            break;
                        case "UNLIMITED":
                            Logger.getLogger(Money.class.getName()).info("Using MathContext.UNLIMITED");
                            builder.setAttribute(MathContext.UNLIMITED);
                            break;
                    }
                }else{
                    Logger.getLogger(Money.class.getName()).info("Using default MathContext.DECIMAL64");
                    builder.setAttribute(MathContext.DECIMAL64);
                }
                return builder.create();
            }
        }
        catch(Exception e){
            Logger.getLogger(Money.class.getName())
                    .log(Level.SEVERE, "Error evaluating default NumericContext, using default (NumericContext.NUM64).",
                         e);
            return new MonetaryContext.Builder(Money.class).setAttribute(MathContext.DECIMAL64).create();
        }
        finally{
            if(is != null){
{'fraction_non_alphanumeric': 0.10870648537054176, 'fraction_numerical': 0.01010892005410408, 'mean_word_length': 2.2405997693194926, 'pattern_counts': {'":': 8, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '361751', 'n_tokens_mistral': 3808, 'n_tokens_neox': 3603, 'n_words': 972}