ConfigManager.java
/*
* GovWay - A customizable API Gateway
* https://govway.org
*
* Copyright (c) 2005-2024 Link.it srl (https://link.it).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3, as published by
* the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openspcoop2.core.mvc.properties.utils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.openspcoop2.core.commons.CoreException;
import org.openspcoop2.core.mvc.properties.Compatibility;
import org.openspcoop2.core.mvc.properties.Config;
import org.openspcoop2.core.mvc.properties.Tags;
import org.openspcoop2.core.mvc.properties.utils.serializer.JaxbDeserializer;
import org.openspcoop2.generic_project.exception.DeserializerException;
import org.openspcoop2.utils.xml.AbstractValidatoreXSD;
import org.slf4j.Logger;
/**
* Manager delle configurazioni disponibili.
*
* @author Pintori Giuliano (pintori@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class ConfigManager {
private static ConfigManager instance = null;
private Logger log = null;
private Map<String, Map<String,Config>> mapConfigBuildIn = null;
private Map<String, Map<String,Config>> mapConfigFileSystem = null;
private Map<String, Map<String,Config>> mapConfig = null;
private AbstractValidatoreXSD validator = null;
public static ConfigManager getinstance(Logger log) throws CoreException {
if(instance == null) {
// spotbugs warning 'SING_SINGLETON_GETTER_NOT_SYNCHRONIZED'
synchronized (ConfigManager.class) {
init(log);
}
}
return instance;
}
private static synchronized void init(Logger log) throws CoreException{
instance = new ConfigManager(log);
}
private ConfigManager(Logger log) throws CoreException {
this.log = log;
this.mapConfigBuildIn = new HashMap<>();
this.mapConfigFileSystem = new HashMap<>();
this.mapConfig = new HashMap<>();
try {
this.validator = XSDValidator.getXSDValidator(log);
}catch(Exception e) {
doError("Errore durante la init del ManagerConfigurazioni",e);
}
}
private void doError(String msg,Exception e) throws CoreException {
String msgError = msg +": "+ e.getMessage();
this.log.error(msgError,e);
throw new CoreException(e.getMessage(),e);
}
public void leggiConfigurazioni(PropertiesSourceConfiguration propertiesSourceConfiguration, boolean validazioneXSD) throws CoreException, DeserializerException{
// Configurazioni builtIn
if(!this.mapConfigBuildIn.containsKey(propertiesSourceConfiguration.getId()) || propertiesSourceConfiguration.isUpdateBuiltIn()) {
if(this.mapConfigBuildIn.containsKey(propertiesSourceConfiguration.getId())) {
this.mapConfigBuildIn.remove(propertiesSourceConfiguration.getId());
}
Map<String,Config> mapConfigFromDir = null;
List<byte[]> builtIn = propertiesSourceConfiguration.getBuiltIn();
if(builtIn != null && !builtIn.isEmpty()) {
mapConfigFromDir = new HashMap<>();
JaxbDeserializer xmlReader = new JaxbDeserializer();
for (int i = 0 ; i < builtIn.size(); i++ ) {
byte[] f = builtIn.get(i);
// validazione XSD se prevista
if(validazioneXSD) {
try {
this.validator.valida(new ByteArrayInputStream(f));
}catch(Exception e) {
doError("La configurazione builtIn numero ["+(i+1)+"] non e' valida",e);
}
}
Config configDaFile = xmlReader.readConfig(f);
String id = configDaFile.getId();
if(mapConfigFromDir.containsKey(id))
throw new CoreException("La configurazione builtIn con id '"+id+"' risulta duplicata all'interno di quelle precaricate nel sistema.");
mapConfigFromDir.put(id,configDaFile);
}
this.mapConfigBuildIn.put(propertiesSourceConfiguration.getId(), mapConfigFromDir);
}
}
// configurazioni da file system
if(propertiesSourceConfiguration.getDirectory() != null && (!this.mapConfigFileSystem.containsKey(propertiesSourceConfiguration.getId()) || propertiesSourceConfiguration.isUpdate())) {
if(this.mapConfigFileSystem.containsKey(propertiesSourceConfiguration.getId())) {
this.mapConfigFileSystem.remove(propertiesSourceConfiguration.getId());
}
Map<String,Config> mapConfigFromDir = null;
File dir = new File(propertiesSourceConfiguration.getDirectory());
if(!dir.exists())
throw new CoreException("Il path indicato ["+propertiesSourceConfiguration.getDirectory()+"] non esiste, impossibile leggere le configurazioni");
if(!dir.isDirectory())
throw new CoreException("Il path indicato ["+propertiesSourceConfiguration.getDirectory()+"] non e' una directory");
String[] fileList = dir.list();
if(fileList != null && fileList.length > 0) {
mapConfigFromDir = new HashMap<>();
JaxbDeserializer xmlReader = new JaxbDeserializer();
for (String f : fileList) {
File fileConfig = new File(dir.getPath() + File.separator + f);
if(!fileConfig.isDirectory()) {
// validazione XSD se prevista
if(validazioneXSD) {
try {
this.validator.valida(fileConfig);
}catch(Exception e) {
doError("La configurazione ["+fileConfig.getName()+"] non e' valida",e);
}
}
Config configDaFile = xmlReader.readConfig(fileConfig);
String id = configDaFile.getId();
if(mapConfigFromDir.containsKey(id))
throw new CoreException("La configurazione con id '"+id+"' risulta duplicata all'interno del path indicato ["+propertiesSourceConfiguration.getDirectory()+"].");
mapConfigFromDir.put(id,configDaFile);
}
}
this.mapConfigFileSystem.put(propertiesSourceConfiguration.getId(), mapConfigFromDir);
}
}
// merge configurazioni
if(!this.mapConfig.containsKey(propertiesSourceConfiguration.getId()) || propertiesSourceConfiguration.isUpdateBuiltIn() || propertiesSourceConfiguration.isUpdate()) {
if(this.mapConfig.containsKey(propertiesSourceConfiguration.getId())) {
this.mapConfig.remove(propertiesSourceConfiguration.getId());
}
Map<String, Config> mapBuiltIn = this.mapConfigBuildIn.get(propertiesSourceConfiguration.getId());
Map<String, Config> mapFileSystem = this.mapConfigFileSystem.get(propertiesSourceConfiguration.getId());
if(mapBuiltIn != null && mapBuiltIn.size() > 0 && mapFileSystem != null && mapFileSystem.size() > 0 ) {
// controllo duplicati
for (String keyBuiltIn : mapBuiltIn.keySet()) {
if(mapFileSystem.keySet().contains(keyBuiltIn))
throw new CoreException("La configurazione con id '"+keyBuiltIn+"' risulta duplicata, e' presente sia come configurazione builtIn che come configurazione esterna, eliminare una delle due.");
}
}
Map<String, Config> map = new HashMap<>();
if(mapBuiltIn != null && mapBuiltIn.size() > 0)
map.putAll(mapBuiltIn);
if(mapFileSystem != null && mapFileSystem.size() > 0)
map.putAll(mapFileSystem);
this.mapConfig.put(propertiesSourceConfiguration.getId(), map);
}
}
public List<String> getNomiConfigurazioni(PropertiesSourceConfiguration propertiesSourceConfiguration, String ... tags) {
List<String> mapSortedKeys = new ArrayList<>();
Map<String, List<String>> mapSorted = new HashMap<>();
Map<String, Config> map = this.mapConfig.get(propertiesSourceConfiguration.getId());
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String id = iterator.next();
Config config = map.get(id);
if(tags!=null && tags.length>0) {
Compatibility compatibility = config.getCompatibility();
// se non e' compatibile con i tag richiesti non lo aggiungo alla lista
if(!checkCompatibility(compatibility, Arrays.asList(tags)))
continue;
}
String labelId = config.getLabel();
if(config.getSortLabel()!=null) {
labelId = config.getSortLabel();
}
List<String> l = null;
if(mapSorted.containsKey(labelId)) {
l = mapSorted.get(labelId);
}
else {
l = new ArrayList<>();
mapSorted.put(labelId, l);
mapSortedKeys.add(labelId);
}
l.add(id);
}
Collections.sort(mapSortedKeys);
List<String> list = new ArrayList<>();
for (String labelId : mapSortedKeys) {
List<String> l = mapSorted.get(labelId);
list.addAll(l);
}
return list; // lista contenente gli id
}
public List<String> convertToLabel(PropertiesSourceConfiguration propertiesSourceConfiguration, List<String> idList){
Map<String, Config> map = this.mapConfig.get(propertiesSourceConfiguration.getId());
List<String> listLabels = new ArrayList<>();
for (String id : idList) {
Config config = map.get(id);
String labelId = config.getLabel();
/**if(config.getSortLabel()!=null) {
labelId = config.getSortLabel();
}*/
listLabels.add(labelId);
}
return listLabels;
}
public Config getConfigurazione(PropertiesSourceConfiguration propertiesSourceConfiguration, String name){
return this.mapConfig.get(propertiesSourceConfiguration.getId()).get(name);
}
public boolean checkCompatibility(Compatibility compatibility, List<String> tags) {
if(compatibility == null)
return true;
boolean isAnd = compatibility.getAnd();
boolean isNot = compatibility.getNot();
// Valore di partenza dell'esito totale e'
// TRUE se devo controllare l'and dei tag
// FALSE se devo controllare l'or dei tag
boolean esito = isAnd;
for (Tags tag : compatibility.getTagsList()) {
boolean resCondition = checkTags(tag,tags);
// aggiorno l'esito in base all'operazione da aggregare AND o OR
esito = isAnd ? (esito && resCondition) : (esito || resCondition);
}
// eventuale NOT della condizione
return isNot ? !esito : esito;
}
private boolean checkTags(Tags tag, List<String> tags) {
boolean isAnd = tag.getAnd();
boolean isNot = tag.getNot();
// Valore di partenza dell'esito totale e'
// TRUE se devo controllare l'and dei tag
// FALSE se devo controllare l'or dei tag
boolean esito = isAnd;
for (String stringTag : tag.getTagList()) {
boolean resCondition = tags.contains(stringTag);
// aggiorno l'esito in base all'operazione da aggregare AND o OR
esito = isAnd ? (esito && resCondition) : (esito || resCondition);
}
// eventuale NOT della condizione
return isNot ? !esito : esito;
}
}