package com.acme.ejb.calc; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import javax.annotation.Resource; import javax.ejb.Stateless; @Stateless public class MortgageCalculatorBean implements MortgageCalculator { private static final BigDecimal TWELVE = new BigDecimal(12); private static final BigDecimal ONE_HUNDRED = new BigDecimal(100); private static final int CURRENCY_DECIMALS = 2; @Resource(name = "interestRate") private Double interestRate; /** * a = [ P(1 + r)^Y * r ] / [ (1 + r)^Y - 1 ] */ @Override public BigDecimal calculateMonthlyPayment(double principal, double interestRate, int termYears) { // System.out.println(getClass().getName() + ".calculateMonthlyPayment() call chain:"); // for (StackTraceElement e : Thread.currentThread().getStackTrace()) // { // if (!e.getClassName().equals(getClass().getName()) && // !e.getMethodName().equals("getStackTrace") && // !(e.getLineNumber() < -1)) { // System.out.println(" L " + e.getClassName() + "." + e.getMethodName() + "(line: " + e.getLineNumber() + ")"); // } // } BigDecimal p = new BigDecimal(principal); int divisionScale = p.precision() + CURRENCY_DECIMALS; BigDecimal r = new BigDecimal(interestRate).divide(ONE_HUNDRED, MathContext.UNLIMITED).divide(TWELVE, divisionScale, RoundingMode.HALF_EVEN); BigDecimal z = r.add(BigDecimal.ONE); BigDecimal tr = new BigDecimal(Math.pow(z.doubleValue(), termYears * 12)); return p.multiply(tr).multiply(r).divide(tr.subtract(BigDecimal.ONE), divisionScale, RoundingMode.HALF_EVEN) .setScale(CURRENCY_DECIMALS, RoundingMode.HALF_EVEN); } @Override public BigDecimal calculateMonthlyPayment(double principal, int termYears) { if (interestRate == null) { throw new IllegalStateException("No interest rate has been specified."); } return calculateMonthlyPayment(principal, interestRate, termYears); } @Override public double getCurrentInterestRate() { if (interestRate == null) { throw new IllegalStateException("No interest rate has been specified."); } return interestRate; } }