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}