Performance tuning - backend
This commit is contained in:
@@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
<display-name>Matrix Cygnus 1.0</display-name>
|
<display-name>Matrix Cygnus 1.0</display-name>
|
||||||
|
|
||||||
|
<listener>
|
||||||
|
<listener-class>matrix.nimble.utilities.DatabasePoolLifecycleListener</listener-class>
|
||||||
|
</listener>
|
||||||
|
|
||||||
<!-- The front controller of the Spring MVC Web application, responsible
|
<!-- The front controller of the Spring MVC Web application, responsible
|
||||||
for handling all application requests -->
|
for handling all application requests -->
|
||||||
<servlet>
|
<servlet>
|
||||||
|
|||||||
6
pom.xml
6
pom.xml
@@ -21,6 +21,7 @@
|
|||||||
<poi.version>5.5.1</poi.version>
|
<poi.version>5.5.1</poi.version>
|
||||||
<itext.version>5.3.4</itext.version>
|
<itext.version>5.3.4</itext.version>
|
||||||
<log4j.version>2.24.3</log4j.version>
|
<log4j.version>2.24.3</log4j.version>
|
||||||
|
<hikaricp.version>6.3.3</hikaricp.version>
|
||||||
<junit.version>5.12.2</junit.version>
|
<junit.version>5.12.2</junit.version>
|
||||||
<tomcat.version>10.1.57</tomcat.version>
|
<tomcat.version>10.1.57</tomcat.version>
|
||||||
<server.port>8080</server.port>
|
<server.port>8080</server.port>
|
||||||
@@ -123,6 +124,11 @@
|
|||||||
<version>42.7.13</version>
|
<version>42.7.13</version>
|
||||||
<scope>runtime</scope>
|
<scope>runtime</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.zaxxer</groupId>
|
||||||
|
<artifactId>HikariCP</artifactId>
|
||||||
|
<version>${hikaricp.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.microsoft.sqlserver</groupId>
|
<groupId>com.microsoft.sqlserver</groupId>
|
||||||
<artifactId>mssql-jdbc</artifactId>
|
<artifactId>mssql-jdbc</artifactId>
|
||||||
|
|||||||
@@ -324,7 +324,7 @@ public class CombinedExcelReporting {
|
|||||||
}
|
}
|
||||||
if(isProcessFlag())
|
if(isProcessFlag())
|
||||||
{
|
{
|
||||||
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail sent successfully.\n" : ""));
|
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail delivery queued.\n" : ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void DesignReport(String [] reportData,String [][] reportlayout)
|
private void DesignReport(String [] reportData,String [][] reportlayout)
|
||||||
@@ -430,15 +430,11 @@ public class CombinedExcelReporting {
|
|||||||
{
|
{
|
||||||
if(isAutoemail)
|
if(isAutoemail)
|
||||||
{
|
{
|
||||||
SendReports SR=new SendReports();
|
if (!ReportEmailJobExecutor.submitBatch(getErrCode(), processedOn, BranchId, getUserId(), runningMode))
|
||||||
SR.setErrCode(getErrCode());
|
|
||||||
SR.setProcessFlag(true);
|
|
||||||
SR.SendReportsByBatch(processedOn, BranchId,getUserId(),runningMode);
|
|
||||||
if (!SR.isProcessFlag())
|
|
||||||
{
|
{
|
||||||
setErrMsg(SR.getErrMsg().replace(getErrCode()+"SEML:warning:", getErrCode()+"SEML:warning:Bank Reports generated successfully.\n\n"));
|
setErrMsg(getErrCode()+"SEML:warning:Bank Reports generated successfully, but the email queue is full. Please retry from the mailbox.");
|
||||||
setErrDesc(SR.getErrDesc());
|
setErrDesc("The bounded report email queue has reached its configured capacity.");
|
||||||
setProcessFlag(SR.isProcessFlag());
|
setProcessFlag(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ public class CombinedReporting {
|
|||||||
}
|
}
|
||||||
if(isProcessFlag())
|
if(isProcessFlag())
|
||||||
{
|
{
|
||||||
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail sent successfully.\n" : ""));
|
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail delivery queued.\n" : ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void DesignReport(String [] reportData,String [][] reportlayout,PDFFormatter PDFF)
|
private void DesignReport(String [] reportData,String [][] reportlayout,PDFFormatter PDFF)
|
||||||
@@ -482,15 +482,11 @@ public class CombinedReporting {
|
|||||||
{
|
{
|
||||||
if(isAutoemail)
|
if(isAutoemail)
|
||||||
{
|
{
|
||||||
SendReports SR=new SendReports();
|
if (!ReportEmailJobExecutor.submitBatch(getErrCode(), processedOn, BranchId, getUserId(), runningMode))
|
||||||
SR.setErrCode(getErrCode());
|
|
||||||
SR.setProcessFlag(true);
|
|
||||||
SR.SendReportsByBatch(processedOn, BranchId,getUserId(),runningMode);
|
|
||||||
if (!SR.isProcessFlag())
|
|
||||||
{
|
{
|
||||||
setErrMsg(SR.getErrMsg().replace(getErrCode()+"SEML:warning:", getErrCode()+"SEML:warning:Bank Reports generated successfully.\n\n"));
|
setErrMsg(getErrCode()+"SEML:warning:Bank Reports generated successfully, but the email queue is full. Please retry from the mailbox.");
|
||||||
setErrDesc(SR.getErrDesc());
|
setErrDesc("The bounded report email queue has reached its configured capacity.");
|
||||||
setProcessFlag(SR.isProcessFlag());
|
setProcessFlag(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ public class CombinedWordlReporting {
|
|||||||
}
|
}
|
||||||
if(isProcessFlag())
|
if(isProcessFlag())
|
||||||
{
|
{
|
||||||
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail sent successfully.\n" : ""));
|
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail delivery queued.\n" : ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void DesignReport(String [] reportData,String [][] reportlayout)
|
private void DesignReport(String [] reportData,String [][] reportlayout)
|
||||||
@@ -488,15 +488,11 @@ public class CombinedWordlReporting {
|
|||||||
{
|
{
|
||||||
if(isAutoemail)
|
if(isAutoemail)
|
||||||
{
|
{
|
||||||
SendReports SR=new SendReports();
|
if (!ReportEmailJobExecutor.submitBatch(getErrCode(), processedOn, BranchId, getUserId(), runningMode))
|
||||||
SR.setErrCode(getErrCode());
|
|
||||||
SR.setProcessFlag(true);
|
|
||||||
SR.SendReportsByBatch(processedOn, BranchId,getUserId(),runningMode);
|
|
||||||
if (!SR.isProcessFlag())
|
|
||||||
{
|
{
|
||||||
setErrMsg(SR.getErrMsg().replace(getErrCode()+"SEML:warning:", getErrCode()+"SEML:warning:Bank Reports generated successfully.\n\n"));
|
setErrMsg(getErrCode()+"SEML:warning:Bank Reports generated successfully, but the email queue is full. Please retry from the mailbox.");
|
||||||
setErrDesc(SR.getErrDesc());
|
setErrDesc("The bounded report email queue has reached its configured capacity.");
|
||||||
setProcessFlag(SR.isProcessFlag());
|
setProcessFlag(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ public class CombinedWordlReportingTabular {
|
|||||||
}
|
}
|
||||||
if(isProcessFlag())
|
if(isProcessFlag())
|
||||||
{
|
{
|
||||||
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail sent successfully.\n" : ""));
|
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail delivery queued.\n" : ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void DesignReport(String [] reportData,String [][] reportlayout)
|
private void DesignReport(String [] reportData,String [][] reportlayout)
|
||||||
@@ -488,15 +488,11 @@ public class CombinedWordlReportingTabular {
|
|||||||
{
|
{
|
||||||
if(isAutoemail)
|
if(isAutoemail)
|
||||||
{
|
{
|
||||||
SendReports SR=new SendReports();
|
if (!ReportEmailJobExecutor.submitBatch(getErrCode(), processedOn, BranchId, getUserId(), runningMode))
|
||||||
SR.setErrCode(getErrCode());
|
|
||||||
SR.setProcessFlag(true);
|
|
||||||
SR.SendReportsByBatch(processedOn, BranchId,getUserId(),runningMode);
|
|
||||||
if (!SR.isProcessFlag())
|
|
||||||
{
|
{
|
||||||
setErrMsg(SR.getErrMsg().replace(getErrCode()+"SEML:warning:", getErrCode()+"SEML:warning:Bank Reports generated successfully.\n\n"));
|
setErrMsg(getErrCode()+"SEML:warning:Bank Reports generated successfully, but the email queue is full. Please retry from the mailbox.");
|
||||||
setErrDesc(SR.getErrDesc());
|
setErrDesc("The bounded report email queue has reached its configured capacity.");
|
||||||
setProcessFlag(SR.isProcessFlag());
|
setProcessFlag(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ public class PartWiseReporting {
|
|||||||
}
|
}
|
||||||
if(isProcessFlag())
|
if(isProcessFlag())
|
||||||
{
|
{
|
||||||
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail sent successfully.\n" : ""));
|
setErrMsg(getErrCode()+"REPGEN:Info:Reports generated successfully."+(RS.isAutoemail() ? "\n\nEmail delivery queued.\n" : ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private boolean CreateReport(String [][] reportData,String [][] reportlayout,String reportType,String rootPath,String curDate,String processedOn,String reportBy,String repType,String UserId,String BranchId,boolean isArchive,String runningMode,String portfolioid)
|
private boolean CreateReport(String [][] reportData,String [][] reportlayout,String reportType,String rootPath,String curDate,String processedOn,String reportBy,String repType,String UserId,String BranchId,boolean isArchive,String runningMode,String portfolioid)
|
||||||
@@ -405,15 +405,11 @@ public class PartWiseReporting {
|
|||||||
{
|
{
|
||||||
if(isAutoemail)
|
if(isAutoemail)
|
||||||
{
|
{
|
||||||
SendReports SR=new SendReports();
|
if (!ReportEmailJobExecutor.submitBatch(getErrCode(), processedOn, BranchId, UserId, runningMode))
|
||||||
SR.setErrCode(getErrCode());
|
|
||||||
SR.setProcessFlag(true);
|
|
||||||
SR.SendReportsByBatch(processedOn, BranchId, UserId,runningMode);
|
|
||||||
if (!SR.isProcessFlag())
|
|
||||||
{
|
{
|
||||||
setErrMsg(SR.getErrMsg().replace(getErrCode()+"SEML:warning:", getErrCode()+"SEML:warning:Bank Reports generated successfully.\n\n"));
|
setErrMsg(getErrCode()+"SEML:warning:Bank Reports generated successfully, but the email queue is full. Please retry from the mailbox.");
|
||||||
setErrDesc(SR.getErrDesc());
|
setErrDesc("The bounded report email queue has reached its configured capacity.");
|
||||||
setProcessFlag(SR.isProcessFlag());
|
setProcessFlag(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package matrix.nimble.operation.output.model;
|
||||||
|
|
||||||
|
import java.util.concurrent.ArrayBlockingQueue;
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
/** Bounded background executor for automatically generated report-email batches. */
|
||||||
|
public final class ReportEmailJobExecutor {
|
||||||
|
private static final int WORKERS = integerSetting("matrix.mail.workers", 2);
|
||||||
|
private static final int QUEUE_CAPACITY = integerSetting("matrix.mail.queueCapacity", 50);
|
||||||
|
private static final AtomicInteger THREAD_SEQUENCE = new AtomicInteger();
|
||||||
|
private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
|
||||||
|
WORKERS,
|
||||||
|
WORKERS,
|
||||||
|
0L,
|
||||||
|
TimeUnit.MILLISECONDS,
|
||||||
|
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
|
||||||
|
new ReportEmailThreadFactory(),
|
||||||
|
new ThreadPoolExecutor.AbortPolicy());
|
||||||
|
|
||||||
|
private ReportEmailJobExecutor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean submitBatch(String errorCode, String batch, String branchId,
|
||||||
|
String userId, String runningMode) {
|
||||||
|
try {
|
||||||
|
EXECUTOR.execute(() -> sendBatch(errorCode, batch, branchId, userId, runningMode));
|
||||||
|
return true;
|
||||||
|
} catch (RejectedExecutionException rejected) {
|
||||||
|
System.err.println("Report email queue is full; batch was not queued: " + batch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void sendBatch(String errorCode, String batch, String branchId,
|
||||||
|
String userId, String runningMode) {
|
||||||
|
try {
|
||||||
|
SendReports reports = new SendReports();
|
||||||
|
reports.setErrCode(errorCode);
|
||||||
|
reports.setProcessFlag(true);
|
||||||
|
reports.SendReportsByBatch(batch, branchId, userId, runningMode);
|
||||||
|
if (!reports.isProcessFlag()) {
|
||||||
|
System.err.println("Report email batch completed with failures: " + reports.getErrMsg());
|
||||||
|
}
|
||||||
|
} catch (RuntimeException exception) {
|
||||||
|
System.err.println("Report email batch failed unexpectedly: " + exception.getMessage());
|
||||||
|
exception.printStackTrace(System.err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void shutdown() {
|
||||||
|
EXECUTOR.shutdown();
|
||||||
|
try {
|
||||||
|
if (!EXECUTOR.awaitTermination(10, TimeUnit.SECONDS)) {
|
||||||
|
EXECUTOR.shutdownNow();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException interrupted) {
|
||||||
|
EXECUTOR.shutdownNow();
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int integerSetting(String name, int defaultValue) {
|
||||||
|
int value = Integer.parseInt(System.getProperty(name, Integer.toString(defaultValue)));
|
||||||
|
if (value < 1) {
|
||||||
|
throw new IllegalArgumentException(name + " must be greater than zero");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class ReportEmailThreadFactory implements ThreadFactory {
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable task) {
|
||||||
|
Thread thread = new Thread(task, "cygnus-report-email-" + THREAD_SEQUENCE.incrementAndGet());
|
||||||
|
thread.setDaemon(true);
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -137,9 +137,7 @@ public class DBFunctions {
|
|||||||
}
|
}
|
||||||
private void ConnectDB() {
|
private void ConnectDB() {
|
||||||
try {
|
try {
|
||||||
Class.forName(ModFunc.decrypt(FFunc.getDBDriver())).newInstance();
|
con = DatabaseConnectionPool.getConnection();
|
||||||
//con = DriverManager.getConnection(ModFunc.decrypt(FFunc.getConnString()), ModFunc.decrypt(FFunc.getDBUser()), ModFunc.decrypt(FFunc.getDBPassword()));
|
|
||||||
con = DriverManager.getConnection("jdbc:postgresql://192.168.0.111:5432/matrix", "postgres", "M@triXPostgr3s@6202");
|
|
||||||
} catch (Exception exce) {
|
} catch (Exception exce) {
|
||||||
setErrMsg(getErrCode()+"CONDB:Error:Could not connect with database. Please check the network connection.");
|
setErrMsg(getErrCode()+"CONDB:Error:Could not connect with database. Please check the network connection.");
|
||||||
setErrDesc(exce.getMessage());
|
setErrDesc(exce.getMessage());
|
||||||
@@ -474,16 +472,16 @@ public class DBFunctions {
|
|||||||
String [][] dataArray=null;
|
String [][] dataArray=null;
|
||||||
Hashtable<String , String> dataHash=new Hashtable<String, String>();
|
Hashtable<String , String> dataHash=new Hashtable<String, String>();
|
||||||
int ColCount=0;
|
int ColCount=0;
|
||||||
String Result="";
|
StringBuilder result = new StringBuilder();
|
||||||
int RowIndex=0;
|
int RowIndex=0;
|
||||||
String tempStr="";
|
String tempStr="";
|
||||||
String hashKey="";
|
String hashKey="";
|
||||||
String hashValue="";
|
StringBuilder hashValue = new StringBuilder();
|
||||||
int hascol=getHashKeyColIndex();
|
int hascol=getHashKeyColIndex();
|
||||||
boolean ishash=isGenerateHash();
|
boolean ishash=isGenerateHash();
|
||||||
while (RstSet.next())
|
while (RstSet.next())
|
||||||
{
|
{
|
||||||
hashValue="";
|
hashValue.setLength(0);
|
||||||
if(RowIndex==0)
|
if(RowIndex==0)
|
||||||
{
|
{
|
||||||
rsmd = RstSet.getMetaData();
|
rsmd = RstSet.getMetaData();
|
||||||
@@ -499,21 +497,21 @@ public class DBFunctions {
|
|||||||
{
|
{
|
||||||
hashKey=tempStr;
|
hashKey=tempStr;
|
||||||
}
|
}
|
||||||
hashValue+=tempStr+ColDelimeter;
|
hashValue.append(tempStr).append(ColDelimeter);
|
||||||
}
|
}
|
||||||
Result+=tempStr+ColDelimeter;
|
result.append(tempStr).append(ColDelimeter);
|
||||||
dataArray[RowIndex][i-1]=tempStr;
|
dataArray[RowIndex][i-1]=tempStr;
|
||||||
}
|
}
|
||||||
if(ishash)
|
if(ishash)
|
||||||
{
|
{
|
||||||
dataHash.put(hashKey, hashValue);
|
dataHash.put(hashKey, hashValue.toString());
|
||||||
}
|
}
|
||||||
Result+=RowDelimeter;
|
result.append(RowDelimeter);
|
||||||
RowIndex++;
|
RowIndex++;
|
||||||
}
|
}
|
||||||
setResultHash(dataHash);
|
setResultHash(dataHash);
|
||||||
setResultArray(dataArray);
|
setResultArray(dataArray);
|
||||||
return Result;
|
return result.toString();
|
||||||
}
|
}
|
||||||
private static int getRowCount(ResultSet set) throws SQLException
|
private static int getRowCount(ResultSet set) throws SQLException
|
||||||
{
|
{
|
||||||
@@ -535,10 +533,9 @@ public class DBFunctions {
|
|||||||
ConnectDB();
|
ConnectDB();
|
||||||
if(isProcessFlag())
|
if(isProcessFlag())
|
||||||
{
|
{
|
||||||
try
|
try (CallableStatement proc = con.prepareCall("{ ? = call "+ProcedureName+" }"))
|
||||||
{
|
{
|
||||||
con.setAutoCommit(false);
|
con.setAutoCommit(false);
|
||||||
CallableStatement proc =con.prepareCall("{ ? = call "+ProcedureName+" }");
|
|
||||||
proc.registerOutParameter(1, Types.LONGVARCHAR);
|
proc.registerOutParameter(1, Types.LONGVARCHAR);
|
||||||
if(ParameterList.isEmpty()){}
|
if(ParameterList.isEmpty()){}
|
||||||
else
|
else
|
||||||
@@ -555,11 +552,24 @@ public class DBFunctions {
|
|||||||
}
|
}
|
||||||
catch(Exception excp)
|
catch(Exception excp)
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
if (con != null) {
|
||||||
|
con.rollback();
|
||||||
|
}
|
||||||
|
} catch (SQLException rollbackException) {
|
||||||
|
setErrDesc(excp.getMessage()+"; rollback failed: "+rollbackException.getMessage());
|
||||||
|
}
|
||||||
setProcessFlag(false);
|
setProcessFlag(false);
|
||||||
setErrMsg(getErrCode()+"CLPROC:Error:Record updation failed. Please try again later");
|
setErrMsg(getErrCode()+"CLPROC:Error:Record updation failed. Please try again later");
|
||||||
|
if (getErrDesc() == null || !getErrDesc().contains("rollback failed")) {
|
||||||
setErrDesc(excp.getMessage());
|
setErrDesc(excp.getMessage());
|
||||||
|
}
|
||||||
Result=getErrMsg();
|
Result=getErrMsg();
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
CloseConnection();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Result;
|
return Result;
|
||||||
|
|||||||
70
src/matrix/nimble/utilities/DatabaseConnectionPool.java
Normal file
70
src/matrix/nimble/utilities/DatabaseConnectionPool.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package matrix.nimble.utilities;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
|
||||||
|
/** Shared, bounded JDBC connection pool for the legacy database layer. */
|
||||||
|
public final class DatabaseConnectionPool {
|
||||||
|
private static final String DEFAULT_JDBC_URL = "jdbc:postgresql://192.168.0.111:5432/matrix";
|
||||||
|
private static final String DEFAULT_USERNAME = "postgres";
|
||||||
|
private static final String DEFAULT_PASSWORD = "M@triXPostgr3s@6202";
|
||||||
|
private static volatile HikariDataSource dataSource;
|
||||||
|
|
||||||
|
private DatabaseConnectionPool() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Connection getConnection() throws SQLException {
|
||||||
|
return getDataSource().getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HikariDataSource getDataSource() {
|
||||||
|
HikariDataSource current = dataSource;
|
||||||
|
if (current != null) {
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
synchronized (DatabaseConnectionPool.class) {
|
||||||
|
if (dataSource == null) {
|
||||||
|
HikariConfig config = new HikariConfig();
|
||||||
|
config.setPoolName("CygnusDatabasePool");
|
||||||
|
config.setJdbcUrl(setting("matrix.db.url", "MATRIX_DB_URL", DEFAULT_JDBC_URL));
|
||||||
|
config.setUsername(setting("matrix.db.username", "MATRIX_DB_USERNAME", DEFAULT_USERNAME));
|
||||||
|
config.setPassword(setting("matrix.db.password", "MATRIX_DB_PASSWORD", DEFAULT_PASSWORD));
|
||||||
|
config.setMaximumPoolSize(integerSetting("matrix.db.maximumPoolSize", 10));
|
||||||
|
config.setMinimumIdle(integerSetting("matrix.db.minimumIdle", 2));
|
||||||
|
config.setConnectionTimeout(longSetting("matrix.db.connectionTimeoutMs", 30_000L));
|
||||||
|
config.setValidationTimeout(longSetting("matrix.db.validationTimeoutMs", 5_000L));
|
||||||
|
config.setIdleTimeout(longSetting("matrix.db.idleTimeoutMs", 600_000L));
|
||||||
|
config.setMaxLifetime(longSetting("matrix.db.maxLifetimeMs", 1_800_000L));
|
||||||
|
config.setLeakDetectionThreshold(longSetting("matrix.db.leakDetectionThresholdMs", 60_000L));
|
||||||
|
dataSource = new HikariDataSource(config);
|
||||||
|
}
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized void close() {
|
||||||
|
if (dataSource != null) {
|
||||||
|
dataSource.close();
|
||||||
|
dataSource = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String setting(String systemProperty, String environmentVariable, String defaultValue) {
|
||||||
|
String value = System.getProperty(systemProperty);
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
value = System.getenv(environmentVariable);
|
||||||
|
}
|
||||||
|
return value == null || value.isBlank() ? defaultValue : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int integerSetting(String name, int defaultValue) {
|
||||||
|
return Integer.parseInt(System.getProperty(name, Integer.toString(defaultValue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long longSetting(String name, long defaultValue) {
|
||||||
|
return Long.parseLong(System.getProperty(name, Long.toString(defaultValue)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package matrix.nimble.utilities;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletContextEvent;
|
||||||
|
import jakarta.servlet.ServletContextListener;
|
||||||
|
import matrix.nimble.operation.output.model.ReportEmailJobExecutor;
|
||||||
|
|
||||||
|
/** Releases pooled database resources when Tomcat stops or reloads the application. */
|
||||||
|
public class DatabasePoolLifecycleListener implements ServletContextListener {
|
||||||
|
@Override
|
||||||
|
public void contextDestroyed(ServletContextEvent event) {
|
||||||
|
ReportEmailJobExecutor.shutdown();
|
||||||
|
DatabaseConnectionPool.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,9 @@ import java.io.File;
|
|||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
@@ -29,8 +25,6 @@ import javax.mail.internet.MimeBodyPart;
|
|||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
import javax.mail.internet.MimeMultipart;
|
import javax.mail.internet.MimeMultipart;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
public class EmailFunctions {
|
public class EmailFunctions {
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
@@ -209,6 +203,9 @@ public class EmailFunctions {
|
|||||||
Properties props=new Properties();
|
Properties props=new Properties();
|
||||||
props.setProperty("mail.smtp.auth", "true");
|
props.setProperty("mail.smtp.auth", "true");
|
||||||
props.setProperty("mail.smtp.starttls.enable", "true");
|
props.setProperty("mail.smtp.starttls.enable", "true");
|
||||||
|
props.setProperty("mail.smtp.connectiontimeout", System.getProperty("matrix.mail.connectionTimeoutMs", "30000"));
|
||||||
|
props.setProperty("mail.smtp.timeout", System.getProperty("matrix.mail.readTimeoutMs", "30000"));
|
||||||
|
props.setProperty("mail.smtp.writetimeout", System.getProperty("matrix.mail.writeTimeoutMs", "30000"));
|
||||||
|
|
||||||
if(getUsername().toLowerCase().contains("@arveebizpro.com")) {
|
if(getUsername().toLowerCase().contains("@arveebizpro.com")) {
|
||||||
|
|
||||||
@@ -272,11 +269,8 @@ public class EmailFunctions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
ObjectMapper Obj = new ObjectMapper();
|
|
||||||
String sessionStr = "";
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sessionStr = Obj.writeValueAsString(session);
|
|
||||||
Message message = new MimeMessage(session);
|
Message message = new MimeMessage(session);
|
||||||
message.setFrom(new InternetAddress(getFrom()));
|
message.setFrom(new InternetAddress(getFrom()));
|
||||||
message.setRecipients(Message.RecipientType.TO,InternetAddress.parse(getTo()));
|
message.setRecipients(Message.RecipientType.TO,InternetAddress.parse(getTo()));
|
||||||
@@ -309,25 +303,18 @@ public class EmailFunctions {
|
|||||||
}
|
}
|
||||||
// Send the complete message parts
|
// Send the complete message parts
|
||||||
message.setContent(multipart);
|
message.setContent(multipart);
|
||||||
if(CheckInternetConnection("www.google.co.in"))
|
|
||||||
{
|
|
||||||
Transport.send(message);
|
Transport.send(message);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "Error - Unable to access internet. Please check your internet connection";
|
|
||||||
}
|
|
||||||
/*if(isArchive())
|
/*if(isArchive())
|
||||||
{
|
{
|
||||||
new File(FileList.get(0)).delete();
|
new File(FileList.get(0)).delete();
|
||||||
}*/
|
}*/
|
||||||
}catch(IOException iexce)
|
}catch(IOException iexce)
|
||||||
{
|
{
|
||||||
return "Error - Request Sent to : "+sessionStr + ", Response IO: " + iexce.getMessage();
|
return "Error - Unable to prepare email attachments: " + iexce.getMessage();
|
||||||
}
|
}
|
||||||
catch(MessagingException exce)
|
catch(MessagingException exce)
|
||||||
{
|
{
|
||||||
return "Error - Request Sent to : "+sessionStr + ", Response Message: " + exce.getMessage();
|
return "Error - Unable to send email: " + exce.getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -402,19 +389,4 @@ public class EmailFunctions {
|
|||||||
FileList=new ArrayList<String>();
|
FileList=new ArrayList<String>();
|
||||||
FileList.add(zipFile);
|
FileList.add(zipFile);
|
||||||
}
|
}
|
||||||
public boolean CheckInternetConnection(String UrlToCheck)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
SocketChannel channel;
|
|
||||||
InetSocketAddress socketAddress = new InetSocketAddress(UrlToCheck, 80);
|
|
||||||
channel = SocketChannel.open();
|
|
||||||
channel.configureBlocking(false);
|
|
||||||
channel.connect(socketAddress);
|
|
||||||
return true;
|
|
||||||
}catch(Exception exce)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,15 @@ import java.io.*;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class FileFunctions {
|
public class FileFunctions {
|
||||||
|
private static final Object QUERY_CACHE_LOCK = new Object();
|
||||||
|
private static volatile Map<Integer, String> queryCache = Collections.emptyMap();
|
||||||
|
private static volatile long queryCacheLastModified = Long.MIN_VALUE;
|
||||||
|
private static volatile String queryCachePath = "";
|
||||||
private String ConnString;
|
private String ConnString;
|
||||||
private String DBDriver;
|
private String DBDriver;
|
||||||
private String DBUser;
|
private String DBUser;
|
||||||
@@ -212,15 +219,41 @@ public class FileFunctions {
|
|||||||
{
|
{
|
||||||
realPath=realPath.replace("%20", " ");
|
realPath=realPath.replace("%20", " ");
|
||||||
}
|
}
|
||||||
File QueryFile = new File(realPath + "nimble.qry");
|
File queryFile = new File(realPath + "nimble.qry");
|
||||||
BufferedReader Breader = new BufferedReader(new FileReader(QueryFile));
|
refreshQueryCacheIfRequired(queryFile);
|
||||||
String TempContent;
|
return queryCache.get(QueryIndex);
|
||||||
while ((TempContent = Breader.readLine()) != null) {
|
}
|
||||||
if (TempContent.split(GlobalClass.ColDelim)[0].equals("Query"+QueryIndex)) {
|
|
||||||
return TempContent.replace("Query"+QueryIndex+GlobalClass.ColDelim, "");
|
private static void refreshQueryCacheIfRequired(File queryFile) throws IOException {
|
||||||
|
String absolutePath = queryFile.getAbsolutePath();
|
||||||
|
long lastModified = queryFile.lastModified();
|
||||||
|
if (absolutePath.equals(queryCachePath) && lastModified == queryCacheLastModified) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (QUERY_CACHE_LOCK) {
|
||||||
|
if (absolutePath.equals(queryCachePath) && lastModified == queryCacheLastModified) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<Integer, String> loadedQueries = new HashMap<>();
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(queryFile))) {
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
int delimiterIndex = line.indexOf(GlobalClass.ColDelim);
|
||||||
|
if (delimiterIndex <= 5 || !line.startsWith("Query")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int queryIndex = Integer.parseInt(line.substring(5, delimiterIndex));
|
||||||
|
loadedQueries.put(queryIndex, line.substring(delimiterIndex + GlobalClass.ColDelim.length()));
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
// Ignore malformed/non-query lines, matching the legacy lookup behavior.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Breader.close();
|
}
|
||||||
return TempContent;
|
queryCache = Collections.unmodifiableMap(loadedQueries);
|
||||||
|
queryCachePath = absolutePath;
|
||||||
|
queryCacheLastModified = lastModified;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/test/java/matrix/nimble/FileFunctionsQueryCacheTest.java
Normal file
20
src/test/java/matrix/nimble/FileFunctionsQueryCacheTest.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package matrix.nimble;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import matrix.nimble.utilities.FileFunctions;
|
||||||
|
|
||||||
|
class FileFunctionsQueryCacheTest {
|
||||||
|
@Test
|
||||||
|
void loadsQueriesFromNimbleQueryFileAndHandlesMissingCodes() throws Exception {
|
||||||
|
FileFunctions files = new FileFunctions("TEST");
|
||||||
|
|
||||||
|
String query = files.GetQuery(1);
|
||||||
|
|
||||||
|
assertTrue(query.startsWith("select!C0L!select u.user_id"));
|
||||||
|
assertNull(files.GetQuery(Integer.MAX_VALUE));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user