/*
* Copyright (c) 2012, 2013, Credit Suisse (Anatole Tresch), Werner Keil.
*
* 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.format.internal;
import org.javamoney.format.ItemFormat;
import org.javamoney.format.ItemFormatException;
import org.javamoney.format.LocalizationContext;
import org.javamoney.format.spi.ItemFormatFactorySpi;
import org.javamoney.format.spi.TokenizeableFormatsSingletonSpi;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Singleton;
import javax.money.spi.Bootstrap;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* This is the base class for implementing the
* {@link org.javamoney.format.spi.TokenizeableFormatsSingletonSpi}.
*
* @author Anatole Tresch
*/
@Singleton
public class DefaultTokenizeableFormatsSingletonSpi implements TokenizeableFormatsSingletonSpi{
@SuppressWarnings("rawtypes")
private Map<Class,Set<ItemFormatFactorySpi>> formatMap = new ConcurrentHashMap<Class,Set<ItemFormatFactorySpi>>();
private static final Logger LOG = LoggerFactory.getLogger(DefaultTokenizeableFormatsSingletonSpi.class);
public DefaultTokenizeableFormatsSingletonSpi(){
reload();
}
@Override
public Collection<String> getSupportedStyleIds(Class<?> targetType){
Set<String> result = new HashSet<String>();
Set<ItemFormatFactorySpi> factories = formatMap.get(targetType);
if(factories == null){
return Collections.emptySet();
}
for(ItemFormatFactorySpi spi : factories){
result.addAll(spi.getSupportedStyleIds());
}
return result;
}
@Override
public boolean isSupportedStyle(Class<?> targetType, String styleId){
Set<ItemFormatFactorySpi> factories = formatMap.get(targetType);
if(factories == null){
return false;
}
Set<String> result = new HashSet<String>();
for(ItemFormatFactorySpi spi : factories){
if(spi.isSupportedStyle(styleId)){
return true;
}
}
return false;
}
@Override
public <T> ItemFormat<T> getItemFormat(Class<T> targetType, LocalizationContext style) throws ItemFormatException{
@SuppressWarnings("rawtypes") Set<ItemFormatFactorySpi> factories = formatMap.get(targetType);
if(factories == null){
throw new ItemFormatException("No formatter factories loaded for " + targetType.getName());
}
for(ItemFormatFactorySpi spi : factories){
ItemFormat<T> itemFormatter = spi.getItemFormat(style);
if(itemFormatter != null){
return itemFormatter;
}
}
ItemFormat format = null;
Class<? extends ItemFormat<T>> formatClass = (Class<? extends ItemFormat<T>>)style.getDefaultItemFormatClass();
if(formatClass!=null){
try{
format = ItemFormat.class.cast(formatClass.newInstance());
}
catch(InstantiationException | IllegalAccessException e){
LOG.error("Error instantiating default format for: " + style, e);
}
}
if(format==null){
format = style.get(ItemFormat.class);
}
if(format==null){
throw new ItemFormatException("No formatter could be created for " + targetType.getName() + ", " + style);
}
return format;
}
/**
* Loads and registers the {@link org.javamoney.format.spi.ItemFormatFactorySpi} instances. It also
* checks for the types exposed.
*/
public void reload(){
for(ItemFormatFactorySpi t : Bootstrap.getServices(ItemFormatFactorySpi.class)){
try{
if(t.getTargetClass() == null){
throw new IllegalArgumentException("ItemFormatterFactorySpi of type: " + t.getClass().getName() +
" does not define a target type.");
}
Set<ItemFormatFactorySpi> spis = this.formatMap.get(t.getTargetClass());
if(spis == null){
spis = new HashSet<ItemFormatFactorySpi>();
this.formatMap.put(t.getTargetClass(), spis);
}
spis.add(t);
}
catch(Exception e){
LOG.warn("Error loading ItemFormatFactorySpi.", e);
}
}
}
@Override
public LocalizationContext getLocalizationStyle(Class<?> targetType, String styleId){
LocalizationContext style = LocalizationContext.of(targetType, styleId);
if(style == null){
style = new LocalizationContext.Builder(targetType, styleId).build();
}
return style;
}
}