001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.parsers;
019:
020: import org.apache.xerces.xni.grammars.Grammar;
021: import org.apache.xerces.xni.grammars.XMLGrammarPool;
022: import org.apache.xerces.xni.grammars.XMLGrammarDescription;
023: import org.apache.xerces.util.XMLGrammarPoolImpl;
024:
025: import org.apache.xerces.util.ShadowedSymbolTable;
026: import org.apache.xerces.util.SymbolTable;
027: import org.apache.xerces.util.SynchronizedSymbolTable;
028:
029: /**
030: * A parser pool that enables caching of grammars. The caching parser
031: * pool is constructed with a specific symbol table and grammar pool
032: * that has already been populated with the grammars used by the
033: * application.
034: * <p>
035: * Once the caching parser pool is constructed, specific parser
036: * instances are created by calling the appropriate factory method
037: * on the parser pool.
038: * <p>
039: * <strong>Note:</strong> There is a performance penalty for using
040: * a caching parser pool due to thread safety. Access to the symbol
041: * table and grammar pool must be synchronized to ensure the safe
042: * operation of the symbol table and grammar pool.
043: * <p>
044: * <strong>Note:</strong> If performance is critical, then another
045: * mechanism needs to be used instead of the caching parser pool.
046: * One approach would be to create parser instances that do not
047: * share these structures. Instead, each instance would get its
048: * own copy to use while parsing. This avoids the synchronization
049: * overhead at the expense of more memory and the time required
050: * to copy the structures for each new parser instance. And even
051: * when a parser instance is re-used, there is a potential for a
052: * memory leak due to new symbols being added to the symbol table
053: * over time. In other words, always take caution to make sure
054: * that your application is thread-safe and avoids leaking memory.
055: *
056: * @author Andy Clark, IBM
057: *
058: * @version $Id: CachingParserPool.java 447239 2006-09-18 05:08:26Z mrglavas $
059: */
060: public class CachingParserPool {
061:
062: //
063: // Constants
064: //
065:
066: /** Default shadow symbol table (false). */
067: public static final boolean DEFAULT_SHADOW_SYMBOL_TABLE = false;
068:
069: /** Default shadow grammar pool (false). */
070: public static final boolean DEFAULT_SHADOW_GRAMMAR_POOL = false;
071:
072: //
073: // Data
074: //
075:
076: /**
077: * Symbol table. The symbol table that the caching parser pool is
078: * constructed with is automatically wrapped in a synchronized
079: * version for thread-safety.
080: */
081: protected SymbolTable fSynchronizedSymbolTable;
082:
083: /**
084: * Grammar pool. The grammar pool that the caching parser pool is
085: * constructed with is automatically wrapped in a synchronized
086: * version for thread-safety.
087: */
088: protected XMLGrammarPool fSynchronizedGrammarPool;
089:
090: /**
091: * Shadow the symbol table for new parser instances. If true,
092: * new parser instances use shadow copies of the main symbol
093: * table and are not allowed to add new symbols to the main
094: * symbol table. New symbols are added to the shadow symbol
095: * table and are local to the parser instance.
096: */
097: protected boolean fShadowSymbolTable = DEFAULT_SHADOW_SYMBOL_TABLE;
098:
099: /**
100: * Shadow the grammar pool for new parser instances. If true,
101: * new parser instances use shadow copies of the main grammar
102: * pool and are not allowed to add new grammars to the main
103: * grammar pool. New grammars are added to the shadow grammar
104: * pool and are local to the parser instance.
105: */
106: protected boolean fShadowGrammarPool = DEFAULT_SHADOW_GRAMMAR_POOL;
107:
108: //
109: // Constructors
110: //
111:
112: /** Default constructor. */
113: public CachingParserPool() {
114: this (new SymbolTable(), new XMLGrammarPoolImpl());
115: } // <init>()
116:
117: /**
118: * Constructs a caching parser pool with the specified symbol table
119: * and grammar pool.
120: *
121: * @param symbolTable The symbol table.
122: * @param grammarPool The grammar pool.
123: */
124: public CachingParserPool(SymbolTable symbolTable,
125: XMLGrammarPool grammarPool) {
126: fSynchronizedSymbolTable = new SynchronizedSymbolTable(
127: symbolTable);
128: fSynchronizedGrammarPool = new SynchronizedGrammarPool(
129: grammarPool);
130: } // <init>(SymbolTable,XMLGrammarPool)
131:
132: //
133: // Public methods
134: //
135:
136: /** Returns the symbol table. */
137: public SymbolTable getSymbolTable() {
138: return fSynchronizedSymbolTable;
139: } // getSymbolTable():SymbolTable
140:
141: /** Returns the grammar pool. */
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: */
160: public void setShadowSymbolTable(boolean shadow) {
161: fShadowSymbolTable = shadow;
162: } // setShadowSymbolTable(boolean)
163:
164: // factory methods
165:
166: /** Creates a new DOM parser. */
167: public DOMParser createDOMParser() {
168: SymbolTable symbolTable = fShadowSymbolTable ? new ShadowedSymbolTable(
169: fSynchronizedSymbolTable)
170: : fSynchronizedSymbolTable;
171: XMLGrammarPool grammarPool = fShadowGrammarPool ? new ShadowedGrammarPool(
172: fSynchronizedGrammarPool)
173: : fSynchronizedGrammarPool;
174: return new DOMParser(symbolTable, grammarPool);
175: } // createDOMParser():DOMParser
176:
177: /** Creates a new SAX parser. */
178: public SAXParser createSAXParser() {
179: SymbolTable symbolTable = fShadowSymbolTable ? new ShadowedSymbolTable(
180: fSynchronizedSymbolTable)
181: : fSynchronizedSymbolTable;
182: XMLGrammarPool grammarPool = fShadowGrammarPool ? new ShadowedGrammarPool(
183: 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 implements
198: 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. */
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"
225: public Grammar[] retrieveInitialGrammarSet(String grammarType) {
226: synchronized (fGrammarPool) {
227: return fGrammarPool
228: .retrieveInitialGrammarSet(grammarType);
229: }
230: } // retrieveInitialGrammarSet(String): Grammar[]
231:
232: // retrieve a particular grammar.
233: // REVISIT: does this need to be synchronized since it's just reading?
234: // @param gDesc description of the grammar to be retrieved
235: // @return Grammar corresponding to gDesc, or null if none exists.
236: public Grammar retrieveGrammar(XMLGrammarDescription gDesc) {
237: synchronized (fGrammarPool) {
238: return fGrammarPool.retrieveGrammar(gDesc);
239: }
240: } // retrieveGrammar(XMLGrammarDesc): Grammar
241:
242: // give the grammarPool the option of caching these grammars.
243: // This certainly must be synchronized.
244: // @param grammarType The type of the grammars to be cached.
245: // @param grammars the Grammars that may be cached (unordered, Grammars previously
246: // given to the validator may be included).
247: public void cacheGrammars(String grammarType, Grammar[] grammars) {
248: synchronized (fGrammarPool) {
249: fGrammarPool.cacheGrammars(grammarType, grammars);
250: }
251: } // cacheGrammars(String, Grammar[]);
252:
253: /** lock the grammar pool */
254: public void lockPool() {
255: synchronized (fGrammarPool) {
256: fGrammarPool.lockPool();
257: }
258: } // lockPool()
259:
260: /** clear the grammar pool */
261: public void clear() {
262: synchronized (fGrammarPool) {
263: fGrammarPool.clear();
264: }
265: } // lockPool()
266:
267: /** unlock the grammar pool */
268: public void unlockPool() {
269: synchronized (fGrammarPool) {
270: fGrammarPool.unlockPool();
271: }
272: } // unlockPool()
273:
274: /***
275: * Methods corresponding to original (pre Xerces2.0.0final)
276: * grammarPool have been commented out.
277: */
278: /**
279: * Puts the specified grammar into the grammar pool.
280: *
281: * @param key Key to associate with grammar.
282: * @param grammar Grammar object.
283: */
284: /******
285: public void putGrammar(String key, Grammar grammar) {
286: synchronized (fGrammarPool) {
287: fGrammarPool.putGrammar(key, grammar);
288: }
289: } // putGrammar(String,Grammar)
290: *******/
291:
292: /**
293: * Returns the grammar associated to the specified key.
294: *
295: * @param key The key of the grammar.
296: */
297: /**********
298: public Grammar getGrammar(String key) {
299: synchronized (fGrammarPool) {
300: return fGrammarPool.getGrammar(key);
301: }
302: } // getGrammar(String):Grammar
303: ***********/
304:
305: /**
306: * Removes the grammar associated to the specified key from the
307: * grammar pool and returns the removed grammar.
308: *
309: * @param key The key of the grammar.
310: */
311: /**********
312: public Grammar removeGrammar(String key) {
313: synchronized (fGrammarPool) {
314: return fGrammarPool.removeGrammar(key);
315: }
316: } // removeGrammar(String):Grammar
317: ******/
318:
319: /**
320: * Returns true if the grammar pool contains a grammar associated
321: * to the specified key.
322: *
323: * @param key The key of the grammar.
324: */
325: /**********
326: public boolean containsGrammar(String key) {
327: synchronized (fGrammarPool) {
328: return fGrammarPool.containsGrammar(key);
329: }
330: } // containsGrammar(String):boolean
331: ********/
332:
333: } // class SynchronizedGrammarPool
334:
335: /**
336: * Shadowed grammar pool.
337: * This class is predicated on the existence of a concrete implementation;
338: * so using our own doesn't seem to bad an idea.
339: *
340: * @author Andy Clark, IBM
341: * @author Neil Graham, IBM
342: */
343: public static final class ShadowedGrammarPool extends
344: XMLGrammarPoolImpl {
345:
346: //
347: // Data
348: //
349:
350: /** Main grammar pool. */
351: private XMLGrammarPool fGrammarPool;
352:
353: //
354: // Constructors
355: //
356:
357: /** Constructs a shadowed grammar pool. */
358: public ShadowedGrammarPool(XMLGrammarPool grammarPool) {
359: fGrammarPool = grammarPool;
360: } // <init>(GrammarPool)
361:
362: //
363: // GrammarPool methods
364: //
365:
366: /**
367: * Retrieve the initial set of grammars for the validator to work with.
368: * REVISIT: does this need to be synchronized since it's just reading?
369: *
370: * @param grammarType Type of the grammars to be retrieved.
371: * @return The initial grammar set the validator may place in its "bucket"
372: */
373: public Grammar[] retrieveInitialGrammarSet(String grammarType) {
374: Grammar[] grammars = super
375: .retrieveInitialGrammarSet(grammarType);
376: if (grammars != null)
377: return grammars;
378: return fGrammarPool.retrieveInitialGrammarSet(grammarType);
379: } // retrieveInitialGrammarSet(String): Grammar[]
380:
381: /**
382: * Retrieve a particular grammar.
383: * REVISIT: does this need to be synchronized since it's just reading?
384: *
385: * @param gDesc Description of the grammar to be retrieved
386: * @return Grammar corresponding to gDesc, or null if none exists.
387: */
388: public Grammar retrieveGrammar(XMLGrammarDescription gDesc) {
389: Grammar g = super .retrieveGrammar(gDesc);
390: if (g != null)
391: return g;
392: return fGrammarPool.retrieveGrammar(gDesc);
393: } // retrieveGrammar(XMLGrammarDesc): Grammar
394:
395: /**
396: * Give the grammarPool the option of caching these grammars.
397: * This certainly must be synchronized.
398: *
399: * @param grammarType The type of the grammars to be cached.
400: * @param grammars The Grammars that may be cached (unordered, Grammars previously
401: * given to the validator may be included).
402: */
403: public void cacheGrammars(String grammarType, Grammar[] grammars) {
404: // better give both grammars a shot...
405: super .cacheGrammars(grammarType, grammars);
406: fGrammarPool.cacheGrammars(grammarType, grammars);
407: } // cacheGrammars(grammarType, Grammar[]);
408:
409: /**
410: * Returns the grammar associated to the specified description.
411: *
412: * @param desc The description of the grammar.
413: */
414: public Grammar getGrammar(XMLGrammarDescription desc) {
415:
416: if (super .containsGrammar(desc)) {
417: return super .getGrammar(desc);
418: }
419: return null;
420:
421: } // getGrammar(XMLGrammarDescription):Grammar
422:
423: /**
424: * Returns true if the grammar pool contains a grammar associated
425: * to the specified description.
426: *
427: * @param desc The description of the grammar.
428: */
429: public boolean containsGrammar(XMLGrammarDescription desc) {
430: return super .containsGrammar(desc);
431: } // containsGrammar(XMLGrammarDescription):boolean
432:
433: } // class ShadowedGrammarPool
434:
435: } // class CachingParserPool
|