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