001package gudusoft.gsqlparser; 002 003import java.util.concurrent.ConcurrentHashMap; 004 005/** 006 * Factory class for managing parser pool instances. 007 * Provides singleton access to parser pools and configuration options. 008 */ 009public class TParserPoolFactory { 010 011 // Global shared pool instance 012 private static volatile TParserPool sharedPool; 013 014 // Named pool instances for specific use cases 015 private static final ConcurrentHashMap<String, TParserPool> namedPools = new ConcurrentHashMap<>(); 016 017 // Configuration 018 private static int defaultPoolSize = Runtime.getRuntime().availableProcessors() * 2; 019 020 /** 021 * Private constructor to prevent instantiation 022 */ 023 private TParserPoolFactory() { 024 } 025 026 /** 027 * Gets the shared global parser pool instance. 028 * Creates it lazily with double-checked locking. 029 * 030 * @return Shared parser pool instance 031 */ 032 public static TParserPool getSharedPool() { 033 if (sharedPool == null) { 034 synchronized (TParserPoolFactory.class) { 035 if (sharedPool == null) { 036 sharedPool = new TParserPool(defaultPoolSize); 037 } 038 } 039 } 040 return sharedPool; 041 } 042 043 /** 044 * Creates or gets a named parser pool. 045 * Useful for isolating pools for different components or use cases. 046 * 047 * @param name Pool name 048 * @param poolSize Size of the pool 049 * @return Named parser pool instance 050 */ 051 public static TParserPool getNamedPool(String name, int poolSize) { 052 return namedPools.computeIfAbsent(name, k -> new TParserPool(poolSize)); 053 } 054 055 /** 056 * Gets a named parser pool with default size. 057 * 058 * @param name Pool name 059 * @return Named parser pool instance 060 */ 061 public static TParserPool getNamedPool(String name) { 062 return getNamedPool(name, defaultPoolSize); 063 } 064 065 /** 066 * Sets the default pool size for new pools. 067 * 068 * @param size Default pool size 069 */ 070 public static void setDefaultPoolSize(int size) { 071 if (size > 0) { 072 defaultPoolSize = size; 073 } 074 } 075 076 /** 077 * Resets the shared pool instance. 078 * The old pool is shut down and a new one will be created on next access. 079 */ 080 public static synchronized void resetSharedPool() { 081 if (sharedPool != null) { 082 sharedPool.shutdown(); 083 sharedPool = null; 084 } 085 } 086 087 /** 088 * Removes and shuts down a named pool. 089 * 090 * @param name Pool name 091 */ 092 public static void removeNamedPool(String name) { 093 TParserPool pool = namedPools.remove(name); 094 if (pool != null) { 095 pool.shutdown(); 096 } 097 } 098 099 /** 100 * Shuts down all pools. 101 */ 102 public static void shutdownAll() { 103 resetSharedPool(); 104 namedPools.values().forEach(TParserPool::shutdown); 105 namedPools.clear(); 106 } 107 108 /** 109 * Convenience method to parse SQL using the shared pool. 110 * This is a drop-in replacement for direct TGSqlParser usage. 111 * 112 * @param vendor Database vendor 113 * @param sqlText SQL text to parse 114 * @return Parse result (0 for success, non-zero for errors) 115 */ 116 public static int parseSQL(EDbVendor vendor, String sqlText) { 117 TGSqlParser parser = null; 118 try { 119 parser = getSharedPool().borrowParser(vendor); 120 parser.sqltext = sqlText; 121 return parser.parse(); 122 } catch (Exception e) { 123 return -1; 124 } finally { 125 if (parser != null) { 126 getSharedPool().returnParser(vendor, parser); 127 } 128 } 129 } 130 131 /** 132 * Convenience method to tokenize SQL using the shared pool. 133 * 134 * @param vendor Database vendor 135 * @param sqlText SQL text to tokenize 136 * @return 0 for success, -1 for error 137 */ 138 public static int tokenizeSQL(EDbVendor vendor, String sqlText) { 139 TGSqlParser parser = null; 140 try { 141 parser = getSharedPool().borrowParser(vendor); 142 parser.sqltext = sqlText; 143 parser.tokenizeSqltext(); 144 // tokenizeSqltext() returns void; failures (e.g., the trial size 145 // gate) are reported via the parser's error message. 146 if (parser.getErrormessage() != null && !parser.getErrormessage().isEmpty()) { 147 return -1; 148 } 149 return 0; // Success 150 } catch (Exception e) { 151 return -1; 152 } finally { 153 if (parser != null) { 154 getSharedPool().returnParser(vendor, parser); 155 } 156 } 157 } 158 159 /** 160 * Gets statistics for all pools. 161 * 162 * @return String representation of all pool statistics 163 */ 164 public static String getAllStatistics() { 165 StringBuilder sb = new StringBuilder(); 166 sb.append("=== Parser Pool Statistics ===\n"); 167 168 if (sharedPool != null) { 169 sb.append("\nShared Pool:\n"); 170 for (EDbVendor vendor : EDbVendor.values()) { 171 TParserPool.PoolStatistics stats = sharedPool.getStatistics(vendor); 172 if (stats.totalParsers > 0) { 173 sb.append(" ").append(vendor).append(": ").append(stats).append("\n"); 174 } 175 } 176 } 177 178 if (!namedPools.isEmpty()) { 179 sb.append("\nNamed Pools:\n"); 180 namedPools.forEach((name, pool) -> { 181 sb.append(" Pool '").append(name).append("':\n"); 182 for (EDbVendor vendor : EDbVendor.values()) { 183 TParserPool.PoolStatistics stats = pool.getStatistics(vendor); 184 if (stats.totalParsers > 0) { 185 sb.append(" ").append(vendor).append(": ").append(stats).append("\n"); 186 } 187 } 188 }); 189 } 190 191 return sb.toString(); 192 } 193}