| /* |
| * 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: GrammarResolver.cpp 568078 2007-08-21 11:43:25Z amassari $ |
| */ |
| |
| #include <xercesc/validators/common/GrammarResolver.hpp> |
| #include <xercesc/validators/schema/SchemaSymbols.hpp> |
| #include <xercesc/validators/schema/SchemaGrammar.hpp> |
| #include <xercesc/validators/schema/XMLSchemaDescriptionImpl.hpp> |
| #include <xercesc/validators/DTD/XMLDTDDescriptionImpl.hpp> |
| #include <xercesc/internal/XMLGrammarPoolImpl.hpp> |
| |
| 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<Grammar>(29, true, manager); |
| |
| /*** |
| * Grammars in this set are not owned |
| */ |
| fGrammarFromPool = new (manager) RefHashTableOf<Grammar>(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<SchemaGrammar*> (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); |
| fDataTypeReg->expandRegistryToFullSchemaSet(); |
| } |
| |
| 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<XMLGrammarDescription> 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<Grammar> |
| GrammarResolver::getGrammarEnumerator() const |
| { |
| return RefHashTableOfEnumerator<Grammar>(fGrammarBucket, false, fMemoryManager); |
| } |
| |
| RefHashTableOfEnumerator<Grammar> |
| GrammarResolver::getReferencedGrammarEnumerator() const |
| { |
| return RefHashTableOfEnumerator<Grammar>(fGrammarFromPool, false, fMemoryManager); |
| } |
| |
| RefHashTableOfEnumerator<Grammar> |
| 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<XMLGrammarDescription> 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<Grammar> grammarEnum(fGrammarBucket, false, fMemoryManager); |
| ValueVectorOf<XMLCh*> 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<Grammar> 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 |