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 return 0; // Success 145 } catch (Exception e) { 146 return -1; 147 } finally { 148 if (parser != null) { 149 getSharedPool().returnParser(vendor, parser); 150 } 151 } 152 } 153 154 /** 155 * Gets statistics for all pools. 156 * 157 * @return String representation of all pool statistics 158 */ 159 public static String getAllStatistics() { 160 StringBuilder sb = new StringBuilder(); 161 sb.append("=== Parser Pool Statistics ===\n"); 162 163 if (sharedPool != null) { 164 sb.append("\nShared Pool:\n"); 165 for (EDbVendor vendor : EDbVendor.values()) { 166 TParserPool.PoolStatistics stats = sharedPool.getStatistics(vendor); 167 if (stats.totalParsers > 0) { 168 sb.append(" ").append(vendor).append(": ").append(stats).append("\n"); 169 } 170 } 171 } 172 173 if (!namedPools.isEmpty()) { 174 sb.append("\nNamed Pools:\n"); 175 namedPools.forEach((name, pool) -> { 176 sb.append(" Pool '").append(name).append("':\n"); 177 for (EDbVendor vendor : EDbVendor.values()) { 178 TParserPool.PoolStatistics stats = pool.getStatistics(vendor); 179 if (stats.totalParsers > 0) { 180 sb.append(" ").append(vendor).append(": ").append(stats).append("\n"); 181 } 182 } 183 }); 184 } 185 186 return sb.toString(); 187 } 188}