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.util;
019:
020: import org.apache.xerces.xni.grammars.Grammar;
021: import org.apache.xerces.xni.grammars.XMLGrammarDescription;
022: import org.apache.xerces.xni.grammars.XMLGrammarPool;
023:
024: /**
025: * Stores grammars in a pool associated to a specific key. This grammar pool
026: * implementation stores two types of grammars: those keyed by the root element
027: * name, and those keyed by the grammar's target namespace.
028: *
029: * This is the default implementation of the GrammarPool interface.
030: * As we move forward, this will become more function-rich and robust.
031: *
032: * @author Jeffrey Rodriguez, IBM
033: * @author Andy Clark, IBM
034: * @author Neil Graham, IBM
035: * @author Pavani Mukthipudi, Sun Microsystems
036: * @author Neeraj Bajaj, SUN Microsystems
037: *
038: * @version $Id: XMLGrammarPoolImpl.java 447241 2006-09-18 05:12:57Z mrglavas $
039: */
040: public class XMLGrammarPoolImpl implements XMLGrammarPool {
041:
042: //
043: // Constants
044: //
045:
046: /** Default size. */
047: protected static final int TABLE_SIZE = 11;
048:
049: //
050: // Data
051: //
052:
053: /** Grammars. */
054: protected Entry[] fGrammars = null;
055:
056: // whether this pool is locked
057: protected boolean fPoolIsLocked;
058:
059: // the number of grammars in the pool
060: protected int fGrammarCount = 0;
061:
062: private static final boolean DEBUG = false;
063:
064: //
065: // Constructors
066: //
067:
068: /** Constructs a grammar pool with a default number of buckets. */
069: public XMLGrammarPoolImpl() {
070: fGrammars = new Entry[TABLE_SIZE];
071: fPoolIsLocked = false;
072: } // <init>()
073:
074: /** Constructs a grammar pool with a specified number of buckets. */
075: public XMLGrammarPoolImpl(int initialCapacity) {
076: fGrammars = new Entry[initialCapacity];
077: fPoolIsLocked = false;
078: }
079:
080: //
081: // XMLGrammarPool methods
082: //
083:
084: /* <p> Retrieve the initial known set of grammars. This method is
085: * called by a validator before the validation starts. The application
086: * can provide an initial set of grammars available to the current
087: * validation attempt. </p>
088: *
089: * @param grammarType The type of the grammar, from the
090: * <code>org.apache.xerces.xni.grammars.XMLGrammarDescription</code>
091: * interface.
092: * @return The set of grammars the validator may put in its "bucket"
093: */
094: public Grammar[] retrieveInitialGrammarSet(String grammarType) {
095: synchronized (fGrammars) {
096: int grammarSize = fGrammars.length;
097: Grammar[] tempGrammars = new Grammar[fGrammarCount];
098: int pos = 0;
099: for (int i = 0; i < grammarSize; i++) {
100: for (Entry e = fGrammars[i]; e != null; e = e.next) {
101: if (e.desc.getGrammarType().equals(grammarType)) {
102: tempGrammars[pos++] = e.grammar;
103: }
104: }
105: }
106: Grammar[] toReturn = new Grammar[pos];
107: System.arraycopy(tempGrammars, 0, toReturn, 0, pos);
108: return toReturn;
109: }
110: } // retrieveInitialGrammarSet (String): Grammar[]
111:
112: /* <p> Return the final set of grammars that the validator ended up
113: * with. This method is called after the validation finishes. The
114: * application may then choose to cache some of the returned grammars.</p>
115: * <p>In this implementation, we make our choice based on whether this object
116: * is "locked"--that is, whether the application has instructed
117: * us not to accept any new grammars.</p>
118: *
119: * @param grammarType The type of the grammars being returned;
120: * @param grammars An array containing the set of grammars being
121: * returned; order is not significant.
122: */
123: public void cacheGrammars(String grammarType, Grammar[] grammars) {
124: if (!fPoolIsLocked) {
125: for (int i = 0; i < grammars.length; i++) {
126: if (DEBUG) {
127: System.out.println("CACHED GRAMMAR " + (i + 1));
128: Grammar temp = grammars[i];
129: //print(temp.getGrammarDescription());
130: }
131: putGrammar(grammars[i]);
132: }
133: }
134: } // cacheGrammars(String, Grammar[]);
135:
136: /* <p> This method requests that the application retrieve a grammar
137: * corresponding to the given GrammarIdentifier from its cache.
138: * If it cannot do so it must return null; the parser will then
139: * call the EntityResolver. </p>
140: * <strong>An application must not call its EntityResolver itself
141: * from this method; this may result in infinite recursions.</strong>
142: *
143: * This implementation chooses to use the root element name to identify a DTD grammar
144: * and the target namespace to identify a Schema grammar.
145: *
146: * @param desc The description of the Grammar being requested.
147: * @return The Grammar corresponding to this description or null if
148: * no such Grammar is known.
149: */
150: public Grammar retrieveGrammar(XMLGrammarDescription desc) {
151: if (DEBUG) {
152: System.out
153: .println("RETRIEVING GRAMMAR FROM THE APPLICATION WITH FOLLOWING DESCRIPTION :");
154: //print(desc);
155: }
156: return getGrammar(desc);
157: } // retrieveGrammar(XMLGrammarDescription): Grammar
158:
159: //
160: // Public methods
161: //
162:
163: /**
164: * Puts the specified grammar into the grammar pool and associates it to
165: * its root element name or its target namespace.
166: *
167: * @param grammar The Grammar.
168: */
169: public void putGrammar(Grammar grammar) {
170: if (!fPoolIsLocked) {
171: synchronized (fGrammars) {
172: XMLGrammarDescription desc = grammar
173: .getGrammarDescription();
174: int hash = hashCode(desc);
175: int index = (hash & 0x7FFFFFFF) % fGrammars.length;
176: for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) {
177: if (entry.hash == hash && equals(entry.desc, desc)) {
178: entry.grammar = grammar;
179: return;
180: }
181: }
182: // create a new entry
183: Entry entry = new Entry(hash, desc, grammar,
184: fGrammars[index]);
185: fGrammars[index] = entry;
186: fGrammarCount++;
187: }
188: }
189: } // putGrammar(Grammar)
190:
191: /**
192: * Returns the grammar associated to the specified grammar description.
193: * Currently, the root element name is used as the key for DTD grammars
194: * and the target namespace is used as the key for Schema grammars.
195: *
196: * @param desc The Grammar Description.
197: */
198: public Grammar getGrammar(XMLGrammarDescription desc) {
199: synchronized (fGrammars) {
200: int hash = hashCode(desc);
201: int index = (hash & 0x7FFFFFFF) % fGrammars.length;
202: for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) {
203: if ((entry.hash == hash) && equals(entry.desc, desc)) {
204: return entry.grammar;
205: }
206: }
207: return null;
208: }
209: } // getGrammar(XMLGrammarDescription):Grammar
210:
211: /**
212: * Removes the grammar associated to the specified grammar description from the
213: * grammar pool and returns the removed grammar. Currently, the root element name
214: * is used as the key for DTD grammars and the target namespace is used
215: * as the key for Schema grammars.
216: *
217: * @param desc The Grammar Description.
218: * @return The removed grammar.
219: */
220: public Grammar removeGrammar(XMLGrammarDescription desc) {
221: synchronized (fGrammars) {
222: int hash = hashCode(desc);
223: int index = (hash & 0x7FFFFFFF) % fGrammars.length;
224: for (Entry entry = fGrammars[index], prev = null; entry != null; prev = entry, entry = entry.next) {
225: if ((entry.hash == hash) && equals(entry.desc, desc)) {
226: if (prev != null) {
227: prev.next = entry.next;
228: } else {
229: fGrammars[index] = entry.next;
230: }
231: Grammar tempGrammar = entry.grammar;
232: entry.grammar = null;
233: fGrammarCount--;
234: return tempGrammar;
235: }
236: }
237: return null;
238: }
239: } // removeGrammar(XMLGrammarDescription):Grammar
240:
241: /**
242: * Returns true if the grammar pool contains a grammar associated
243: * to the specified grammar description. Currently, the root element name
244: * is used as the key for DTD grammars and the target namespace is used
245: * as the key for Schema grammars.
246: *
247: * @param desc The Grammar Description.
248: */
249: public boolean containsGrammar(XMLGrammarDescription desc) {
250: synchronized (fGrammars) {
251: int hash = hashCode(desc);
252: int index = (hash & 0x7FFFFFFF) % fGrammars.length;
253: for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) {
254: if ((entry.hash == hash) && equals(entry.desc, desc)) {
255: return true;
256: }
257: }
258: return false;
259: }
260: } // containsGrammar(XMLGrammarDescription):boolean
261:
262: /* <p> Sets this grammar pool to a "locked" state--i.e.,
263: * no new grammars will be added until it is "unlocked".
264: */
265: public void lockPool() {
266: fPoolIsLocked = true;
267: } // lockPool()
268:
269: /* <p> Sets this grammar pool to an "unlocked" state--i.e.,
270: * new grammars will be added when putGrammar or cacheGrammars
271: * are called.
272: */
273: public void unlockPool() {
274: fPoolIsLocked = false;
275: } // unlockPool()
276:
277: /*
278: * <p>This method clears the pool-i.e., removes references
279: * to all the grammars in it.</p>
280: */
281: public void clear() {
282: for (int i = 0; i < fGrammars.length; i++) {
283: if (fGrammars[i] != null) {
284: fGrammars[i].clear();
285: fGrammars[i] = null;
286: }
287: }
288: fGrammarCount = 0;
289: } // clear()
290:
291: /**
292: * This method checks whether two grammars are the same. Currently, we compare
293: * the root element names for DTD grammars and the target namespaces for Schema grammars.
294: * The application can override this behaviour and add its own logic.
295: *
296: * @param desc1 The grammar description
297: * @param desc2 The grammar description of the grammar to be compared to
298: * @return True if the grammars are equal, otherwise false
299: */
300: public boolean equals(XMLGrammarDescription desc1,
301: XMLGrammarDescription desc2) {
302: return desc1.equals(desc2);
303: }
304:
305: /**
306: * Returns the hash code value for the given grammar description.
307: *
308: * @param desc The grammar description
309: * @return The hash code value
310: */
311: public int hashCode(XMLGrammarDescription desc) {
312: return desc.hashCode();
313: }
314:
315: /**
316: * This class is a grammar pool entry. Each entry acts as a node
317: * in a linked list.
318: */
319: protected static final class Entry {
320: public int hash;
321: public XMLGrammarDescription desc;
322: public Grammar grammar;
323: public Entry next;
324:
325: protected Entry(int hash, XMLGrammarDescription desc,
326: Grammar grammar, Entry next) {
327: this .hash = hash;
328: this .desc = desc;
329: this .grammar = grammar;
330: this .next = next;
331: }
332:
333: // clear this entry; useful to promote garbage collection
334: // since reduces reference count of objects to be destroyed
335: protected void clear() {
336: desc = null;
337: grammar = null;
338: if (next != null) {
339: next.clear();
340: next = null;
341: }
342: } // clear()
343: } // class Entry
344:
345: /* For DTD build we can't import here XSDDescription. Thus, this method is commented out.. */
346: /* public void print(XMLGrammarDescription description){
347: if(description.getGrammarType().equals(XMLGrammarDescription.XML_DTD)){
348:
349: }
350: else if(description.getGrammarType().equals(XMLGrammarDescription.XML_SCHEMA)){
351: XSDDescription schema = (XSDDescription)description ;
352: System.out.println("Context = " + schema.getContextType());
353: System.out.println("TargetNamespace = " + schema.getTargetNamespace());
354: String [] temp = schema.getLocationHints();
355:
356: for (int i = 0 ; (temp != null && i < temp.length) ; i++){
357: System.out.println("LocationHint " + i + " = "+ temp[i]);
358: }
359:
360: System.out.println("Triggering Component = " + schema.getTriggeringComponent());
361: System.out.println("EnclosingElementName =" + schema.getEnclosingElementName());
362:
363: }
364:
365: }//print
366: */
367:
368: } // class XMLGrammarPoolImpl
|