ConfigurazioneNodiRuntime.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.pdd.config;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.openspcoop2.core.config.constants.CostantiConfigurazione;
import org.openspcoop2.pdd.core.CostantiPdD;
import org.openspcoop2.utils.BooleanNullable;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.certificate.byok.BYOKCostanti;
import org.openspcoop2.utils.properties.PropertiesReader;
import org.openspcoop2.utils.transport.TransportUtils;
import org.slf4j.Logger;
/**
* ConfigurazioneNodiRuntime
*
* @author Poli Andrea (apoli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class ConfigurazioneNodiRuntime {
public static final String RESOURCE_NAME = "govway.nodirun.properties";
public static final String RESOURCE_TIPOLOGIA_ACCESSO_JMX = "jmx";
public static final String RESOURCE_TIPOLOGIA_ACCESSO_OPENSPCOOP = "openspcoop";
public static final String RESOURCE_TIPOLOGIA_ACCESSO_GOVWAY = "govway";
public static final String ALIAS_DEFAULT = "pdd";
private static Map<String, ConfigurazioneNodiRuntime> staticInstanceMap = new HashMap<>();
private static final String PREFIX_DEFAULT = "";
public static void initialize(String path, ConfigurazioneNodiRuntimeProperties ... backwardCompatibilitiesProperties) throws UtilsException {
initialize(path, true, backwardCompatibilitiesProperties);
}
public static void initialize(String path, boolean configFileRequired, ConfigurazioneNodiRuntimeProperties ... backwardCompatibilitiesProperties) throws UtilsException {
ConfigurazioneNodiRuntimeProperties cpClasspath = null;
try(InputStream is = ConfigurazioneNodiRuntime.class.getResourceAsStream("/"+RESOURCE_NAME);){
if(is!=null) {
Properties p = new Properties();
p.load(is);
cpClasspath = new ConfigurazioneNodiRuntimeProperties(PREFIX_DEFAULT, p);
}
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
ConfigurazioneNodiRuntimeProperties cpFile = null;
if(path!=null && StringUtils.isNotEmpty(path)) {
File f = new File(path);
boolean read = false;
if(cpClasspath!=null || (backwardCompatibilitiesProperties!=null && backwardCompatibilitiesProperties.length>0)) {
// la configurazione di default e' opzionale, se siamo in backwardCompatibilities mode
if(f.exists() && f.canRead()) {
read = true;
}
}
else {
if(!f.exists()) {
if(configFileRequired) {
throw new UtilsException("Configuration file '"+f.getAbsolutePath()+"' not exists");
}
}
else if(!f.canRead()) {
if(configFileRequired) {
throw new UtilsException("Configuration file '"+f.getAbsolutePath()+"' cannot read");
}
}
else {
read = true;
}
}
if(read) {
try(FileInputStream fin = new FileInputStream(f)){
Properties p = new Properties();
p.load(fin);
cpFile = new ConfigurazioneNodiRuntimeProperties(PREFIX_DEFAULT, p);
}catch(Exception e) {
throw new UtilsException(e.getMessage(),e);
}
}
}
if(cpClasspath!=null || cpFile!=null) {
ConfigurazioneNodiRuntime newInstance = new ConfigurazioneNodiRuntime(cpFile, cpClasspath);
staticInstanceMap.put(PREFIX_DEFAULT, newInstance);
}
if(backwardCompatibilitiesProperties!=null && backwardCompatibilitiesProperties.length>0) {
for (ConfigurazioneNodiRuntimeProperties bc : backwardCompatibilitiesProperties) {
ConfigurazioneNodiRuntime newInstance = new ConfigurazioneNodiRuntime(bc, null);
staticInstanceMap.put(bc.getPrefix(), newInstance);
}
}
}
public static ConfigurazioneNodiRuntime getConfigurazioneNodiRuntime() {
return getConfigurazioneNodiRuntime(PREFIX_DEFAULT);
}
public static ConfigurazioneNodiRuntime getConfigurazioneNodiRuntime(String prefix) {
if(staticInstanceMap!=null) {
return staticInstanceMap.get(prefix);
}
return null;
}
public static List<String> getPrefixes(){
List<String> l = null;
if(staticInstanceMap!=null && !staticInstanceMap.isEmpty()) {
l = new ArrayList<>();
l.addAll(staticInstanceMap.keySet());
return l;
}
return l;
}
private PropertiesReader reader;
private PropertiesReader readerClasspath;
private String prefix = PREFIX_DEFAULT;
private boolean clusterDinamico = false;
private List<String> aliases;
private Map<String,List<String>> gruppiAliases;
private Map<String, String> descrizione;
private Map<String, String> tipoAccesso;
private Map<String, String> username;
private Map<String, String> password;
private Map<String, Boolean> https;
private Map<String, Boolean> httpsVerificaHostName;
private Map<String, Boolean> httpsAutenticazioneServer;
private Map<String, String> httpsAutenticazioneServerTruststorePath;
private Map<String, String> httpsAutenticazioneServerTruststoreType;
private Map<String, String> httpsAutenticazioneServerTruststorePassword;
private Map<String, String> connectionTimeout;
private Map<String, String> readConnectionTimeout;
private Map<String, String> readConnectionTimeoutSlowOperation;
private Map<String, String> as;
private Map<String, String> factory;
private Map<String, String> resourceUrl; // check con parametri o proxy in modalità dinamica
private Map<String, String> forceResourceUrl = new HashMap<>();
private Map<String, String> checkStatusUrl; // check senza parametri
private Map<String, String> dominio;
private ConfigurazioneNodiRuntime(ConfigurazioneNodiRuntimeProperties config, ConfigurazioneNodiRuntimeProperties configClasspath) throws UtilsException {
if(config!=null) {
this.reader = new PropertiesReader(config.getProperties(), false);
this.prefix = config.getPrefix();
}
if(configClasspath!=null) {
this.readerClasspath = new PropertiesReader(configClasspath.getProperties(), false);
this.prefix = configClasspath.getPrefix();
}
if(this.reader==null && this.readerClasspath==null) {
throw new UtilsException("Nessuna configurazione fornita");
}
this.initAliases();
this.initGruppiAliases();
this.initConfigAliases();
}
public boolean containsNode(String alias) {
return this.aliases.contains(alias);
}
public void initClusterDinamico() throws UtilsException {
String tipo = this.readProperty(false, "clusterDinamico");
if(tipo!=null) {
this.clusterDinamico = "true".equalsIgnoreCase(tipo);
}
else {
// backward compatibility
if(!PREFIX_DEFAULT.equals(this.prefix)){
tipo = this.readProperty(false, "cluster_dinamico.enabled");
if(tipo!=null) {
this.clusterDinamico = "true".equalsIgnoreCase(tipo);
}
}
}
}
public boolean isClusterDinamico() {
return this.clusterDinamico;
}
public void initAliases() throws UtilsException {
List<String> list = new ArrayList<>();
String tipo = this.readProperty(false, "aliases");
if(tipo!=null && !"".equals(tipo)){
String [] tmp = tipo.split(",");
for (int i = 0; i < tmp.length; i++) {
list.add(tmp[i].trim());
}
}
if(PREFIX_DEFAULT.equals(this.prefix) && list.isEmpty()) {
list.add(ALIAS_DEFAULT);
}
this.aliases = list;
}
public List<String> getAliases() {
return this.aliases;
}
private void initGruppiAliases() throws UtilsException {
Map<String,List<String>> map = new HashMap<>();
String nomeP = "aliases.";
Properties p = null;
if(this.readerClasspath!=null) {
p = this.readerClasspath.readProperties(nomeP);
}
if(this.reader!=null) {
if(p==null || p.isEmpty()) {
p = this.reader.readProperties(nomeP);
}
else {
Properties pConfig = this.reader.readProperties(nomeP);
if(pConfig!=null && !pConfig.isEmpty()) {
p.putAll(pConfig); // sovrascrivo
}
}
}
if(p!=null && !p.isEmpty()) {
List<String> aliasesRegistrati = getAliases();
Enumeration<?> en = p.keys();
while (en.hasMoreElements()) {
Object object = en.nextElement();
if(object instanceof String) {
String gruppo = (String) object;
if(map.containsKey(gruppo)) {
throw new UtilsException("Gruppo '"+gruppo+"' definito più di una volta nella proprietà '"+this.prefix+nomeP+"*'");
}
String aliasesGruppo = p.getProperty(gruppo);
if(aliasesGruppo!=null && !"".equals(aliasesGruppo)){
String [] tmp = aliasesGruppo.split(",");
if(tmp!=null && tmp.length>0) {
List<String> list = new ArrayList<>();
for (int i = 0; i < tmp.length; i++) {
String alias = tmp[i].trim();
if(!aliasesRegistrati.contains(alias)) {
throw new UtilsException("Alias '"+alias+"' indicato nella proprietà '"+nomeP+""+gruppo+"' non è uno degli alias censiti in '"+this.prefix+"aliases'");
}
list.add(alias);
}
if(!list.isEmpty()) {
map.put(gruppo, list);
}
}
}
}
}
}
this.gruppiAliases = map;
}
public Map<String, List<String>> getGruppi_aliases() {
return this.gruppiAliases;
}
public void initConfigAliases() throws UtilsException {
this.descrizione = new HashMap<>();
this.tipoAccesso = new HashMap<>();
this.username = new HashMap<>();
this.password = new HashMap<>();
this.https = new HashMap<>();
this.httpsVerificaHostName = new HashMap<>();
this.httpsAutenticazioneServer = new HashMap<>();
this.httpsAutenticazioneServerTruststorePath = new HashMap<>();
this.httpsAutenticazioneServerTruststoreType = new HashMap<>();
this.httpsAutenticazioneServerTruststorePassword = new HashMap<>();
this.connectionTimeout = new HashMap<>();
this.readConnectionTimeout = new HashMap<>();
this.readConnectionTimeoutSlowOperation = new HashMap<>();
this.as = new HashMap<>();
this.factory = new HashMap<>();
this.resourceUrl = new HashMap<>();
this.checkStatusUrl = new HashMap<>();
this.dominio = new HashMap<>();
if(this.aliases!=null && !this.aliases.isEmpty()) {
for (String alias : this.aliases) {
String descr = this.readProperty(false, alias+".descrizione");
if(descr!=null) {
this.descrizione.put(alias, descr);
}
boolean tipoAccessoRequired = PREFIX_DEFAULT.equals(this.prefix) ? false : true;
String tipoAccessoCfg = getValueEngine(tipoAccessoRequired, alias, "tipoAccesso");
if(tipoAccessoCfg==null) {
tipoAccessoCfg = RESOURCE_TIPOLOGIA_ACCESSO_JMX;
}
if(RESOURCE_TIPOLOGIA_ACCESSO_GOVWAY.equals(tipoAccessoCfg)) {
tipoAccessoCfg = RESOURCE_TIPOLOGIA_ACCESSO_OPENSPCOOP;
}
else {
if(!RESOURCE_TIPOLOGIA_ACCESSO_JMX.equals(tipoAccessoCfg) && !RESOURCE_TIPOLOGIA_ACCESSO_OPENSPCOOP.equals(tipoAccessoCfg)){
throw new UtilsException("Tipo di accesso ["+tipoAccessoCfg+"] non supportato per la proprietà '"+this.prefix+"tipoAccesso'");
}
}
this.tipoAccesso.put(alias, tipoAccessoCfg);
String user =getValueEngine(false, alias, "remoteAccess.username");
if(user!=null) {
this.username.put(alias, user);
}
String pwd =getValueEngine(false, alias, "remoteAccess.password");
if(pwd!=null) {
this.password.put(alias, pwd);
}
String v = getValueEngine(false, alias, "remoteAccess.https");
boolean httpsEnabled = v!=null ? Boolean.valueOf(v.trim()) : false; // default false
this.https.put(alias, httpsEnabled);
v = getValueEngine(false, alias, "remoteAccess.https.verificaHostName");
boolean httpsVerificaHostNameEnabled = v!=null ? Boolean.valueOf(v.trim()) : true; // default true
this.httpsVerificaHostName.put(alias, httpsVerificaHostNameEnabled);
v = getValueEngine(false, alias, "remoteAccess.https.autenticazioneServer");
boolean httpsAutenticazioneServerEnabled = v!=null ? Boolean.valueOf(v.trim()) : true; // default true
this.httpsAutenticazioneServer.put(alias, httpsAutenticazioneServerEnabled);
v = getValueEngine(false, alias, "remoteAccess.https.autenticazioneServer.truststorePath");
if(v!=null) {
this.httpsAutenticazioneServerTruststorePath.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.https.autenticazioneServer.truststoreType");
if(v!=null) {
this.httpsAutenticazioneServerTruststoreType.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.https.autenticazioneServer.truststorePassword");
if(v!=null) {
this.httpsAutenticazioneServerTruststorePassword.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.connectionTimeout");
if(v!=null) {
this.connectionTimeout.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.readConnectionTimeout");
if(v!=null) {
this.readConnectionTimeout.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.readConnectionTimeout.slowOperation");
if(v!=null) {
this.readConnectionTimeoutSlowOperation.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.as");
if(v!=null) {
this.as.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.factory");
if(v!=null) {
this.factory.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.url");
if(v!=null) {
this.resourceUrl.put(alias, v);
}
v = getValueEngine(false, alias, "remoteAccess.checkStatus.url");
if(v!=null) {
this.checkStatusUrl.put(alias, v);
}
v = getValueEngine(!PREFIX_DEFAULT.equals(this.prefix), alias, "dominio");
if(v!=null) {
this.dominio.put(alias, v);
}
else {
this.dominio.put(alias, org.openspcoop2.utils.jmx.CostantiJMX.JMX_DOMINIO);
}
}
}
}
public String getDescrizione(String alias) {
return this.descrizione.get(alias);
}
public String getTipoAccesso(String alias) {
return this.tipoAccesso.get(alias);
}
public String getUsername(String alias) {
return this.username.get(alias);
}
public String getPassword(String alias) {
return this.password.get(alias);
}
public boolean isHttps(String alias) {
return this.https.get(alias);
}
public boolean isHttps_verificaHostName(String alias) {
return this.httpsVerificaHostName.get(alias);
}
public boolean isHttps_autenticazioneServer(String alias) {
return this.httpsAutenticazioneServer.get(alias);
}
public String getHttps_autenticazioneServer_truststorePath(String alias) {
return this.httpsAutenticazioneServerTruststorePath.get(alias);
}
public String getHttps_autenticazioneServer_truststoreType(String alias) {
return this.httpsAutenticazioneServerTruststoreType.get(alias);
}
public String getHttps_autenticazioneServer_truststorePassword(String alias) {
return this.httpsAutenticazioneServerTruststorePassword.get(alias);
}
public String getConnectionTimeout(String alias) {
return this.connectionTimeout.get(alias);
}
public String getReadConnectionTimeout(String alias) {
return this.readConnectionTimeout.get(alias);
}
public String getReadConnectionTimeout_slowOperation(String alias) {
return this.readConnectionTimeoutSlowOperation.get(alias);
}
public String getAs(String alias) {
return this.as.get(alias);
}
public String getFactory(String alias) {
return this.factory.get(alias);
}
public void addForceResourceUrl(String alias, String url) {
this.forceResourceUrl.put(alias, url);
}
public String getResourceUrl(String alias) {
if(!this.forceResourceUrl.isEmpty() && this.forceResourceUrl.containsKey(alias)) {
return this.forceResourceUrl.get(alias);
}
return this.resourceUrl.get(alias);
}
public String getCheckStatusUrl(String alias) {
return this.checkStatusUrl.get(alias);
}
public String getDominio(String alias) {
return this.dominio.get(alias);
}
private String getValueEngine(boolean required, String alias, String prop) throws UtilsException{
String tmp = this.readProperty(false, alias+"."+prop);
if(tmp==null || "".equals(tmp)){
tmp = this.readProperty(required, prop);
}
return tmp;
}
private String readProperty(boolean required,String property) throws UtilsException{
String tmp = null;
if(this.reader!=null) {
tmp = this.reader.getValue_convertEnvProperties(property);
}
if(tmp==null &&
this.readerClasspath!=null) {
tmp = this.readerClasspath.getValue_convertEnvProperties(property);
}
if(tmp==null){
if(required){
throw new UtilsException("Property ["+this.prefix+property+"] not found");
}
else{
return null;
}
}else{
return tmp.trim();
}
}
@SuppressWarnings("unused")
private BooleanNullable readBooleanProperty(boolean required,String property) throws UtilsException{
String tmp = this.readProperty(required, property);
if(tmp==null && !required) {
return BooleanNullable.NULL(); // se e' required viene sollevata una eccezione dal metodo readProperty
}
if(!"true".equalsIgnoreCase(tmp) && !"false".equalsIgnoreCase(tmp)){
throw new UtilsException("Property ["+this.prefix+property+"] with uncorrect value ["+tmp+"] (true/value expected)");
}
return Boolean.parseBoolean(tmp) ? BooleanNullable.TRUE() : BooleanNullable.FALSE();
}
@SuppressWarnings("unused")
private Integer readIntegerProperty(boolean required,String property) throws UtilsException{
String tmp = this.readProperty(required, property);
if(tmp==null && !required) {
return null; // se e' required viene sollevata una eccezione dal metodo readProperty
}
try{
return Integer.parseInt(tmp);
}catch(Exception e){
throw new UtilsException("Property ["+this.prefix+property+"] with uncorrect value ["+tmp+"] (int value expected)");
}
}
@SuppressWarnings("unused")
private Long readLongProperty(boolean required,String property) throws UtilsException{
String tmp = this.readProperty(required, property);
if(tmp==null && !required) {
return null; // se e' required viene sollevata una eccezione dal metodo readProperty
}
try{
return Long.parseLong(tmp);
}catch(Exception e){
throw new UtilsException("Property ["+this.prefix+property+"] with uncorrect value ["+tmp+"] (long value expected)");
}
}
public void initBYOKDynamicMapRemoteGovWayNode(Logger log, Map<String, Object> dynamicMap, boolean wrap, boolean unwrap, ConfigurazioneNodiRuntimeBYOKRemoteConfig remoteConfig) {
if(this.aliases!=null && !this.aliases.isEmpty()){
// prendo il primo nodo funzionante
for (String alias : this.aliases) {
if(isActiveNode(log, alias, remoteConfig) &&
this.getResourceUrl(alias)!=null && !"".equals(this.getResourceUrl(alias))
&& !InvokerNodiRuntime.RESOURCE_URL_LOCALE.equals(this.getResourceUrl(alias))
){
initBYOKDynamicMapRemoteGovWayNode(dynamicMap, wrap, unwrap, alias, remoteConfig);
break;
}
}
}
}
public boolean isAtLeastOneActiveNode(Logger log, ConfigurazioneNodiRuntimeBYOKRemoteConfig remoteConfig) {
if(this.aliases!=null && !this.aliases.isEmpty()){
// prendo il primo nodo funzionante
for (String alias : this.aliases) {
if(isActiveNode(log, alias, remoteConfig)){
return true;
}
}
}
return false;
}
public boolean isActiveNode(Logger log, String alias, ConfigurazioneNodiRuntimeBYOKRemoteConfig remoteConfig) {
try {
InvokerNodiRuntime invoker = new InvokerNodiRuntime(null,this); // passo volutamente null per non registrare l'errore
String value = invoker.readJMXAttribute(alias, remoteConfig.getType(),
remoteConfig.getResourceStatoServiziPdd(),
remoteConfig.getAttributeComponentePD());
return value!=null && !"".equals(value) && !value.startsWith(InvokerNodiRuntime.PREFIX_HTTP_CODE) &&
(CostantiConfigurazione.ABILITATO.getValue().equals(value) || CostantiConfigurazione.DISABILITATO.getValue().equals(value));
}catch(Exception e) {
log.debug("Nodo '"+alias+"' non non attivo?: "+e.getMessage(),e);
return false;
}
}
private void initBYOKDynamicMapRemoteGovWayNode(Map<String, Object> dynamicMap, boolean wrap, boolean unwrap, String alias, ConfigurazioneNodiRuntimeBYOKRemoteConfig remoteConfig) {
String remoteUrl = this.getResourceUrl(alias);
Map<String, String> govwayContext = new HashMap<>();
dynamicMap.put(BYOKCostanti.GOVWAY_RUNTIME_CONTEXT, govwayContext);
Map<String, List<String>> p = new HashMap<>();
TransportUtils.setParameter(p,CostantiPdD.CHECK_STATO_PDD_RESOURCE_NAME, remoteConfig.getResourceConfigurazioneSistema());
if(wrap) {
TransportUtils.setParameter(p,CostantiPdD.CHECK_STATO_PDD_METHOD_NAME, remoteConfig.getMethodWrap());
String urlWrap = TransportUtils.buildUrlWithParameters(p, remoteUrl);
govwayContext.put(BYOKCostanti.GOVWAY_RUNTIME_ENDPOINT_WRAP, urlWrap);
}
if(unwrap) {
TransportUtils.setParameter(p,CostantiPdD.CHECK_STATO_PDD_METHOD_NAME, remoteConfig.getMethodUnwrap());
String urlUnwrap = TransportUtils.buildUrlWithParameters(p, remoteUrl);
govwayContext.put(BYOKCostanti.GOVWAY_RUNTIME_ENDPOINT_UNWRAP, urlUnwrap);
}
String user = this.getUsername(alias);
if(user!=null) {
govwayContext.put(BYOKCostanti.GOVWAY_RUNTIME_USERNAME, user);
}
String pwd = this.getPassword(alias);
if(pwd!=null) {
govwayContext.put(BYOKCostanti.GOVWAY_RUNTIME_PASSWORD, pwd);
}
}
}