using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Data.OracleClient; using System.IO; using System.Runtime.CompilerServices; using System.Threading; using System.Web; using System.Xml; using Amib.Threading; using CCSTrace.CCS.Domain; using CCSTrace.CCS.Object; using NLog; namespace CCSTrace.CCS { public class CcsMain { private const string DbConfigFilename = "DBConfig.xml"; private static Logger _logger = LogManager.GetCurrentClassLogger(); private static CcsMain _instance; public static ArrayList ProcessCases = new ArrayList(); public static Queue ProcessCaseQueue = new Queue(); public static Hashtable ProcessFdr = new Hashtable();//Record the processing FDR public static ArrayList WaitingCases = new ArrayList();//Record the case when the case's FDR processed by another private int _connectionCount = 1; private OracleConnection _mainConn = null; private SEventLog _mainLog = null; private SmartThreadPool _mainjobThreadPool = null; private readonly object _syncDbQueue = new object(); private readonly Queue _dbQueue = new Queue(); public CcsMain() { _mainjobThreadPool = new SmartThreadPool(); // Startup(); } public string AppDataPath { get; set; } public static CcsMain Instance() { // Uses lazy initialization. // Note: this is not thread safe. if (_instance == null) { _instance = new CcsMain(); } return _instance; } public void Startup() { _mainLog = new SEventLog(); try { ReadXml(); if (_mainConn == null) _mainConn = CreateConnection(); //MainConn = CreateMainConnection(); GlobalVariable.CcsCodelist = new CcsCodelist(_mainConn); GlobalVariable.EosCodelist = new EosCodelist(_mainConn); for (int i = 0; i < _connectionCount; i++) { lock (_syncDbQueue) _dbQueue.Enqueue(CreateConnection()); } } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); _mainLog.Error(e.Message); if (GlobalVariable.ShowError) _mainLog.Error(e.StackTrace); throw; } finally { _mainLog.Close(); } CcsRecord mRecord = GetWaitRecord(_mainConn); if (mRecord != null) { OracleConnection conn = null; lock (_syncDbQueue) conn = _dbQueue.Dequeue(); ProcessCase(mRecord, conn); } STPStartInfo stpStartInfo = new STPStartInfo(); stpStartInfo.IdleTimeout = GlobalVariable.IdleTimeout * 1000; stpStartInfo.MaxWorkerThreads = GlobalVariable.MaxThreadSize; stpStartInfo.MinWorkerThreads = GlobalVariable.MinThreadSize; _mainjobThreadPool = new SmartThreadPool(stpStartInfo); } public void Shutdown() { _mainjobThreadPool.Shutdown(true, 1000); _mainjobThreadPool.Dispose(); _mainjobThreadPool = null; GC.Collect(); GC.WaitForPendingFinalizers(); } public void AcceptEvent(CcsRecord record) { int i = 0; int reConnectCount = 1; while (i <= reConnectCount) { try { if (InsertEventRecord(record, _mainConn)) { if (_dbQueue.Count > 0) { //將EVETNQUERY的案件狀態改為開始處理 CcsRecord mRecord = GetWaitRecord(_mainConn); if (mRecord != null) { OracleConnection conn = _dbQueue.Dequeue(); ProcessCase(mRecord, conn); } } break; } } catch (Exception) { if (_mainConn.State == ConnectionState.Closed) { i++; if (i > reConnectCount) throw; } else throw; } } } private void ReadXml() { XmlReader reader = null; try { string file = Path.Combine(AppDataPath, DbConfigFilename); // 建立 XML 讀取器 XmlReaderSettings settings = new XmlReaderSettings(); settings.IgnoreComments = true; // 不處理註解 settings.IgnoreWhitespace = true; // 跳過空白 settings.ValidationType = ValidationType.None; // 不驗證任何資料 reader = XmlReader.Create(file, settings); // 進入讀取主要部分 while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: string localName = reader.LocalName; // 取得標籤名稱 // Step 3: 讀取 FileInfo 標籤的屬性 if (localName.Equals("DBSetting")) { GlobalVariable.ConnectionString = $"Data source={reader["DataSource"]};User Id={reader["UserId"]};Password={reader["Password"]};"; GlobalVariable.TraceConnectionString = $"{reader["UserId"]}/{reader["Password"]}@{reader["DataSource"]}"; string token = reader["ConnectionCount"]; if (token != null) { GlobalVariable.MaxConnectionCount = int.Parse(token); } token = reader["ShowError"]; if (token != null) { GlobalVariable.ShowError = bool.Parse(token); } } else if (localName.Equals("ThreadSetting")) { string token = reader["maxThreadSize"]; if (token != null) { GlobalVariable.MaxThreadSize = int.Parse(token); } token = reader["minThreadSize"]; if (token != null) { GlobalVariable.MinThreadSize = int.Parse(token); } } break; } } reader.Close(); } catch (XmlException xe) { Console.WriteLine(xe.StackTrace); reader?.Close(); } } private OracleConnection CreateConnection() { OracleConnection dbConn = new OracleConnection(GlobalVariable.ConnectionString); dbConn.Open(); return dbConn; } [MethodImpl(MethodImplOptions.Synchronized)] private bool InsertEventRecord(CcsRecord record, OracleConnection conn) { OracleTransaction transaction = null; try { _mainLog = new SEventLog(); if (conn.State.ToString().Equals("Closed")) conn.Open(); transaction = conn.BeginTransaction(); if (record.InsertDb(conn, transaction, _mainLog)) { var eventQuery = new EventQuery { CcsId = record.CcsId, Meter = record.Meter, CaseStatus = (int) CCSCaseState.EventInitial, ChangeTime = record.AcceptTime }; if (eventQuery.Insert(_mainLog, conn, transaction)) transaction.Commit(); else { if (transaction.Connection.State.ToString().Equals("Open")) transaction.Rollback(); throw new Exception("案件未受理成功。"); } } else { if (transaction.Connection.State.ToString().Equals("Open")) transaction.Rollback(); throw new Exception("案件未受理成功。"); } } catch (OracleException e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); _mainLog.Error(e.Message); if (GlobalVariable.ShowError) _mainLog.Error(e.StackTrace); if (transaction != null && transaction.Connection.State.ToString().Equals("Open")) transaction.Rollback(); throw; } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); _mainLog.Error(ex.Message); if (GlobalVariable.ShowError) _mainLog.Error(ex.StackTrace); if (transaction != null && transaction.Connection.State.ToString().Equals("Open")) transaction.Rollback(); throw; } finally { _mainLog.Close(); } return true; } private delegate void WorkerThreadHandler(); private void ProcessCase(CcsRecord record, OracleConnection conn) { try { if (conn.State.ToString().Equals("Closed")) conn.Open(); ProcessEvent processEvent = new ProcessEvent(record, conn, GlobalVariable.TraceConnectionString); processEvent.ThreadFinish += ThreadEndEventProcess; ThreadStart threadStart = processEvent.Run; Thread thread = new Thread(threadStart); thread.Start(); } catch { lock (_syncDbQueue) _dbQueue.Enqueue(conn); } } private void ThreadEndEventProcess(object sender, ThreadEndEvent e) { //將EVETNQUERY的案件狀態改為開始處理 CcsRecord mRecord = GetWaitRecord(e.GetConnection()); try { if (mRecord != null) ProcessCase(mRecord, e.GetConnection()); } finally { lock (_syncDbQueue) _dbQueue.Enqueue(e.GetConnection()); } } [MethodImpl(MethodImplOptions.Synchronized)] private CcsRecord GetWaitRecord(OracleConnection conn) { string processCcsid = ""; string ccsid = ""; CcsRecord record = null; foreach (string[] obj in WaitingCases) { string ccsId = obj[0]; string fdrid = obj[1]; if (ProcessFdr.ContainsKey(fdrid)) //該條饋線仍有案件在處理中 processCcsid = processCcsid + "'" + ccsid + "',"; else { ccsid = ccsId; WaitingCases.Remove(obj); break; } } if (ccsid.Length == 0) //沒有因同饋線而在等候中的案件 { string sqlStmt = "SELECT Q.CCSID AS CCSID FROM CCS.EVENTQUERY Q,CCS.EVENTRECORD R WHERE Q.CASESTATUS IN (" + (int) CCSCaseState.EventInitial + "," + (int) CCSCaseState.EventProcess + ")"; IEnumerator Enum = ProcessCases.GetEnumerator(); while (Enum.MoveNext()) if (Enum.Current != null) processCcsid = processCcsid + "'" + Enum.Current + "',"; if (processCcsid.Length != 0) sqlStmt = sqlStmt + " AND Q.CCSID NOT IN (" + processCcsid.Substring(0, processCcsid.Length - 1) + ")"; sqlStmt = sqlStmt + " AND Q.CCSID = R.CCSID AND ROWNUM < 2 ORDER BY Q.ChangeTime"; OracleCommand command = new OracleCommand(sqlStmt, conn); OracleDataReader reader = command.ExecuteReader(); try { if (reader.Read()) ccsid = reader["CCSID"].ToString(); } catch (Exception e) { Log(e.Message); _mainLog.Error("無法取得等候處理CCS案件資料。錯誤訊息 = " + e.Message); if (GlobalVariable.ShowError) _mainLog.Error(e.StackTrace); } finally { reader.Close(); command.Dispose(); } } if (ccsid.Length != 0) record = new CcsRecord(ccsid, conn, _mainLog); if (record != null) { EventQuery eventQuery = new EventQuery(); //先將EVETNQUERY的案件狀態改為開始處理 eventQuery.CcsId = record.CcsId; eventQuery.CaseStatus = (int) CCSCaseState.EventProcess; OracleTransaction transaction = conn.BeginTransaction(); try { if (eventQuery.UpdateCaseStatus(_mainLog, conn, transaction)) { _mainLog.Info("更新EVENTQUERY的案件狀態為處理中.(CCSID = " + record.CcsId + ")"); transaction.Commit(); ProcessCases.Add(record.CcsId); } else { _mainLog.Error("無法更新EVENTQUERY的案件狀態.(CCSID = " + record.CcsId + ")"); if (transaction.Connection.State.ToString().Equals("Open")) transaction.Rollback(); } } catch (Exception e) { if (transaction.Connection.State.ToString().Equals("Open")) transaction.Rollback(); Log(e.Message); record = null; } } return record; } private void Log(string message) { RecordLog pLog = null; try { pLog = new RecordLog(GlobalVariable.CcsListPath + "MAIN.txt"); pLog.Error(message); } finally { if (pLog != null) { pLog.Close(); } } } } }