/*
* Copyright (c) 2012, 2013, Werner Keil, Credit Suisse (Anatole Tresch).
*
* 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.
*
*
* Contributors: Anatole Tresch - initial version.
*/
package org.javamoney.cdi.internal;
import org.javamoney.cdi.api.AmountSpec;
import org.javamoney.cdi.api.CurrencySpec;
import org.javamoney.cdi.api.FormatSpec;
import org.javamoney.cdi.api.ConversionSpec;
import javax.enterprise.context.Dependent;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.money.*;
import javax.money.convert.*;
import javax.money.format.AmountFormatQuery;
import javax.money.format.AmountFormatQueryBuilder;
import javax.money.format.MonetaryAmountFormat;
import javax.money.format.MonetaryFormats;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Producer bean that bridges to the javamoney API.
*/
public final class MonetaryProducer {
private static final Logger LOG = Logger.getLogger(MonetaryProducer.class.getName());
/**
* Class is not instanciatable.
*/
private MonetaryProducer(){}
@Produces @Dependent
public static CurrencyUnit currencyUnit(InjectionPoint ip){
CurrencySpec specAnnot = ip.getAnnotated()!=null?
ip.getAnnotated().getAnnotation(CurrencySpec.class):
null;
if(specAnnot==null){
Currency jdkDefault = Currency.getInstance(Locale.getDefault());
if(jdkDefault!=null) {
return Monetary.getCurrency(jdkDefault.getCurrencyCode());
}else{
throw new MonetaryException("No default currency found.");
}
}
return Monetary.getCurrency(createCurrencyQuery(specAnnot));
}
@Produces @Dependent
public static Collection<CurrencyUnit> currencyUnits(InjectionPoint ip){
CurrencySpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(CurrencySpec.class):null;
if(specAnnot!=null){
return Monetary.getCurrencies(createCurrencyQuery(specAnnot));
}
return Monetary.getCurrencies();
}
@Produces @Dependent
public static ExchangeRateProvider rateProvider(InjectionPoint ip){
ConversionSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(ConversionSpec.class):null;
if(specAnnot!=null){
return MonetaryConversions.getExchangeRateProvider(createConversionQuery(specAnnot));
}
return MonetaryConversions.getExchangeRateProvider();
}
@Produces @Dependent
public static Collection<ExchangeRateProvider> rateProviders(InjectionPoint ip){
List<ExchangeRateProvider> providers = new ArrayList<>();
ConversionSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(ConversionSpec.class):null;
if(specAnnot!=null && specAnnot.providers().length>0){
for(String providerId:specAnnot.providers()){
providers.add(MonetaryConversions.getExchangeRateProvider(providerId));
}
}else{
for(String providerId:MonetaryConversions.getConversionProviderNames()){
providers.add(MonetaryConversions.getExchangeRateProvider(providerId));
}
}
return providers;
}
@Produces @Dependent
public static CurrencyConversion currencyConversion(InjectionPoint ip){
ConversionSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(ConversionSpec.class):null;
if(specAnnot==null){
throw new IllegalArgumentException("@RateSpec is required.");
}
return MonetaryConversions.getConversion(createConversionQuery(specAnnot));
}
@Produces @Dependent
public static ExchangeRate exchangeRate(InjectionPoint ip){
ConversionSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(ConversionSpec.class):null;
if(specAnnot==null){
throw new IllegalArgumentException("@RateSpec is required.");
}
ConversionQuery query = createConversionQuery(specAnnot);
return MonetaryConversions.getExchangeRateProvider(query)
.getExchangeRate(query);
}
@Produces @Dependent
public static Collection<ExchangeRate> exchangeRates(InjectionPoint ip){
ConversionSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(ConversionSpec.class):null;
if(specAnnot==null){
throw new IllegalArgumentException("@RateSpec is required.");
}
ConversionQuery query = createConversionQuery(specAnnot);
Collection<String> providers = query.getProviderNames();
if(providers.isEmpty()){
providers = MonetaryConversions.getConversionProviderNames();
}
List<ExchangeRate> rates = new ArrayList<>();
for(String providerId:providers){
ExchangeRateProvider provider = MonetaryConversions.getExchangeRateProvider(providerId);
try {
ExchangeRate rate = provider.getExchangeRate(query);
if (rate != null) {
rates.add(rate);
}
}catch(Exception e){
LOG.log(Level.FINE,
"Could not evaluate rate from provider '" + providerId + "': "+ query,
e);
}
}
return rates;
}
@Produces @Dependent
public static MonetaryAmountFormat amountFormat(InjectionPoint ip){
FormatSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(FormatSpec.class):null;
if(specAnnot==null){
throw new IllegalArgumentException("@FormatName is required.");
}
return MonetaryFormats.getAmountFormat(createAmountFormatQuery(
specAnnot,
ip.getAnnotated().getAnnotation(AmountSpec.class)));
}
@Produces @Dependent
public static Collection<MonetaryAmountFormat> amountFormats(InjectionPoint ip){
FormatSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(FormatSpec.class):null;
if(specAnnot==null){
throw new IllegalArgumentException("@FormatName is required.");
}
return MonetaryFormats.getAmountFormats(createAmountFormatQuery(
specAnnot,
ip.getAnnotated().getAnnotation(AmountSpec.class)));
}
@Produces @Dependent
public static MonetaryAmountFactory amountFactory(InjectionPoint ip){
AmountSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(AmountSpec.class):null;
if(specAnnot!=null){
return Monetary.getAmountFactory(createAmountQuery(specAnnot));
}
return Monetary.getDefaultAmountFactory();
}
@Produces @Dependent
public static Collection<MonetaryAmountFactory> amountFactories(InjectionPoint ip){
AmountSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(AmountSpec.class):null;
if(specAnnot!=null){
return Collection.class.cast(Monetary.getAmountFactories(createAmountQuery(specAnnot)));
}
return Collection.class.cast(Monetary.getAmountFactories());
}
@Produces @Dependent
public static CurrencyQuery currencyQuery(InjectionPoint ip){
CurrencySpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(CurrencySpec.class):null;
if(specAnnot==null){
return null;
}
return createCurrencyQuery(specAnnot);
}
@Produces @Dependent
public static ConversionQuery conversionQuery(InjectionPoint ip){
ConversionSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(ConversionSpec.class):null;
if(specAnnot==null){
return null;
}
return createConversionQuery(specAnnot);
}
@Produces @Dependent
public static AmountFormatQuery amountFormatQuery(InjectionPoint ip){
FormatSpec specAnnot = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(FormatSpec.class):null;
if(specAnnot==null){
return null;
}
AmountSpec amountSpec = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(AmountSpec.class):null;
return createAmountFormatQuery(specAnnot, amountSpec);
}
@Produces @Dependent
public static MonetaryAmountFactoryQuery amountFactoryQuery(InjectionPoint ip){
AmountSpec amountSpec = ip.getAnnotated()!=null?ip.getAnnotated().getAnnotation(AmountSpec.class):null;
if(amountSpec==null){
return null;
}
return createAmountQuery(amountSpec);
}
private static CurrencyQuery createCurrencyQuery(CurrencySpec specAnnot) {
CurrencyQueryBuilder b = CurrencyQueryBuilder.of();
b.setCountries(convertToCountries(specAnnot.countries()));
b.setCurrencyCodes(specAnnot.codes());
b.setNumericCodes(specAnnot.numericCodes());
if(specAnnot.attributes().length>0){
applyAttributes(specAnnot.attributes(), b);
}
if(specAnnot.providers().length>0){
b.setProviderNames(specAnnot.providers());
}
return b.build();
}
private static Locale[] convertToCountries(String[] codes) {
Locale[] locales = new Locale[codes.length];
for(int i=0;i<codes.length;i++){
locales[i] = new Locale("", codes[i]);
}
return locales;
}
private static ConversionQuery createConversionQuery(ConversionSpec specAnnot) {
ConversionQueryBuilder b = ConversionQueryBuilder.of();
if(!specAnnot.baseCurrency().isEmpty()){
b.setBaseCurrency(specAnnot.baseCurrency());
}
if(!specAnnot.termCurrency().isEmpty()){
b.setTermCurrency(specAnnot.termCurrency());
}
if(specAnnot.attributes().length>0){
applyAttributes(specAnnot.attributes(), b);
}
if(specAnnot.providers().length>0){
b.setProviderNames(specAnnot.providers());
}
if(specAnnot.rateTypes().length==0){
b.setRateTypes(specAnnot.rateTypes());
}
return b.build();
}
private static AmountFormatQuery createAmountFormatQuery(FormatSpec specAnnot, AmountSpec amountSpec) {
AmountFormatQueryBuilder b = AmountFormatQueryBuilder.of(specAnnot.name());
if(specAnnot.providers().length>0){
b.setProviderNames(specAnnot.providers());
}
if(specAnnot.attributes().length>0){
applyAttributes(specAnnot.attributes(), b);
}
if(!specAnnot.locale().isEmpty()){
b.setLocale(createLocale(specAnnot.locale()));
}else{
// Required to avoid NOE, see https://github.com/JavaMoney/jsr354-ri/issues/156
b.setLocale(Locale.getDefault());
}
if(amountSpec!=null){
b.setMonetaryAmountFactory(Monetary.getAmountFactory(createAmountQuery(amountSpec)));
}
return b.build();
}
private static Locale createLocale(String locale) {
String[] parts = locale.split("\\_", 3);
switch(parts.length){
case 1:
return new Locale(parts[0]);
case 2:
return new Locale(parts[0], parts[1]);
default:
return new Locale(parts[0], parts[1], parts[2]);
}
}
private static MonetaryAmountFactoryQuery createAmountQuery(AmountSpec specAnnot) {
MonetaryAmountFactoryQueryBuilder b = MonetaryAmountFactoryQueryBuilder.of();
if(specAnnot.value()!=MonetaryAmount.class){
b.setTargetType(specAnnot.value());
}
if(specAnnot.providers().length>0){
b.setProviderNames(specAnnot.providers());
}
if(specAnnot.attributes().length>0){
applyAttributes(specAnnot.attributes(), b);
}
if(specAnnot.fixedScale()){
b.setFixedScale(true);
}
if(specAnnot.maxScale()>0){
b.setMaxScale(specAnnot.maxScale());
}
if(specAnnot.precision()>0){
b.setPrecision(specAnnot.precision());
}
return b.build();
}
private static void applyAttributes(String[] attributes, AbstractQueryBuilder b) {
for(String attr:attributes){
String[] parts = attr.split("=", 2);
b.set(parts[0], parts[1]);
}
}
}