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}