FileTraceConfig.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.logger.filetrace;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;
import org.apache.commons.lang.StringUtils;
import org.openspcoop2.core.commons.CoreException;
import org.openspcoop2.monitor.sdk.transaction.FaseTracciamento;
import org.openspcoop2.pdd.config.OpenSPCoop2Properties;
import org.openspcoop2.utils.LoggerWrapperFactory;
import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.properties.PropertiesReader;
import org.openspcoop2.utils.resources.FileSystemUtilities;
/**
* FileTraceConfig
*
* @author Poli Andrea (poli@link.it)
* @author $Author$
* @version $Rev$, $Date$
*/
public class FileTraceConfig {
private static HashMap<String, FileTraceConfig> staticInstanceMap = new HashMap<>();
private static final org.openspcoop2.utils.Semaphore semaphore = new org.openspcoop2.utils.Semaphore("FileTraceConfig");
public static void init(InputStream is, String fileNamePath, boolean globale) throws CoreException {
semaphore.acquireThrowRuntime("init_InputStream");
try {
if(!staticInstanceMap.containsKey(fileNamePath)){
FileTraceConfig instance = new FileTraceConfig(is, globale);
staticInstanceMap.put(fileNamePath, instance);
}
}finally {
semaphore.release("init_InputStream");
}
}
public static void init(File file, boolean globale) throws CoreException {
semaphore.acquireThrowRuntime("init_File");
try {
if(!staticInstanceMap.containsKey(file.getAbsolutePath())){
FileTraceConfig instance = new FileTraceConfig(file, globale);
staticInstanceMap.put(file.getAbsolutePath(), instance);
}
}finally {
semaphore.release("init_File");
}
}
public static void update(File file, boolean globale) throws CoreException {
semaphore.acquireThrowRuntime("update");
try {
updateWithoutSynchronizedEngine(file, globale);
}finally {
semaphore.release("update_File");
}
}
public static void resetFileTraceAssociatePorte() {
semaphore.acquireThrowRuntime("resetFileTraceAssociatePorte");
try {
if(!staticInstanceMap.isEmpty()) {
List<String> removeEntries = new ArrayList<>();
for (Map.Entry<String,FileTraceConfig> entry : staticInstanceMap.entrySet()) {
String path = entry.getKey();
FileTraceConfig config = staticInstanceMap.get(path);
if(config.isGlobale()) {
continue;
}
/**updateWithoutSynchronizedEngine(new File(path), config.isGlobale());*/
removeEntries.add(path); // verra poi ricreato
}
while(!removeEntries.isEmpty()) {
String path = removeEntries.remove(0);
staticInstanceMap.remove(path);
}
}
}finally {
semaphore.release("resetFileTraceAssociatePorte");
}
}
private static void updateWithoutSynchronizedEngine(File file, boolean globale) throws CoreException {
FileTraceConfig newConfig = new FileTraceConfig(file, globale);
FileTraceConfig instance = newConfig;
staticInstanceMap.remove(file.getAbsolutePath());
staticInstanceMap.put(file.getAbsolutePath(), instance);
}
public static FileTraceConfig getConfig(File file, boolean globale) throws CoreException {
if(!staticInstanceMap.containsKey(file.getAbsolutePath())){
init(file, globale);
}
return staticInstanceMap.get(file.getAbsolutePath());
}
private boolean globale = true;
private LogSeverity logSeverity = LogSeverity.info;
private Map<String, String> escape = new HashMap<>();
private String headersSeparator = ",";
private String headerSeparator = "=";
private String headerPrefix = "";
private String headerSuffix = "";
private List<String> headerBlackList;
private List<String> headerWhiteList;
private String headerMultiValueSeparator = ","; // per singolo header
private List<String> propertiesSortKeys = new ArrayList<>();
private Map<String, String> propertiesNames = new HashMap<>();
private Map<String, String> propertiesValues = new HashMap<>();
private Map<String, String> propertiesEncryptionMode = new HashMap<>();
private Map<String, FileTraceEncryptConfig> encryptionMode = new HashMap<>();
private List<String> topicErogazioni = new ArrayList<>();
private Map<String, Topic> topicErogazioniMap = new HashMap<>();
private List<String> topicFruizioni = new ArrayList<>();
private Map<String, Topic> topicFruizioneMap = new HashMap<>();
public FileTraceConfig(File file, boolean globale) throws CoreException {
try(FileInputStream fin = new FileInputStream(file)){
initEngine(fin, globale);
}catch(Exception e) {
throw new CoreException(e.getMessage(),e);
}
}
public FileTraceConfig(InputStream is, boolean globale) throws CoreException {
initEngine(is, globale);
}
private static boolean escapeInFile = true;
public static boolean isEscapeInFile() {
return escapeInFile;
}
public static void setEscapeInFile(boolean escapeInFile) {
FileTraceConfig.escapeInFile = escapeInFile;
}
private void initEngine(InputStream is, boolean globale) throws CoreException {
try {
this.globale = globale;
Properties p = new Properties();
if(escapeInFile) {
p.load(is); // non tratta bene i caratteri speciali
}
else {
fillProperties(p, is);
File fTmp = FileSystemUtilities.createTempFile("test", ".properties");
try {
try(FileOutputStream fout = new FileOutputStream(fTmp)){
p.store(fout, "test");
}
try(FileInputStream finNewP = new FileInputStream(fTmp)){
p = new Properties();
p.load(finNewP);
}
}finally {
FileSystemUtilities.deleteFile(fTmp);
}
}
PropertiesReader reader = new PropertiesReader(p,true);
// ** Log **
String tmp = getProperty(reader, "log.severity", false);
if(tmp!=null) {
this.logSeverity = LogSeverity.valueOf(tmp);
}
InputStream isLog = getInputStreamLogFile(reader);
Properties pLog = new Properties();
pLog.load(isLog);
LoggerWrapperFactory.setLogConfiguration(pLog, true);
// ** Topics **
boolean erogazioni = true;
registerTopic(reader, erogazioni);
registerTopic(reader, !erogazioni);
// ** Encryption mode
this.encryptionMode = FileTraceEncryptConfig.parse(reader);
// ** Format **
readFormatProperties(reader);
}catch(Exception t) {
throw new CoreException(t.getMessage(),t);
}
}
private void fillProperties(Properties p, InputStream is) {
Scanner scanner = new Scanner(is);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
if(line.startsWith("#") ||
StringUtils.isEmpty(line) ||
(line.endsWith("=") && line.length()==1) ||
(line.indexOf("=")<=0)
) {
continue;
}
/**System.out.println("LINE ["+line+"]");*/
String key = null;
String value = "";
if(line.endsWith("=")) {
key = line.substring(0, line.length()-1);
}
else {
int indexOf = line.indexOf("=");
key = line.substring(0, indexOf);
value = line.substring(indexOf+1, line.length());
}
p.put(key, value);
}
scanner.close();
}
private InputStream getInputStreamLogFile(PropertiesReader reader) throws UtilsException, FileNotFoundException {
String tmp = getProperty(reader, "log.config.file", true);
File fTmp = new File(tmp);
if(fTmp.exists()) {
return new FileInputStream(fTmp);
}
InputStream isTmp = FileTraceConfig.class.getResourceAsStream(tmp);
if(isTmp!=null) {
return isTmp;
}
if(!tmp.startsWith("/")) {
isTmp = FileTraceConfig.class.getResourceAsStream("/"+tmp);
if(isTmp!=null) {
return isTmp;
}
}
fTmp = new File(OpenSPCoop2Properties.getInstance().getRootDirectory(), tmp);
if(fTmp.exists()) {
return new FileInputStream(fTmp);
}
throw new UtilsException("File '"+tmp+"' not found");
}
private void registerTopic(PropertiesReader reader, boolean erogazioni) throws UtilsException {
String tipo = erogazioni ? "erogazioni" : "fruizioni";
String propertyName = "topic."+tipo;
String tmp = getProperty(reader, propertyName, false);
if(tmp!=null && !StringUtils.isEmpty(tmp)) {
List<String> list = erogazioni ? this.topicErogazioni : this.topicFruizioni;
Map<String, Topic> map = erogazioni ? this.topicErogazioniMap : this.topicFruizioneMap;
String [] split = tmp.split(",");
if(split!=null && split.length>0) {
for (int i = 0; i < split.length; i++) {
String nome = split[i].trim();
if(list.contains(nome)) {
throw new UtilsException("Found duplicate topic '"+nome+"' ("+tipo+")");
}
list.add(nome);
Topic topic = new Topic();
topic.setErogazioni(erogazioni);
topic.setNome(nome);
String propertyNameOnlyRequestSent = propertyName+"."+nome+".requestSent";
String tmpOnlyRequestSent = getProperty(reader, propertyNameOnlyRequestSent, false);
if(tmpOnlyRequestSent!=null) {
topic.setOnlyRequestSent(Boolean.valueOf(tmpOnlyRequestSent));
}
else {
// backward
propertyNameOnlyRequestSent = propertyName+"."+nome+".requestSended";
tmpOnlyRequestSent = getProperty(reader, propertyNameOnlyRequestSent, false);
if(tmpOnlyRequestSent!=null) {
topic.setOnlyRequestSent(Boolean.valueOf(tmpOnlyRequestSent));
}
}
String propertyNameInRequestContentDefined = propertyName+"."+nome+".inRequestContentDefined";
String tmpInRequestContentDefined = getProperty(reader, propertyNameInRequestContentDefined, false);
if(tmpInRequestContentDefined!=null)
topic.setOnlyInRequestContentDefined(Boolean.valueOf(tmpInRequestContentDefined));
String propertyNameOutRequestContentDefined = propertyName+"."+nome+".outRequestContentDefined";
String tmpOutRequestContentDefined = getProperty(reader, propertyNameOutRequestContentDefined, false);
if(tmpOutRequestContentDefined!=null)
topic.setOnlyOutRequestContentDefined(Boolean.valueOf(tmpOutRequestContentDefined));
String propertyNameInResponseContentDefined = propertyName+"."+nome+".inResponseContentDefined";
String tmpInResponseContentDefined = getProperty(reader, propertyNameInResponseContentDefined, false);
if(tmpInResponseContentDefined!=null)
topic.setOnlyInResponseContentDefined(Boolean.valueOf(tmpInResponseContentDefined));
String propertyNameOutResponseContentDefined = propertyName+"."+nome+".outResponseContentDefined";
String tmpOutResponseContentDefined = getProperty(reader, propertyNameOutResponseContentDefined, false);
if(tmpOutResponseContentDefined!=null)
topic.setOnlyOutResponseContentDefined(Boolean.valueOf(tmpOutResponseContentDefined));
String propertyNameTrackingPhases = propertyName+"."+nome+".trackingPhases";
List<String> trackingPhases = getList(reader, propertyNameTrackingPhases);
if(trackingPhases!=null && !trackingPhases.isEmpty()) {
for (String phase : trackingPhases) {
if("inRequest".equalsIgnoreCase(phase) || "in-request".equalsIgnoreCase(phase) || "requestIn".equalsIgnoreCase(phase) || "request-in".equalsIgnoreCase(phase)) {
topic.addFaseTracciamento(FaseTracciamento.IN_REQUEST);
}
else if("outRequest".equalsIgnoreCase(phase) || "out-request".equalsIgnoreCase(phase) || "requestOut".equalsIgnoreCase(phase) || "request-out".equalsIgnoreCase(phase)) {
topic.addFaseTracciamento(FaseTracciamento.OUT_REQUEST);
}
else if("outResponse".equalsIgnoreCase(phase) || "out-response".equalsIgnoreCase(phase) || "responseOut".equalsIgnoreCase(phase) || "response-out".equalsIgnoreCase(phase)) {
topic.addFaseTracciamento(FaseTracciamento.OUT_RESPONSE);
}
else if("postOutResponse".equalsIgnoreCase(phase) || "post-out-response".equalsIgnoreCase(phase) || "postResponseOut".equalsIgnoreCase(phase) || "post-response-out".equalsIgnoreCase(phase)) { topic.addFaseTracciamento(FaseTracciamento.POST_OUT_RESPONSE);
topic.addFaseTracciamento(FaseTracciamento.POST_OUT_RESPONSE);
}
else {
throw new UtilsException("Found unknown tracking phase '"+phase+"' in property '"+propertyNameTrackingPhases+"'");
}
}
}
String propertyNameCategory = "category.topic."+tipo+"."+nome;
String category = getProperty(reader, propertyNameCategory, true);
topic.setCategoryName(category);
topic.setLog(LoggerWrapperFactory.getLogger(category));
String propertyNameFormat = "format.topic."+tipo+"."+nome;
String format = getProperty(reader, propertyNameFormat, true);
topic.setFormat(format);
map.put(nome, topic);
}
}
}
}
private List<String> getList(PropertiesReader reader, String propertyName) throws UtilsException {
List<String> list = new ArrayList<>();
String tmp = getProperty(reader, propertyName, false);
if(tmp!=null && !StringUtils.isEmpty(tmp)) {
String [] split = tmp.split(",");
if(split!=null && split.length>0) {
for (int i = 0; i < split.length; i++) {
String nome = split[i].trim();
if(list.contains(nome)) {
throw new UtilsException("Found duplicate topic '"+nome+"' in property '"+propertyName+"'");
}
list.add(nome);
}
}
}
return list;
}
private void readFormatProperties(PropertiesReader reader) throws UtilsException {
Properties escapeMap = reader.readProperties("format.escape.");
if(escapeMap!=null && !escapeMap.isEmpty()) {
for (Object s : escapeMap.keySet()) {
String key = (String) s;
this.escape.put(key, escapeMap.getProperty(key));
}
}
List<String> listPosition = new ArrayList<>();
List<String> listPnames = new ArrayList<>();
String prefixProperty = "format.property.";
Properties propertiesMap = reader.readProperties(prefixProperty);
parseProperties(propertiesMap, prefixProperty,
listPosition, listPnames,
false,
reader);
String prefixEncryptedProperty = "format.encryptedProperty.";
propertiesMap = reader.readProperties(prefixEncryptedProperty);
parseProperties(propertiesMap, prefixEncryptedProperty,
listPosition, listPnames,
true,
reader);
Collections.sort(listPosition);
this.propertiesSortKeys = listPosition;
String tmp = getProperty(reader, "format.headers.separator", false);
if(tmp!=null) {
this.headersSeparator = tmp;
}
tmp = getProperty(reader, "format.headers.header.separator", false);
if(tmp!=null) {
this.headerSeparator = tmp;
}
tmp = getProperty(reader, "format.headers.header.prefix", false);
if(tmp!=null) {
this.headerPrefix = tmp;
}
tmp = getProperty(reader, "format.headers.header.suffix", false);
if(tmp!=null) {
this.headerSuffix = tmp;
}
tmp = getProperty(reader, "format.header.multiValueSeparator", false);
if(tmp!=null) {
this.headerMultiValueSeparator = tmp;
}
tmp = getProperty(reader, "format.header.whiteList", false);
if(tmp!=null && !"".equals(tmp.trim())) {
tmp = tmp.trim();
this.headerWhiteList = new ArrayList<>();
if(tmp.contains(",")) {
String [] split = tmp.split(",");
if(split!=null && split.length>0) {
for (String s : split) {
if(s!=null) {
s = s.trim();
if(!"".equals(s)) {
this.headerWhiteList.add(s);
}
}
}
}
}
else {
this.headerWhiteList.add(tmp);
}
}
tmp = getProperty(reader, "format.header.blackList", false);
if(tmp!=null && !"".equals(tmp.trim())) {
tmp = tmp.trim();
this.headerBlackList = new ArrayList<>();
if(tmp.contains(",")) {
String [] split = tmp.split(",");
if(split!=null && split.length>0) {
for (String s : split) {
if(s!=null) {
s = s.trim();
if(!"".equals(s)) {
this.headerBlackList.add(s);
}
}
}
}
}
else {
this.headerBlackList.add(tmp);
}
}
}
private void parseProperties(Properties propertiesMap, String prefix,
List<String> listPosition, List<String> listPnames,
boolean encrypted,
PropertiesReader reader) throws UtilsException {
if(propertiesMap!=null && !propertiesMap.isEmpty()) {
for (Object s : propertiesMap.keySet()) {
String key = (String) s;
parseProperty(key, propertiesMap, prefix,
listPosition, listPnames,
encrypted,
reader);
}
}
}
private void parseProperty(String key, Properties propertiesMap, String prefix,
List<String> listPosition, List<String> listPnames,
boolean encrypted,
PropertiesReader reader) throws UtilsException {
if(!key.contains(".") || key.length()<3 || key.startsWith(".") || key.endsWith(".")) {
throw new UtilsException("Format property '"+prefix+""+key+"' wrong (expected: "+prefix+"<intPosition>.<nomeProperty>)");
}
String prefixBad = "Bad property '"+prefix+""+key+"'";
int indexOf = key.indexOf(".");
String pos = key.substring(0, indexOf);
String nomeP = key.substring(indexOf+1,key.length());
String posPadded = StringUtils.leftPad(pos, 10, "0");
if(listPosition.contains(posPadded)) {
throw new UtilsException(prefixBad+": contains duplicate position '"+pos+"'");
}
if(listPnames.contains(nomeP)) {
throw new UtilsException(prefixBad+". contains duplicate name '"+nomeP+"'");
}
listPosition.add(posPadded);
this.propertiesNames.put(posPadded, nomeP);
this.propertiesValues.put(posPadded, propertiesMap.getProperty(key));
if(encrypted) {
parseEncryptedProperty(reader,
key, prefixBad, posPadded);
}
}
private void parseEncryptedProperty(PropertiesReader reader,
String key, String prefixBad, String posPadded) throws UtilsException {
String modeP = "format.encrypt."+key;
String mode = reader.getValue_convertEnvProperties(modeP);
if(this.encryptionMode==null || this.encryptionMode.isEmpty()) {
throw new UtilsException(prefixBad+": no encryption mode defined");
}
if(mode==null || StringUtils.isEmpty(mode.trim())) {
if(this.encryptionMode.size()==1) {
// ce n'รจ solo una definita
this.propertiesEncryptionMode.put(posPadded, this.encryptionMode.keySet().iterator().next());
}
else {
throw new UtilsException(prefixBad+": undefined property '"+modeP+"'");
}
}
else {
mode = mode.trim();
if(!this.encryptionMode.containsKey(mode)) {
throw new UtilsException(prefixBad+": unknown encryption mode '"+mode+"'");
}
this.propertiesEncryptionMode.put(posPadded, mode);
}
}
private String getProperty(PropertiesReader reader, String key, boolean required) throws UtilsException {
String tmp = reader.getValue(key);
if(tmp==null) {
if(required) {
throw new UtilsException("Property '"+key+"' not found");
}
return null;
}
else {
tmp = tmp.trim();
return tmp;
}
}
public LogSeverity getLogSeverity() {
return this.logSeverity;
}
public Map<String, String> getEscape() {
return this.escape;
}
public String getHeadersSeparator() {
return this.headersSeparator;
}
public String getHeaderSeparator() {
return this.headerSeparator;
}
public String getHeaderPrefix() {
return this.headerPrefix;
}
public String getHeaderSuffix() {
return this.headerSuffix;
}
public List<String> getHeaderBlackList() {
return this.headerBlackList;
}
public List<String> getHeaderWhiteList() {
return this.headerWhiteList;
}
public String getHeaderMultiValueSeparator() {
return this.headerMultiValueSeparator;
}
public List<String> getPropertiesSortKeys() {
return this.propertiesSortKeys;
}
public Map<String, String> getPropertiesNames() {
return this.propertiesNames;
}
public Map<String, String> getPropertiesValues() {
return this.propertiesValues;
}
public Map<String, String> getPropertiesEncryptionMode() {
return this.propertiesEncryptionMode;
}
public Map<String, FileTraceEncryptConfig> getEncryptionMode() {
return this.encryptionMode;
}
public List<String> getTopicErogazioni() {
return this.topicErogazioni;
}
public Map<String, Topic> getTopicErogazioniMap() {
return this.topicErogazioniMap;
}
public List<String> getTopicFruizioni() {
return this.topicFruizioni;
}
public Map<String, Topic> getTopicFruizioneMap() {
return this.topicFruizioneMap;
}
public boolean isGlobale() {
return this.globale;
}
}