blob: 00b8d28b873f296ddc23d1f4d81002a132e9b9ee [file] [log] [blame]
/*
* 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