/*
* 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.validity.impl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Singleton;
import javax.money.spi.Bootstrap;
import org.javamoney.validity.RelatedValidityInfo;
import org.javamoney.validity.RelatedValidityQuery;
import org.javamoney.validity.ValidityInfo;
import org.javamoney.validity.ValidityQuery;
import org.javamoney.validity.ValidityType;
import org.javamoney.validity.spi.RelatedValidityProviderSpi;
import org.javamoney.validity.spi.ValiditiesSingletonSpi;
import org.javamoney.validity.spi.ValidityProviderSpi;
/**
* This class models the an internal service class, that provides the base
* functionality required for the {@link ValiditiesSingletonSpi} implementation.
* It is extended for different runtime scenarios, hereby allowing the spi
* implementation loaded using different mechanisms.
*
* @author Anatole Tresch
* @author Werner Keil
*/
@Singleton
public class DefaultValiditiesSingletonSpi implements ValiditiesSingletonSpi {
/** Loaded validity providers. */
private final Map<String, ValidityProviderSpi> validityProviders = new ConcurrentHashMap<String, ValidityProviderSpi>();
/** Loaded validity providers. */
private final Map<Class, List<ValidityProviderSpi>> validityProvidersPerType = new ConcurrentHashMap<Class, List<ValidityProviderSpi>>();
/** Loaded related validity providers. */
private final Map<String, RelatedValidityProviderSpi> relatedValidityProviders = new ConcurrentHashMap<String, RelatedValidityProviderSpi>();
/** Loaded related validity providers. */
private final Map<Class, List<RelatedValidityProviderSpi>> relatedValidityProvidersPerType = new ConcurrentHashMap<Class, List<RelatedValidityProviderSpi>>();
/**
* Constructor, also loading the registered spi's.
*/
public DefaultValiditiesSingletonSpi() {
reload();
}
public <T> Set<String> getValiditySources(Class<T> type) {
List<ValidityProviderSpi> list = validityProvidersPerType.get(type);
if (list == null) {
return Collections.emptySet();
}
Set<String> result = new HashSet<String>();
for (ValidityProviderSpi spi : list) {
result.add(spi.getProviderId());
}
return result;
}
public <T, R> Set<String> getRelatedValiditySources(Class<T> type,
Class<R> relatedType) {
List<RelatedValidityProviderSpi> list = relatedValidityProvidersPerType
.get(type);
if (list == null) {
return Collections.emptySet();
}
Set<String> result = new HashSet<String>();
for (RelatedValidityProviderSpi spi : list) {
if (spi.getRelatedItemTypes(type).contains(relatedType)) {
result.add(spi.getProviderId());
}
}
return result;
}
public <T> Collection<ValidityInfo<T>> getValidityInfo(
ValidityQuery<T> query) {
List<ValidityInfo<T>> result = new ArrayList<ValidityInfo<T>>();
List<ValidityProviderSpi> list = validityProvidersPerType.get(query
.getItemType());
if (list == null) {
return Collections.emptySet();
}
for (ValidityProviderSpi validityProviderSpi : list) {
if (validityProviderSpi.getValidityTypes().contains(
query.getValidityType())) {
result.addAll(validityProviderSpi.getValidityInfo(query));
}
}
return result;
}
public <T, R> Collection<RelatedValidityInfo<T, R>> getRelatedValidityInfo(
RelatedValidityQuery<T, R> query) {
List<RelatedValidityInfo<T, R>> result = new ArrayList<RelatedValidityInfo<T, R>>();
List<RelatedValidityProviderSpi> list = relatedValidityProvidersPerType
.get(query
.getItemType());
if (list == null) {
return Collections.emptySet();
}
for (RelatedValidityProviderSpi validityProviderSpi : list) {
if (validityProviderSpi.getRelatedItemTypes(
query.getItemType()).contains(
query.getRelatedToType())) {
result.addAll(validityProviderSpi.getRelatedValidityInfo(query));
}
}
return result;
}
public <T> Set<Class> getRelatedValidityRelationTypes(Class<T> type) {
Set<Class> result = new HashSet<Class>();
for (RelatedValidityProviderSpi validityProviderSpi : this.relatedValidityProviders
.values()) {
if (validityProviderSpi.getItemTypes().contains(type)) {
result.addAll(validityProviderSpi.getRelatedItemTypes(type));
}
}
return result;
}
public Set<Class> getRelatedValidityItemTypes() {
Set<Class> result = new HashSet<Class>();
for (RelatedValidityProviderSpi validityProviderSpi : this.relatedValidityProviders
.values()) {
result.addAll(validityProviderSpi.getItemTypes());
}
return result;
}
public Set<Class> getValidityItemTypes() {
Set<Class> result = new HashSet<Class>();
for (ValidityProviderSpi validityProviderSpi : this.validityProviders
.values()) {
result.addAll(validityProviderSpi.getItemTypes());
}
return result;
}
public <T,R> Set<ValidityType> getRelatedValidityTypes(Class<T> type, Class<R> relatedType) {
Set<ValidityType> result = new HashSet<ValidityType>();
for (RelatedValidityProviderSpi validityProviderSpi : this.relatedValidityProvidersPerType
.get(type)) {
result.addAll(validityProviderSpi.getValidityTypes(type, relatedType));
}
return result;
}
public <T> Set<ValidityType> getValidityTypes(Class<T> type) {
Set<ValidityType> result = new HashSet<ValidityType>();
for (ValidityProviderSpi validityProviderSpi : this.validityProvidersPerType
.get(type)) {
result.addAll(validityProviderSpi.getValidityTypes());
}
return result;
}
/**
* This method reloads the providers available from the
* {@link ServiceLoader}. This adds providers that were not yet visible
* before.
*/
public void reload() {
for (ValidityProviderSpi validitySpi : Bootstrap.getServices(ValidityProviderSpi.class)) {
ValidityProviderSpi prov = this.validityProviders
.get(validitySpi.getProviderId());
if (prov != null) {
throw new IllegalStateException(
"Duplicate ValidityProviderSpi: "
+ validitySpi.getProviderId());
}
this.validityProviders
.put(validitySpi.getProviderId(), validitySpi);
for (Class type : validitySpi.getItemTypes()) {
List<ValidityProviderSpi> provList = this.validityProvidersPerType
.get(type);
if (provList == null) {
provList = new ArrayList<ValidityProviderSpi>();
this.validityProvidersPerType.put(
type,
provList);
}
provList.add(validitySpi);
}
}
for (RelatedValidityProviderSpi relatedValiditySpi : Bootstrap.getServices(RelatedValidityProviderSpi.class)) {
RelatedValidityProviderSpi prov = this.relatedValidityProviders
.get(relatedValiditySpi.getProviderId());
if (prov != null) {
throw new IllegalStateException(
"Duplicate RelatedValidityProviderSpi: "
+ relatedValiditySpi.getProviderId());
}
this.relatedValidityProviders.put(
relatedValiditySpi.getProviderId(),
relatedValiditySpi);
for (Class type : relatedValiditySpi.getItemTypes()) {
List<RelatedValidityProviderSpi> provList = this.relatedValidityProvidersPerType
.get(type);
if (provList == null) {
provList = new ArrayList<RelatedValidityProviderSpi>();
this.relatedValidityProvidersPerType.put(
type,
provList);
}
provList.add(relatedValiditySpi);
}
}
}
@Override
public <T, R> Set<String> getRelatedValidityProviderIds(Class<T> type,
Class<R> relatedType) {
return this.relatedValidityProviders.keySet();
}
@Override
public <T> Set<String> getValidityProviderIds(Class<T> type) {
return this.validityProviders.keySet();
}
}