/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id $ */ #include #include #include #include #include #include #include XERCES_CPP_NAMESPACE_BEGIN // --------------------------------------------------------------------------- // GrammarResolver: Constructor and Destructor // --------------------------------------------------------------------------- GrammarResolver::GrammarResolver(XMLGrammarPool* const gramPool , MemoryManager* const manager) :fCacheGrammar(false) ,fUseCachedGrammar(false) ,fGrammarPoolFromExternalApplication(true) ,fStringPool(0) ,fGrammarBucket(0) ,fGrammarFromPool(0) ,fDataTypeReg(0) ,fMemoryManager(manager) ,fGrammarPool(gramPool) ,fXSModel(0) ,fGrammarPoolXSModel(0) ,fGrammarsToAddToXSModel(0) { fGrammarBucket = new (manager) RefHashTableOf(29, true, manager); /*** * Grammars in this set are not owned */ fGrammarFromPool = new (manager) RefHashTableOf(29, false, manager); if (!gramPool) { /*** * We need to instantiate a default grammar pool object so that * all grammars and grammar components could be created through * the Factory methods */ fGrammarPool = new (manager) XMLGrammarPoolImpl(manager); fGrammarPoolFromExternalApplication=false; } fStringPool = fGrammarPool->getURIStringPool(); // REVISIT: size fGrammarsToAddToXSModel = new (manager) ValueVectorOf (29, manager); } GrammarResolver::~GrammarResolver() { delete fGrammarBucket; delete fGrammarFromPool; if (fDataTypeReg) delete fDataTypeReg; /*** * delete the grammar pool iff it is created by this resolver */ if (!fGrammarPoolFromExternalApplication) delete fGrammarPool; if (fXSModel) delete fXSModel; // don't delete fGrammarPoolXSModel! we don't own it! delete fGrammarsToAddToXSModel; } // --------------------------------------------------------------------------- // GrammarResolver: Getter methods // --------------------------------------------------------------------------- DatatypeValidator* GrammarResolver::getDatatypeValidator(const XMLCh* const uriStr, const XMLCh* const localPartStr) { DatatypeValidator* dv = 0; if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) { if (!fDataTypeReg) { fDataTypeReg = new (fMemoryManager) DatatypeValidatorFactory(fMemoryManager); } dv = fDataTypeReg->getDatatypeValidator(localPartStr); } else { Grammar* grammar = getGrammar(uriStr); if (grammar && grammar->getGrammarType() == Grammar::SchemaGrammarType) { XMLBuffer nameBuf(128, fMemoryManager); nameBuf.set(uriStr); nameBuf.append(chComma); nameBuf.append(localPartStr); dv = ((SchemaGrammar*) grammar)->getDatatypeRegistry()->getDatatypeValidator(nameBuf.getRawBuffer()); } } return dv; } Grammar* GrammarResolver::getGrammar( const XMLCh* const namespaceKey) { if (!namespaceKey) return 0; Grammar* grammar = fGrammarBucket->get(namespaceKey); if (grammar) return grammar; if (fUseCachedGrammar) { grammar = fGrammarFromPool->get(namespaceKey); if (grammar) { return grammar; } else { XMLSchemaDescription* gramDesc = fGrammarPool->createSchemaDescription(namespaceKey); Janitor janName(gramDesc); grammar = fGrammarPool->retrieveGrammar(gramDesc); if (grammar) { fGrammarFromPool->put((void*) grammar->getGrammarDescription()->getGrammarKey(), grammar); } return grammar; } } return 0; } Grammar* GrammarResolver::getGrammar( XMLGrammarDescription* const gramDesc) { if (!gramDesc) return 0; Grammar* grammar = fGrammarBucket->get(gramDesc->getGrammarKey()); if (grammar) return grammar; if (fUseCachedGrammar) { grammar = fGrammarFromPool->get(gramDesc->getGrammarKey()); if (grammar) { return grammar; } else { grammar = fGrammarPool->retrieveGrammar(gramDesc); if (grammar) { fGrammarFromPool->put((void*) grammar->getGrammarDescription()->getGrammarKey(), grammar); } return grammar; } } return 0; } RefHashTableOfEnumerator GrammarResolver::getGrammarEnumerator() const { return RefHashTableOfEnumerator(fGrammarBucket, false, fMemoryManager); } RefHashTableOfEnumerator GrammarResolver::getReferencedGrammarEnumerator() const { return RefHashTableOfEnumerator(fGrammarFromPool, false, fMemoryManager); } RefHashTableOfEnumerator GrammarResolver::getCachedGrammarEnumerator() const { return fGrammarPool->getGrammarEnumerator(); } bool GrammarResolver::containsNameSpace( const XMLCh* const nameSpaceKey ) { if (!nameSpaceKey) return false; if (fGrammarBucket->containsKey(nameSpaceKey)) return true; if (fUseCachedGrammar) { if (fGrammarFromPool->containsKey(nameSpaceKey)) return true; // Lastly, need to check in fGrammarPool XMLSchemaDescription* gramDesc = fGrammarPool->createSchemaDescription(nameSpaceKey); Janitor janName(gramDesc); Grammar* grammar = fGrammarPool->retrieveGrammar(gramDesc); if (grammar) return true; } return false; } void GrammarResolver::putGrammar(Grammar* const grammarToAdopt) { if (!grammarToAdopt) return; /*** * the grammar will be either in the grammarpool, or in the grammarbucket */ if (!fCacheGrammar || !fGrammarPool->cacheGrammar(grammarToAdopt)) { // either we aren't caching or the grammar pool doesn't want it // so we need to look after it fGrammarBucket->put( (void*) grammarToAdopt->getGrammarDescription()->getGrammarKey(), grammarToAdopt ); if (grammarToAdopt->getGrammarType() == Grammar::SchemaGrammarType) { fGrammarsToAddToXSModel->addElement((SchemaGrammar*) grammarToAdopt); } } } // --------------------------------------------------------------------------- // GrammarResolver: methods // --------------------------------------------------------------------------- void GrammarResolver::reset() { fGrammarBucket->removeAll(); fGrammarsToAddToXSModel->removeAllElements(); delete fXSModel; fXSModel = 0; } void GrammarResolver::resetCachedGrammar() { //REVISIT: if the pool is locked this will fail... should throw an exception? fGrammarPool->clear(); // Even though fXSModel and fGrammarPoolXSModel will be invalid don't touch // them here as getXSModel will handle this. //to clear all other references to the grammars just deleted from fGrammarPool fGrammarFromPool->removeAll(); } void GrammarResolver::cacheGrammars() { RefHashTableOfEnumerator grammarEnum(fGrammarBucket, false, fMemoryManager); ValueVectorOf keys(8, fMemoryManager); unsigned int keyCount = 0; // Build key set while (grammarEnum.hasMoreElements()) { XMLCh* grammarKey = (XMLCh*) grammarEnum.nextElementKey(); keys.addElement(grammarKey); keyCount++; } // PSVI: assume everything will be added, if caching fails add grammar back // into vector fGrammarsToAddToXSModel->removeAllElements(); // Cache for (unsigned int i = 0; i < keyCount; i++) { XMLCh* grammarKey = keys.elementAt(i); /*** * It is up to the GrammarPool implementation to handle duplicated grammar */ Grammar* grammar = fGrammarBucket->get(grammarKey); if(fGrammarPool->cacheGrammar(grammar)) { // only orphan grammar if grammar pool accepts caching of it fGrammarBucket->orphanKey(grammarKey); } else if (grammar->getGrammarType() == Grammar::SchemaGrammarType) { // add it back to list of grammars not in grammar pool fGrammarsToAddToXSModel->addElement((SchemaGrammar*) grammar); } } } // --------------------------------------------------------------------------- // GrammarResolver: Setter methods // --------------------------------------------------------------------------- void GrammarResolver::cacheGrammarFromParse(const bool aValue) { reset(); fCacheGrammar = aValue; } Grammar* GrammarResolver::orphanGrammar(const XMLCh* const nameSpaceKey) { if (fCacheGrammar) { Grammar* grammar = fGrammarPool->orphanGrammar(nameSpaceKey); if (grammar) { if (fGrammarFromPool->containsKey(nameSpaceKey)) fGrammarFromPool->removeKey(nameSpaceKey); } // Check to see if it's in fGrammarBucket, since // we put it there if the grammar pool refused to // cache it. else if (fGrammarBucket->containsKey(nameSpaceKey)) { grammar = fGrammarBucket->orphanKey(nameSpaceKey); } return grammar; } else { return fGrammarBucket->orphanKey(nameSpaceKey); } } XSModel *GrammarResolver::getXSModel() { XSModel* xsModel; if (fCacheGrammar || fUseCachedGrammar) { // We know if the grammarpool changed thru caching, orphaning and erasing // but NOT by other mechanisms such as lockPool() or unlockPool() so it // is safest to always get it. The grammarPool XSModel will only be // regenerated if something changed. bool XSModelWasChanged; // The grammarpool will always return an xsmodel, even if it is just // the schema for schema xsmodel... xsModel = fGrammarPool->getXSModel(XSModelWasChanged); if (XSModelWasChanged) { // we know the grammarpool XSModel has changed or this is the // first call to getXSModel if (!fGrammarPoolXSModel && (fGrammarsToAddToXSModel->size() == 0) && !fXSModel) { fGrammarPoolXSModel = xsModel; return fGrammarPoolXSModel; } else { fGrammarPoolXSModel = xsModel; // We had previously augmented the grammar pool XSModel // with our our grammars or we would like to upate it now // so we have to regenerate the XSModel fGrammarsToAddToXSModel->removeAllElements(); RefHashTableOfEnumerator grammarEnum(fGrammarBucket, false, fMemoryManager); while (grammarEnum.hasMoreElements()) { Grammar& grammar = (Grammar&) grammarEnum.nextElement(); if (grammar.getGrammarType() == Grammar::SchemaGrammarType) fGrammarsToAddToXSModel->addElement((SchemaGrammar*)&grammar); } delete fXSModel; if (fGrammarsToAddToXSModel->size()) { fXSModel = new (fMemoryManager) XSModel(fGrammarPoolXSModel, this, fMemoryManager); fGrammarsToAddToXSModel->removeAllElements(); return fXSModel; } fXSModel = 0; return fGrammarPoolXSModel; } } else { // we know that the grammar pool XSModel is the same as before if (fGrammarsToAddToXSModel->size()) { // we need to update our fXSModel with the new grammars if (fXSModel) { xsModel = new (fMemoryManager) XSModel(fXSModel, this, fMemoryManager); fXSModel = xsModel; } else { fXSModel = new (fMemoryManager) XSModel(fGrammarPoolXSModel, this, fMemoryManager); } fGrammarsToAddToXSModel->removeAllElements(); return fXSModel; } // Nothing has changed! if (fXSModel) { return fXSModel; } else if (fGrammarPoolXSModel) { return fGrammarPoolXSModel; } fXSModel = new (fMemoryManager) XSModel(0, this, fMemoryManager); return fXSModel; } } // Not Caching... if (fGrammarsToAddToXSModel->size()) { xsModel = new (fMemoryManager) XSModel(fXSModel, this, fMemoryManager); fGrammarsToAddToXSModel->removeAllElements(); fXSModel = xsModel; } else if (!fXSModel) { // create a new model only if we didn't have one already fXSModel = new (fMemoryManager) XSModel(0, this, fMemoryManager); } return fXSModel; } XERCES_CPP_NAMESPACE_END