org.sdmxsource.sdmx.structureretrieval.engine.impl.CrossReferenceResolverEngineImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of SdmxStructureRetrieval Show documentation
Show all versions of SdmxStructureRetrieval Show documentation
Open source reference implementation of SDMX
The newest version!
/*******************************************************************************
* Copyright (c) 2013 Metadata Technology Ltd.
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License v 3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* This file is part of the SDMX Component Library.
*
* The SDMX Component Library is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* The SDMX Component Library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with The SDMX Component Library If not, see
* http://www.gnu.org/licenses/lgpl.
*
* Contributors:
* Metadata Technology - initial API and implementation
******************************************************************************/
package org.sdmxsource.sdmx.structureretrieval.engine.impl;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.sdmxsource.sdmx.api.constants.SDMX_STRUCTURE_TYPE;
import org.sdmxsource.sdmx.api.exception.CrossReferenceException;
import org.sdmxsource.sdmx.api.exception.SdmxReferenceException;
import org.sdmxsource.sdmx.api.manager.retrieval.IdentifiableRetrievalManager;
import org.sdmxsource.sdmx.api.manager.retrieval.ProvisionBeanRetrievalManager;
import org.sdmxsource.sdmx.api.manager.retrieval.SdmxBeanRetrievalManager;
import org.sdmxsource.sdmx.api.model.beans.SdmxBeans;
import org.sdmxsource.sdmx.api.model.beans.base.*;
import org.sdmxsource.sdmx.api.model.beans.reference.CrossReferenceBean;
import org.sdmxsource.sdmx.api.model.beans.reference.StructureReferenceBean;
import org.sdmxsource.sdmx.api.model.beans.registry.ProvisionAgreementBean;
import org.sdmxsource.sdmx.api.model.beans.registry.RegistrationBean;
import org.sdmxsource.sdmx.structureretrieval.engine.CrossReferenceResolverEngine;
import org.sdmxsource.sdmx.structureretrieval.engine.MaintainableCrossReferenceRetrieverEngine;
import org.sdmxsource.sdmx.structureretrieval.manager.InMemoryRetrievalManager;
import org.sdmxsource.sdmx.util.beans.container.SdmxBeansImpl;
import org.sdmxsource.sdmx.util.beans.reference.StructureReferenceBeanImpl;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* The type Cross reference resolver engine.
*/
public class CrossReferenceResolverEngineImpl implements CrossReferenceResolverEngine {
private static final Logger LOG = LoggerFactory.getLogger(CrossReferenceResolverEngineImpl.class);
private final MaintainableCrossReferenceRetrieverEngine maintainableCrossReferenceRetrieverEngine;
private boolean resolveAgencies;
private Map> crossReferences = new HashMap>();
private Map allIdentifiables = new HashMap();
private Map agencies = new HashMap();
/**
* Default Constructor
*/
public CrossReferenceResolverEngineImpl() {
maintainableCrossReferenceRetrieverEngine = null;
}
/**
* Constructor which pre-populates cache
*
* @param beans the beans\\\\\\\\\\\\\\\\\\\\
*/
public CrossReferenceResolverEngineImpl(SdmxBeans beans) {
this();
addBeansToMap(beans);
}
private void addBeansToMap(SdmxBeans beans) {
for (MaintainableBean maint : beans.getAllMaintainables()) {
addMaintainableToMap(maint);
}
}
private void addMaintainableToMap(MaintainableBean maint) {
allIdentifiables.put(maint.getUrn(), maint);
for (IdentifiableBean identifiableBean : maint.getIdentifiableComposites()) {
if (identifiableBean.getStructureType() == SDMX_STRUCTURE_TYPE.AGENCY) {
AgencyBean acy = (AgencyBean) identifiableBean;
agencies.put(acy.getFullId(), acy);
}
allIdentifiables.put(identifiableBean.getUrn(), identifiableBean);
}
}
private void resetMaps() {
crossReferences = new HashMap>();
// maintainables = new HashSet();
agencies = new HashMap();
}
@Override
public Map> getMissingCrossReferences(SdmxBeans beans, int numberLevelsDeep, IdentifiableRetrievalManager retrievalManager) {
Map> returnMap = new HashMap>();
resolveReferences(beans, false, numberLevelsDeep, retrievalManager, returnMap);
return returnMap;
}
@Override
public Set resolveReferences(ProvisionAgreementBean provision, IdentifiableRetrievalManager structRetrievalManager) {
if (structRetrievalManager == null) {
throw new IllegalArgumentException("StructureRetrievalManager can not be null");
}
Set returnSet = new HashSet();
if (provision.getStructureUseage() != null) {
IdentifiableBean structureUseage = structRetrievalManager.getIdentifiableBean(provision.getStructureUseage());
if (structureUseage == null) {
throw new CrossReferenceException(provision.getStructureUseage());
}
returnSet.add(structureUseage);
}
if (provision.getDataproviderRef() != null) {
IdentifiableBean dataProvider = structRetrievalManager.getIdentifiableBean(provision.getDataproviderRef());
if (dataProvider == null) {
throw new CrossReferenceException(provision.getDataproviderRef());
}
returnSet.add(dataProvider);
}
return returnSet;
}
@Override
public Map> getMissingAgencies(SdmxBeans beans, IdentifiableRetrievalManager retrievalManager) {
Set agencyIds = new HashSet();
for (AgencyBean acy : beans.getAgencies()) {
agencyIds.add(acy.getFullId());
}
Map> returnMap = new HashMap>();
for (MaintainableBean currentMaint : beans.getAllMaintainables()) {
String referencedAgencyId = currentMaint.getAgencyId();
if (!agencyIds.contains(referencedAgencyId)) {
if (retrievalManager != null) {
try {
AgencyBean acy = resolveAgency(referencedAgencyId, retrievalManager);
if (acy != null) {
agencyIds.add(acy.getFullId());
continue;
}
} catch (Throwable th) {
th.printStackTrace();
}
}
Set maintainables = returnMap.get(referencedAgencyId);
if (maintainables == null) {
maintainables = new HashSet();
returnMap.put(referencedAgencyId, maintainables);
}
maintainables.add(currentMaint);
}
}
return returnMap;
}
@Override
public Set resolveReferences(RegistrationBean registation, ProvisionBeanRetrievalManager provRetrievalManager) {
Set returnSet = new HashSet();
if (registation.getProvisionAgreementRef() != null) {
if (provRetrievalManager == null) {
throw new IllegalArgumentException("ProvisionRetrievalManager can not be null");
}
ProvisionAgreementBean provision = provRetrievalManager.getProvision(registation);
if (provision == null) {
throw new CrossReferenceException(registation.getProvisionAgreementRef());
}
returnSet.add(provision);
}
return returnSet;
}
@Override
public Map> resolveReferences(SdmxBeans beans,
boolean resolveAgencies,
int numberLevelsDeep,
IdentifiableRetrievalManager retrievalManager) throws CrossReferenceException {
return resolveReferences(beans, resolveAgencies, numberLevelsDeep, retrievalManager, null);
}
private Map> resolveReferences(SdmxBeans beans,
boolean resolveAgencies,
int numberLevelsDeep,
IdentifiableRetrievalManager retrievalManager,
Map> populateMap) throws CrossReferenceException {
LOG.info("Resolve References, bean retrieval manager: " + retrievalManager);
resetMaps();
this.resolveAgencies = resolveAgencies;
Map> returnMap = null;
int numberBeansLast = 0;
int numberReferencesLast = 0;
int numberBeansCurrent = -1;
int numberReferencesCurrent = -1;
SdmxBeans allBeans = beans;
int currentLevel = 1;
do {
numberBeansLast = numberBeansCurrent;
numberReferencesLast = numberReferencesCurrent;
LOG.debug("numberBeansLast= " + numberBeansLast);
LOG.debug("numberReferencesLast= " + numberReferencesLast);
returnMap = resolveReferencesInternal(allBeans, retrievalManager, populateMap);
numberBeansCurrent = returnMap.size();
numberReferencesCurrent = countValues(returnMap);
allBeans = new SdmxBeansImpl(beans);
for (Set currentBeanSet : returnMap.values()) {
for (IdentifiableBean currentBean : currentBeanSet) {
allBeans.addIdentifiable(currentBean);
}
}
LOG.debug("numberBeansLast= " + numberBeansLast);
LOG.debug("numberReferencesLast= " + numberReferencesLast);
LOG.debug("numberBeansCurrent= " + numberBeansCurrent);
LOG.debug("numberReferencesCurrent= " + numberReferencesCurrent);
LOG.debug("currentLevel= " + currentLevel);
LOG.debug("numberLevelsDeep= " + numberLevelsDeep);
if (currentLevel == numberLevelsDeep) {
break;
}
currentLevel++;
} while (numberBeansCurrent != numberBeansLast || numberReferencesCurrent != numberReferencesLast);
return returnMap;
}
@Override
public Set resolveReferences(MaintainableBean bean,
boolean resolveAgencies,
int numberLevelsDeep,
IdentifiableRetrievalManager retrievalManager) throws CrossReferenceException {
resetMaps();
SdmxBeans beans = new SdmxBeansImpl();
beans.addIdentifiable(bean);
Map> references = resolveReferences(beans, resolveAgencies, numberLevelsDeep, retrievalManager);
Set returnSet = new HashSet();
for (IdentifiableBean key : references.keySet()) {
returnSet.addAll(references.get(key));
}
return returnSet;
}
private int countValues(Map> map) {
int numberReferences = 0;
for (Set refences : map.values()) {
numberReferences += refences.size();
}
return numberReferences;
}
private Map> resolveReferencesInternal(SdmxBeans beans, IdentifiableRetrievalManager retrievalManager, Map> populateMissingMap) throws CrossReferenceException {
for (AgencyBean currentAgency : beans.getAgencies()) {
agencies.put(currentAgency.getFullId(), currentAgency);
}
//Add all the top level beans to the maintainables list
// maintainables.addAll(beans.getAllMaintainables());
addBeansToMap(beans);
//LOOP THROUGH ALL THE BEANS AND RESOLVE ALL THE REFERENCES
if (resolveAgencies) {
for (MaintainableBean currentBean : beans.getAllMaintainables()) {
try {
resolveAgency(currentBean, retrievalManager);
} catch (CrossReferenceException e) {
throw new SdmxReferenceException(getAgencyRef(currentBean.getAgencyId()));
}
}
}
Set loopSet = new HashSet();
loopSet.addAll(beans.getAllMaintainables());
SdmxBeanRetrievalManager retMan = new InMemoryRetrievalManager(beans);
for (MaintainableBean currentMaintainable : loopSet) {
LOG.debug("Resolving References For : " + currentMaintainable.getUrn());
Set crossReferences;
if (maintainableCrossReferenceRetrieverEngine != null) {
crossReferences = maintainableCrossReferenceRetrieverEngine.getCrossReferences(retMan, currentMaintainable);
} else {
crossReferences = currentMaintainable.getCrossReferences();
}
LOG.debug("Number of References : " + crossReferences.size());
int i = 0;
for (CrossReferenceBean crossReference : crossReferences) {
i++;
if (LOG.isDebugEnabled()) {
LOG.debug("Resolving Reference " + i + ": " + crossReference.toString() + " - referenced from -" + crossReference.getReferencedFrom().getStructureType());
}
try {
storeRef(crossReference.getReferencedFrom(), resolveCrossReference(crossReference, retrievalManager));
} catch (CrossReferenceException e) {
handleMissingReference(e, populateMissingMap);
if (populateMissingMap == null) {
throw e;
}
}
}
}
return crossReferences;
}
/**
* Handles a missing reference either by throwing an exception, if the populateMissingMap, or by populating the map, if both the map is not null and the reference exception has reference to the
* cross referenced artifact.
*/
private void handleMissingReference(CrossReferenceException e, Map> populateMissingMap) throws CrossReferenceException {
if (populateMissingMap != null && e.getCrossReference() != null) {
CrossReferenceBean crossReference = e.getCrossReference();
Set missingRefences = populateMissingMap.get(crossReference.getReferencedFrom());
if (missingRefences == null) {
missingRefences = new HashSet();
if (crossReference.getReferencedFrom().getStructureType().isIdentifiable()) {
populateMissingMap.put((IdentifiableBean) crossReference.getReferencedFrom(), missingRefences);
} else {
populateMissingMap.put(crossReference.getReferencedFrom().getParent(IdentifiableBean.class, true), missingRefences);
}
}
missingRefences.add(crossReference);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////AGENCY REFERENCES ///////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void resolveAgency(MaintainableBean maint, IdentifiableRetrievalManager structRetrievalManager) throws CrossReferenceException {
if (!resolveAgencies) {
return;
}
if (maint.getAgencyId().equals(AgencyBean.DEFAULT_AGENCY)) {
return;
}
AgencyBean agency = resolveAgency(maint.getAgencyId(), structRetrievalManager);
this.agencies.put(agency.getId(), agency);
storeRef(maint, agency);
}
private AgencyBean resolveAgency(String agencyId, IdentifiableRetrievalManager identifiableRetrievalManager) throws CrossReferenceException {
if (agencies.containsKey(agencyId)) {
return agencies.get(agencyId);
}
AgencyBean agency = null;
if (identifiableRetrievalManager != null) {
String[] split = agencyId.split("\\.");
String parentAgencyId = AgencySchemeBean.DEFAULT_SCHEME;
String targetAgencyId = agencyId;
if (split.length > 1) {
targetAgencyId = split[split.length - 1];
split[split.length - 1] = null;
String concat = "";
parentAgencyId = "";
for (String currentSplit : split) {
if (currentSplit != null) {
parentAgencyId += concat + currentSplit;
}
concat = ".";
}
}
StructureReferenceBean agencyRef = new StructureReferenceBeanImpl(parentAgencyId, AgencySchemeBean.FIXED_ID, AgencySchemeBean.FIXED_VERSION, SDMX_STRUCTURE_TYPE.AGENCY, targetAgencyId);
agency = identifiableRetrievalManager.getIdentifiableBean(agencyRef, AgencyBean.class);
}
if (agency == null) {
throw new SdmxReferenceException(getAgencyRef(agencyId));
}
return agency;
}
private StructureReferenceBean getAgencyRef(String agencyId) {
String parentAgency = AgencyBean.DEFAULT_AGENCY;
if (agencyId.contains(".")) {
parentAgency = agencyId.substring(0, agencyId.indexOf("."));
agencyId = agencyId.substring(agencyId.indexOf(".") + 1);
}
return new StructureReferenceBeanImpl(parentAgency, AgencySchemeBean.DEFAULT_SCHEME, AgencySchemeBean.DEFAULT_VERSION, SDMX_STRUCTURE_TYPE.AGENCY, agencyId);
}
@Override
public IdentifiableBean resolveCrossReference(CrossReferenceBean crossReference, IdentifiableRetrievalManager structRetrievalManager) throws CrossReferenceException {
if (crossReference.getTargetReference() == SDMX_STRUCTURE_TYPE.AGENCY) {
return resolveAgency(crossReference.getFullId(), structRetrievalManager);
}
//1. Try local Maps
IdentifiableBean resolvedIdentifiable = resolveMaintainableFromLocalMaps(crossReference);
if (resolvedIdentifiable != null) {
return resolvedIdentifiable;
}
IdentifiableBean identifiableBean = null;
if (structRetrievalManager != null) {
LOG.info("IdentifiableBean '" + crossReference + "' not found locally, check IdentifiableRetrievalManager");
identifiableBean = structRetrievalManager.getIdentifiableBean(crossReference);
}
if (identifiableBean == null) {
throw new CrossReferenceException(crossReference);
}
addMaintainableToMap(identifiableBean.getMaintainableParent());
return identifiableBean;
}
private IdentifiableBean resolveMaintainableFromLocalMaps(CrossReferenceBean xsRef) throws CrossReferenceException {
return allIdentifiables.get(xsRef.getTargetUrn());
}
private void storeRef(SDMXBean referencedFrom, IdentifiableBean reference) {
IdentifiableBean refFromIdentifiable;
if (referencedFrom.getStructureType().isIdentifiable()) {
refFromIdentifiable = (IdentifiableBean) referencedFrom;
} else {
refFromIdentifiable = referencedFrom.getParent(IdentifiableBean.class, true);
}
Set refList;
if (crossReferences.containsKey(refFromIdentifiable)) {
refList = crossReferences.get(refFromIdentifiable);
} else {
refList = new HashSet();
crossReferences.put(refFromIdentifiable, refList);
}
refList.add(reference);
}
}