001/** 002 * Copyright (c) 2012, 2014, Credit Suisse (Anatole Tresch), Werner Keil and others by the @author tag. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016package org.javamoney.moneta.internal; 017 018import javax.money.*; 019import javax.money.spi.Bootstrap; 020import javax.money.spi.MonetaryAmountFactoryProviderSpi; 021import javax.money.spi.MonetaryAmountFactoryProviderSpi.QueryInclusionPolicy; 022import javax.money.spi.MonetaryAmountsSingletonQuerySpi; 023import java.util.*; 024 025/** 026 * Default implementation ot {@link javax.money.spi.MonetaryAmountsSingletonSpi} loading the SPIs on startup 027 * initially once, using the 028 * JSR's {@link javax.money.spi.Bootstrap} mechanism. 029 */ 030public class DefaultMonetaryAmountsSingletonQuerySpi implements MonetaryAmountsSingletonQuerySpi{ 031 032 private static final Comparator<MonetaryAmountFactoryProviderSpi<? extends MonetaryAmount>> CONTEXT_COMPARATOR = 033 (f1, f2) -> { 034 int compare = 0; 035 MonetaryContext c1 = f1.getMaximalMonetaryContext(); 036 MonetaryContext c2 = f2.getMaximalMonetaryContext(); 037 if(c1.getPrecision() == 0 && c2.getPrecision() != 0){ 038 compare = -1; 039 } 040 if(compare == 0 && c2.getPrecision() == 0 && c1.getPrecision() != 0){ 041 compare = 1; 042 } 043 if(compare == 0 && c1.getPrecision() != 0 && c2.getPrecision() > c1.getPrecision()){ 044 compare = 1; 045 } 046 if(compare == 0 && c2.getPrecision() != 0 && c2.getPrecision() < c1.getPrecision()){ 047 compare = -1; 048 } 049 if(compare == 0 && (c1.getMaxScale() > c2.getMaxScale())){ 050 compare = -1; 051 } 052 if(compare == 0 && (c1.getMaxScale() < c2.getMaxScale())){ 053 compare = 1; 054 } 055 return compare; 056 }; 057 058 059 /** 060 * (non-Javadoc) 061 * 062 * @see javax.money.spi.MonetaryAmountsSingletonQuerySpi#getAmountFactories(javax.money.MonetaryAmountFactoryQuery) 063 */ 064 @Override 065 public Collection<MonetaryAmountFactory<?>> getAmountFactories(MonetaryAmountFactoryQuery factoryQuery){ 066 Objects.requireNonNull(factoryQuery); 067 List<MonetaryAmountFactory<?>> factories = new ArrayList<>(); 068 // first check for explicit type 069 for(@SuppressWarnings("unchecked") MonetaryAmountFactoryProviderSpi<? extends MonetaryAmount> f : Bootstrap 070 .getServices(MonetaryAmountFactoryProviderSpi.class)){ 071 if(f.getQueryInclusionPolicy() == QueryInclusionPolicy.NEVER){ 072 continue; 073 } 074 if(factoryQuery.getTargetType() == f.getAmountType()){ 075 if(isPrecisionOK(factoryQuery, f.getMaximalMonetaryContext())){ 076 factories.add(f.createMonetaryAmountFactory()); 077 }else{ 078 throw new MonetaryException("Incompatible context required=" + factoryQuery + ", maximal=" + 079 f.getMaximalMonetaryContext()); 080 } 081 } 082 } 083 List<MonetaryAmountFactoryProviderSpi<? extends MonetaryAmount>> selection = new ArrayList<>(); 084 for(@SuppressWarnings("unchecked") MonetaryAmountFactoryProviderSpi<? extends MonetaryAmount> f : Bootstrap 085 .getServices(MonetaryAmountFactoryProviderSpi.class)){ 086 if(f.getQueryInclusionPolicy() == QueryInclusionPolicy.DIRECT_REFERENCE_ONLY || 087 f.getQueryInclusionPolicy() == QueryInclusionPolicy.NEVER){ 088 continue; 089 } 090 if(isPrecisionOK(factoryQuery, f.getMaximalMonetaryContext())){ 091 selection.add(f); 092 } 093 } 094 if(selection.isEmpty()){ 095 // fall back, add all selections, ignore flavor 096 for(@SuppressWarnings("unchecked") MonetaryAmountFactoryProviderSpi<? extends MonetaryAmount> f : Bootstrap 097 .getServices(MonetaryAmountFactoryProviderSpi.class)){ 098 if(f.getQueryInclusionPolicy() == QueryInclusionPolicy.DIRECT_REFERENCE_ONLY || 099 f.getQueryInclusionPolicy() == QueryInclusionPolicy.NEVER){ 100 continue; 101 } 102 if(isPrecisionOK(factoryQuery, f.getMaximalMonetaryContext())){ 103 selection.add(f); 104 } 105 } 106 } 107 if(selection.size() == 1){ 108 factories.add(selection.get(0).createMonetaryAmountFactory()); 109 } 110 Collections.sort(selection, CONTEXT_COMPARATOR); 111 factories.add(selection.get(0).createMonetaryAmountFactory()); 112 return factories; 113 } 114 115 private boolean isPrecisionOK(MonetaryAmountFactoryQuery requiredContext, MonetaryContext maximalMonetaryContext){ 116 if(maximalMonetaryContext.getPrecision() == 0){ 117 return true; 118 } 119 if(requiredContext.getPrecision() != null){ 120 if(requiredContext.getPrecision() == 0){ 121 return false; 122 } 123 if(requiredContext.getPrecision() > maximalMonetaryContext.getPrecision()){ 124 return false; 125 } 126 } 127 return null == requiredContext.getMaxScale() || 128 requiredContext.getMaxScale() <= maximalMonetaryContext.getMaxScale(); 129 } 130 131}