1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 package com.sun.org.apache.xerces.internal.parsers;
23 
24 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar;
25 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
26 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
27 import com.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl;
28 
29 import com.sun.org.apache.xerces.internal.util.ShadowedSymbolTable;
30 import com.sun.org.apache.xerces.internal.util.SymbolTable;
31 import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
32 
33 /**
34  * A parser pool that enables caching of grammars. The caching parser
35  * pool is constructed with a specific symbol table and grammar pool
36  * that has already been populated with the grammars used by the
37  * application.
38  * <p>
39  * Once the caching parser pool is constructed, specific parser
40  * instances are created by calling the appropriate factory method
41  * on the parser pool.
42  * <p>
43  * <strong>Note:</strong> There is a performance penalty for using
44  * a caching parser pool due to thread safety. Access to the symbol
45  * table and grammar pool must be synchronized to ensure the safe
46  * operation of the symbol table and grammar pool.
47  * <p>
48  * <strong>Note:</strong> If performance is critical, then another
49  * mechanism needs to be used instead of the caching parser pool.
50  * One approach would be to create parser instances that do not
51  * share these structures. Instead, each instance would get its
52  * own copy to use while parsing. This avoids the synchronization
53  * overhead at the expense of more memory and the time required
54  * to copy the structures for each new parser instance. And even
55  * when a parser instance is re-used, there is a potential for a
56  * memory leak due to new symbols being added to the symbol table
57  * over time. In other words, always take caution to make sure
58  * that your application is thread-safe and avoids leaking memory.
59  *
60  * @author Andy Clark, IBM
61  *
62  */
63 public class CachingParserPool {
64 
65     //
66     // Constants
67     //
68 
69     /** Default shadow symbol table (false). */
70     public static final boolean DEFAULT_SHADOW_SYMBOL_TABLE = false;
71 
72     /** Default shadow grammar pool (false). */
73     public static final boolean DEFAULT_SHADOW_GRAMMAR_POOL = false;
74 
75     //
76     // Data
77     //
78 
79     /**
80      * Symbol table. The symbol table that the caching parser pool is
81      * constructed with is automatically wrapped in a synchronized
82      * version for thread-safety.
83      */
84     protected SymbolTable fSynchronizedSymbolTable;
85 
86     /**
87      * Grammar pool. The grammar pool that the caching parser pool is
88      * constructed with is automatically wrapped in a synchronized
89      * version for thread-safety.
90      */
91     protected XMLGrammarPool fSynchronizedGrammarPool;
92 
93     /**
94      * Shadow the symbol table for new parser instances. If true,
95      * new parser instances use shadow copies of the main symbol
96      * table and are not allowed to add new symbols to the main
97      * symbol table. New symbols are added to the shadow symbol
98      * table and are local to the parser instance.
99      */
100     protected boolean fShadowSymbolTable = DEFAULT_SHADOW_SYMBOL_TABLE;
101 
102     /**
103      * Shadow the grammar pool for new parser instances. If true,
104      * new parser instances use shadow copies of the main grammar
105      * pool and are not allowed to add new grammars to the main
106      * grammar pool. New grammars are added to the shadow grammar
107      * pool and are local to the parser instance.
108      */
109     protected boolean fShadowGrammarPool = DEFAULT_SHADOW_GRAMMAR_POOL;
110 
111     //
112     // Constructors
113     //
114 
115     /** Default constructor. */
CachingParserPool()116     public CachingParserPool() {
117         this(new SymbolTable(), new XMLGrammarPoolImpl());
118     } // <init>()
119 
120     /**
121      * Constructs a caching parser pool with the specified symbol table
122      * and grammar pool.
123      *
124      * @param symbolTable The symbol table.
125      * @param grammarPool The grammar pool.
126      */
CachingParserPool(SymbolTable symbolTable, XMLGrammarPool grammarPool)127     public CachingParserPool(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
128         fSynchronizedSymbolTable = new SynchronizedSymbolTable(symbolTable);
129         fSynchronizedGrammarPool = new SynchronizedGrammarPool(grammarPool);
130     } // <init>(SymbolTable,XMLGrammarPool)
131 
132     //
133     // Public methods
134     //
135 
136     /** Returns the symbol table. */
getSymbolTable()137     public SymbolTable getSymbolTable() {
138         return fSynchronizedSymbolTable;
139     } // getSymbolTable():SymbolTable
140 
141     /** Returns the grammar pool. */
getXMLGrammarPool()142     public XMLGrammarPool getXMLGrammarPool() {
143         return fSynchronizedGrammarPool;
144     } // getXMLGrammarPool():XMLGrammarPool
145 
146     // setters and getters
147 
148     /**
149      * Sets whether new parser instance receive shadow copies of the
150      * main symbol table.
151      *
152      * @param shadow If true, new parser instances use shadow copies
153      *               of the main symbol table and are not allowed to
154      *               add new symbols to the main symbol table. New
155      *               symbols are added to the shadow symbol table and
156      *               are local to the parser instance. If false, new
157      *               parser instances are allowed to add new symbols
158      *               to the main symbol table.
159      */
setShadowSymbolTable(boolean shadow)160     public void setShadowSymbolTable(boolean shadow) {
161         fShadowSymbolTable = shadow;
162     } // setShadowSymbolTable(boolean)
163 
164     // factory methods
165 
166     /** Creates a new DOM parser. */
createDOMParser()167     public DOMParser createDOMParser() {
168         SymbolTable symbolTable = fShadowSymbolTable
169                                 ? new ShadowedSymbolTable(fSynchronizedSymbolTable)
170                                 : fSynchronizedSymbolTable;
171         XMLGrammarPool grammarPool = fShadowGrammarPool
172                                 ? new ShadowedGrammarPool(fSynchronizedGrammarPool)
173                                 : fSynchronizedGrammarPool;
174         return new DOMParser(symbolTable, grammarPool);
175     } // createDOMParser():DOMParser
176 
177     /** Creates a new SAX parser. */
createSAXParser()178     public SAXParser createSAXParser() {
179         SymbolTable symbolTable = fShadowSymbolTable
180                                 ? new ShadowedSymbolTable(fSynchronizedSymbolTable)
181                                 : fSynchronizedSymbolTable;
182         XMLGrammarPool grammarPool = fShadowGrammarPool
183                                 ? new ShadowedGrammarPool(fSynchronizedGrammarPool)
184                                 : fSynchronizedGrammarPool;
185         return new SAXParser(symbolTable, grammarPool);
186     } // createSAXParser():SAXParser
187 
188     //
189     // Classes
190     //
191 
192     /**
193      * Synchronized grammar pool.
194      *
195      * @author Andy Clark, IBM
196      */
197     public static final class SynchronizedGrammarPool
198         implements XMLGrammarPool {
199 
200         //
201         // Data
202         //
203 
204         /** Main grammar pool. */
205         private XMLGrammarPool fGrammarPool;
206 
207         //
208         // Constructors
209         //
210 
211         /** Constructs a synchronized grammar pool. */
SynchronizedGrammarPool(XMLGrammarPool grammarPool)212         public SynchronizedGrammarPool(XMLGrammarPool grammarPool) {
213             fGrammarPool = grammarPool;
214         } // <init>(XMLGrammarPool)
215 
216         //
217         // GrammarPool methods
218         //
219 
220         // retrieve the initial set of grammars for the validator
221         // to work with.
222         // REVISIT:  does this need to be synchronized since it's just reading?
223         // @param grammarType type of the grammars to be retrieved.
224         // @return the initial grammar set the validator may place in its "bucket"
retrieveInitialGrammarSet(String grammarType )225         public Grammar [] retrieveInitialGrammarSet(String grammarType ) {
226             synchronized (fGrammarPool) {
227                 return fGrammarPool.retrieveInitialGrammarSet(grammarType);
228             }
229         } // retrieveInitialGrammarSet(String):  Grammar[]
230 
231         // retrieve a particular grammar.
232         // REVISIT:  does this need to be synchronized since it's just reading?
233         // @param gDesc description of the grammar to be retrieved
234         // @return Grammar corresponding to gDesc, or null if none exists.
retrieveGrammar(XMLGrammarDescription gDesc)235         public Grammar retrieveGrammar(XMLGrammarDescription gDesc) {
236             synchronized (fGrammarPool) {
237                 return fGrammarPool.retrieveGrammar(gDesc);
238             }
239         } // retrieveGrammar(XMLGrammarDesc):  Grammar
240 
241         // give the grammarPool the option of caching these grammars.
242         // This certainly must be synchronized.
243         // @param grammarType The type of the grammars to be cached.
244         // @param grammars the Grammars that may be cached (unordered, Grammars previously
245         //  given to the validator may be included).
cacheGrammars(String grammarType, Grammar[] grammars)246         public void cacheGrammars(String grammarType, Grammar[] grammars) {
247             synchronized (fGrammarPool) {
248                 fGrammarPool.cacheGrammars(grammarType, grammars);
249             }
250         } // cacheGrammars(String, Grammar[]);
251 
252         /** lock the grammar pool */
lockPool()253         public void lockPool() {
254             synchronized (fGrammarPool) {
255                 fGrammarPool.lockPool();
256             }
257         } // lockPool()
258 
259         /** clear the grammar pool */
clear()260         public void clear() {
261             synchronized (fGrammarPool) {
262                 fGrammarPool.clear();
263             }
264         } // lockPool()
265 
266         /** unlock the grammar pool */
unlockPool()267         public void unlockPool() {
268             synchronized (fGrammarPool) {
269                 fGrammarPool.unlockPool();
270             }
271         } // unlockPool()
272 
273         /***
274          * Methods corresponding to original (pre Xerces2.0.0final)
275          * grammarPool have been commented out.
276          */
277         /**
278          * Puts the specified grammar into the grammar pool.
279          *
280          * @param key Key to associate with grammar.
281          * @param grammar Grammar object.
282          */
283         /******
284         public void putGrammar(String key, Grammar grammar) {
285             synchronized (fGrammarPool) {
286                 fGrammarPool.putGrammar(key, grammar);
287             }
288         } // putGrammar(String,Grammar)
289         *******/
290 
291         /**
292          * Returns the grammar associated to the specified key.
293          *
294          * @param key The key of the grammar.
295          */
296         /**********
297         public Grammar getGrammar(String key) {
298             synchronized (fGrammarPool) {
299                 return fGrammarPool.getGrammar(key);
300             }
301         } // getGrammar(String):Grammar
302         ***********/
303 
304         /**
305          * Removes the grammar associated to the specified key from the
306          * grammar pool and returns the removed grammar.
307          *
308          * @param key The key of the grammar.
309          */
310         /**********
311         public Grammar removeGrammar(String key) {
312             synchronized (fGrammarPool) {
313                 return fGrammarPool.removeGrammar(key);
314             }
315         } // removeGrammar(String):Grammar
316         ******/
317 
318         /**
319          * Returns true if the grammar pool contains a grammar associated
320          * to the specified key.
321          *
322          * @param key The key of the grammar.
323          */
324         /**********
325         public boolean containsGrammar(String key) {
326             synchronized (fGrammarPool) {
327                 return fGrammarPool.containsGrammar(key);
328             }
329         } // containsGrammar(String):boolean
330         ********/
331 
332     } // class SynchronizedGrammarPool
333 
334     /**
335      * Shadowed grammar pool.
336      * This class is predicated on the existence of a concrete implementation;
337      * so using our own doesn't seem to bad an idea.
338      *
339      * @author Andy Clark, IBM
340      * @author Neil Graham, IBM
341      */
342     public static final class ShadowedGrammarPool
343         extends XMLGrammarPoolImpl {
344 
345         //
346         // Data
347         //
348 
349         /** Main grammar pool. */
350         private XMLGrammarPool fGrammarPool;
351 
352         //
353         // Constructors
354         //
355 
356         /** Constructs a shadowed grammar pool. */
ShadowedGrammarPool(XMLGrammarPool grammarPool)357         public ShadowedGrammarPool(XMLGrammarPool grammarPool) {
358             fGrammarPool = grammarPool;
359         } // <init>(GrammarPool)
360 
361         //
362         // GrammarPool methods
363         //
364 
365         /**
366          * Retrieve the initial set of grammars for the validator to work with.
367          * REVISIT:  does this need to be synchronized since it's just reading?
368          *
369          * @param grammarType Type of the grammars to be retrieved.
370          * @return            The initial grammar set the validator may place in its "bucket"
371          */
retrieveInitialGrammarSet(String grammarType )372         public Grammar [] retrieveInitialGrammarSet(String grammarType ) {
373             Grammar [] grammars = super.retrieveInitialGrammarSet(grammarType);
374             if (grammars != null) return grammars;
375             return fGrammarPool.retrieveInitialGrammarSet(grammarType);
376         } // retrieveInitialGrammarSet(String):  Grammar[]
377 
378         /**
379          * Retrieve a particular grammar.
380          * REVISIT:  does this need to be synchronized since it's just reading?
381          *
382          * @param gDesc Description of the grammar to be retrieved
383          * @return      Grammar corresponding to gDesc, or null if none exists.
384          */
retrieveGrammar(XMLGrammarDescription gDesc)385         public Grammar retrieveGrammar(XMLGrammarDescription gDesc) {
386             Grammar g = super.retrieveGrammar(gDesc);
387             if(g != null) return g;
388             return fGrammarPool.retrieveGrammar(gDesc);
389         } // retrieveGrammar(XMLGrammarDesc):  Grammar
390 
391         /**
392          * Give the grammarPool the option of caching these grammars.
393          * This certainly must be synchronized.
394          *
395          * @param grammarType The type of the grammars to be cached.
396          * @param grammars    The Grammars that may be cached (unordered, Grammars previously
397          *                    given to the validator may be included).
398          */
cacheGrammars(String grammarType, Grammar[] grammars)399         public void cacheGrammars(String grammarType, Grammar[] grammars) {
400            // better give both grammars a shot...
401            super.cacheGrammars(grammarType, grammars);
402            fGrammarPool.cacheGrammars(grammarType, grammars);
403         } // cacheGrammars(grammarType, Grammar[]);
404 
405         /**
406          * Returns the grammar associated to the specified description.
407          *
408          * @param desc The description of the grammar.
409          */
getGrammar(XMLGrammarDescription desc)410         public Grammar getGrammar(XMLGrammarDescription desc) {
411 
412             if (super.containsGrammar(desc)) {
413                 return super.getGrammar(desc);
414             }
415             return null;
416 
417         } // getGrammar(XMLGrammarDescription):Grammar
418 
419         /**
420          * Returns true if the grammar pool contains a grammar associated
421          * to the specified description.
422          *
423          * @param desc The description of the grammar.
424          */
containsGrammar(XMLGrammarDescription desc)425         public boolean containsGrammar(XMLGrammarDescription desc) {
426             return super.containsGrammar(desc);
427         } // containsGrammar(XMLGrammarDescription):boolean
428 
429     } // class ShadowedGrammarPool
430 
431 } // class CachingParserPool
432