View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /*
6    * Copyright 2001, 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.impl.xs;
22  
23  import java.util.Enumeration;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Vector;
27  
28  /**
29   * A class used to hold the internal schema grammar set for the current instance
30   *
31   * @xerces.internal
32   *
33   * @author Sandy Gao, IBM
34   * @version $Id: XSGrammarBucket.java,v 1.7 2010-11-01 04:39:55 joehw Exp $
35   */
36  public class XSGrammarBucket {
37  
38      // Data
39  
40      /**
41       * Hashtable that maps between Namespace and a Grammar
42       */
43      Map<String, SchemaGrammar> fGrammarRegistry = new HashMap();
44      SchemaGrammar fNoNSGrammar = null;
45  
46      /**
47       * Get the schema grammar for the specified namespace
48       *
49       * @param namespace
50       * @return SchemaGrammar associated with the namespace
51       */
52      public SchemaGrammar getGrammar(String namespace) {
53          if (namespace == null)
54              return fNoNSGrammar;
55          return (SchemaGrammar)fGrammarRegistry.get(namespace);
56      }
57  
58      /**
59       * Put a schema grammar into the registry
60       * This method is for internal use only: it assumes that a grammar with
61       * the same target namespace is not already in the bucket.
62       *
63       * @param grammar   the grammar to put in the registry
64       */
65      public void putGrammar(SchemaGrammar grammar) {
66          if (grammar.getTargetNamespace() == null)
67              fNoNSGrammar = grammar;
68          else
69              fGrammarRegistry.put(grammar.getTargetNamespace(), grammar);
70      }
71  
72      /**
73       * put a schema grammar and any grammars imported by it (directly or
74       * inderectly) into the registry. when a grammar with the same target
75       * namespace is already in the bucket, and different from the one being
76       * added, it's an error, and no grammar will be added into the bucket.
77       *
78       * @param grammar   the grammar to put in the registry
79       * @param deep      whether to add imported grammars
80       * @return          whether the process succeeded
81       */
82      public boolean putGrammar(SchemaGrammar grammar, boolean deep) {
83          // whether there is one with the same tns
84          SchemaGrammar sg = getGrammar(grammar.fTargetNamespace);
85          if (sg != null) {
86              // if the one we have is different from the one passed, it's an error
87              return sg == grammar;
88          }
89          // not deep import, then just add this one grammar
90          if (!deep) {
91              putGrammar(grammar);
92              return true;
93          }
94  
95          // get all imported grammars, and make a copy of the Vector, so that
96          // we can recursively process the grammars, and add distinct ones
97          // to the same vector
98          Vector currGrammars = (Vector)grammar.getImportedGrammars();
99          if (currGrammars == null) {
100             putGrammar(grammar);
101             return true;
102         }
103 
104         Vector grammars = ((Vector)currGrammars.clone());
105         SchemaGrammar sg1, sg2;
106         Vector gs;
107         // for all (recursively) imported grammars
108         for (int i = 0; i < grammars.size(); i++) {
109             // get the grammar
110             sg1 = (SchemaGrammar)grammars.elementAt(i);
111             // check whether the bucket has one with the same tns
112             sg2 = getGrammar(sg1.fTargetNamespace);
113             if (sg2 == null) {
114                 // we need to add grammars imported by sg1 too
115                 gs = sg1.getImportedGrammars();
116                 // for all grammars imported by sg2, but not in the vector
117                 // we add them to the vector
118                 if(gs == null) continue;
119                 for (int j = gs.size() - 1; j >= 0; j--) {
120                     sg2 = (SchemaGrammar)gs.elementAt(j);
121                     if (!grammars.contains(sg2))
122                         grammars.addElement(sg2);
123                 }
124             }
125             // we found one with the same target namespace
126             // if the two grammars are not the same object, then it's an error
127             else if (sg2 != sg1) {
128                 return false;
129             }
130         }
131 
132         // now we have all imported grammars stored in the vector. add them
133         putGrammar(grammar);
134         for (int i = grammars.size() - 1; i >= 0; i--)
135             putGrammar((SchemaGrammar)grammars.elementAt(i));
136 
137         return true;
138     }
139 
140     /**
141      * put a schema grammar and any grammars imported by it (directly or
142      * inderectly) into the registry. when a grammar with the same target
143      * namespace is already in the bucket, and different from the one being
144      * added, no grammar will be added into the bucket.
145      *
146      * @param grammar        the grammar to put in the registry
147      * @param deep           whether to add imported grammars
148      * @param ignoreConflict whether to ignore grammars that already exist in the grammar
149      *                       bucket or not - including 'grammar' parameter.
150      * @return               whether the process succeeded
151      */
152     public boolean putGrammar(SchemaGrammar grammar, boolean deep, boolean ignoreConflict) {
153         if (!ignoreConflict) {
154             return putGrammar(grammar, deep);
155         }
156 
157         // if grammar already exist in the bucket, we ignore the request
158         SchemaGrammar sg = getGrammar(grammar.fTargetNamespace);
159         if (sg == null) {
160             putGrammar(grammar);
161         }
162 
163         // not adding the imported grammars
164         if (!deep) {
165             return true;
166         }
167 
168         // get all imported grammars, and make a copy of the Vector, so that
169         // we can recursively process the grammars, and add distinct ones
170         // to the same vector
171         Vector currGrammars = (Vector)grammar.getImportedGrammars();
172         if (currGrammars == null) {
173             return true;
174         }
175 
176         Vector grammars = ((Vector)currGrammars.clone());
177         SchemaGrammar sg1, sg2;
178         Vector gs;
179         // for all (recursively) imported grammars
180         for (int i = 0; i < grammars.size(); i++) {
181             // get the grammar
182             sg1 = (SchemaGrammar)grammars.elementAt(i);
183             // check whether the bucket has one with the same tns
184             sg2 = getGrammar(sg1.fTargetNamespace);
185             if (sg2 == null) {
186                 // we need to add grammars imported by sg1 too
187                 gs = sg1.getImportedGrammars();
188                 // for all grammars imported by sg2, but not in the vector
189                 // we add them to the vector
190                 if(gs == null) continue;
191                 for (int j = gs.size() - 1; j >= 0; j--) {
192                     sg2 = (SchemaGrammar)gs.elementAt(j);
193                     if (!grammars.contains(sg2))
194                         grammars.addElement(sg2);
195                 }
196             }
197             // we found one with the same target namespace, ignore it
198             else  {
199                 grammars.remove(sg1);
200             }
201         }
202 
203         // now we have all imported grammars stored in the vector. add them
204         for (int i = grammars.size() - 1; i >= 0; i--) {
205             putGrammar((SchemaGrammar)grammars.elementAt(i));
206         }
207 
208         return true;
209     }
210 
211     /**
212      * get all grammars in the registry
213      *
214      * @return an array of SchemaGrammars.
215      */
216     public SchemaGrammar[] getGrammars() {
217         // get the number of grammars
218         int count = fGrammarRegistry.size() + (fNoNSGrammar==null ? 0 : 1);
219         SchemaGrammar[] grammars = new SchemaGrammar[count];
220         // get grammars with target namespace
221         int i = 0;
222         for(Map.Entry<String, SchemaGrammar> entry : fGrammarRegistry.entrySet()){
223             grammars[i++] = entry.getValue();
224         }
225 
226         // add the grammar without target namespace, if any
227         if (fNoNSGrammar != null)
228             grammars[count-1] = fNoNSGrammar;
229         return grammars;
230     }
231 
232     /**
233      * Clear the registry.
234      * REVISIT: update to use another XSGrammarBucket
235      */
236     public void reset() {
237         fNoNSGrammar = null;
238         fGrammarRegistry.clear();
239     }
240 
241 } // class XSGrammarBucket