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