1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: schemabuilder.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "schemabuilder.hxx"
35 #include "treenodefactory.hxx"
36 #include "matchlocale.hxx"
37 #include <com/sun/star/configuration/backend/SchemaAttribute.hpp>
38 #include <rtl/ustrbuf.hxx>
40 #ifndef INCLUDED_ALGORITHM
42 #define INCLUDED_ALGORITHM
44 #ifndef INCLUDED_VECTOR
46 #define INCLUDED_VECTOR
51 // -----------------------------------------------------------------------------
54 // -----------------------------------------------------------------------------
56 namespace SchemaAttribute
= backenduno::SchemaAttribute
;
57 // -----------------------------------------------------------------------------
58 //#if OSL_DEBUG_LEVEL > 0
59 // currently not used in debug builds
61 static void check_if_complete(MergedComponentData
& md
, uno::Reference
< uno::XComponentContext
> const & xContext
)
63 uno::Reference
< backenduno::XSchemaHandler
>
64 test(new SchemaBuilder(xContext
, rtl::OUString(),md
,NULL
));
67 // -----------------------------------------------------------------------------
69 SchemaBuilder::SchemaBuilder(uno::Reference
< uno::XComponentContext
> const & xContext
, const rtl::OUString
& aExpectedComponentName
, MergedComponentData
& rData
, ITemplateDataProvider
* aTemplateProvider
)
71 , m_aContext(xContext
)
72 //, m_aContext(xContext,static_cast<backenduno::XSchemaHandler*>(this), aExpectedComponentName, aTemplateProvider )
75 m_aContext
= DataBuilderContext(xContext
,static_cast<backenduno::XSchemaHandler
*>(this), aExpectedComponentName
, aTemplateProvider
);
77 // -----------------------------------------------------------------------------
79 SchemaBuilder::~SchemaBuilder( )
83 // -----------------------------------------------------------------------------
85 // -----------------------------------------------------------------------------
88 void SAL_CALL
SchemaBuilder::startSchema( )
89 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
92 m_aContext
.raiseMalformedDataException("Schema builder: Unexpected Restart of Schema");
96 OSL_ASSERT(!m_aContext
.hasActiveComponent());
97 OSL_ASSERT( m_aContext
.isDone());
99 // -----------------------------------------------------------------------------
101 void SAL_CALL
SchemaBuilder::endSchema( )
102 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
105 m_aContext
.raiseMalformedDataException("Schema builder: Unexpected End of Schema");
107 substituteInstances();
109 // -----------------------------------------------------------------------------
111 void SAL_CALL
SchemaBuilder::importComponent( const rtl::OUString
& /*aName*/ )
112 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
114 //OSL_TRACE("WARNING: Configuration schema parser: Cross-component references are not yet supported\n");
116 // -----------------------------------------------------------------------------
119 void SAL_CALL
SchemaBuilder::startComponent( const rtl::OUString
& aName
)
120 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
122 if (m_aData
.hasSchema())
123 m_aContext
.raiseElementExistException("Schema builder: The component schema is already loaded", rtl::OUString());
125 m_aContext
.startActiveComponent(aName
);
127 std::auto_ptr
<ISubtree
> apSchema
=
128 m_aFactory
.createGroup(aName
,0,getComponentRootAttributes());
130 ISubtree
* pSchema
= m_aData
.setSchemaRoot(apSchema
);
132 m_aContext
.pushNode(pSchema
);
134 // -----------------------------------------------------------------------------
136 void SAL_CALL
SchemaBuilder::endComponent( )
137 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
139 m_aContext
.popNode();
141 m_aContext
.endActiveComponent();
143 // -----------------------------------------------------------------------------
145 bool SchemaBuilder::isExtensible(sal_Int16 aSchemaAttributes
)
147 sal_Int16
const aValidAttributes
= aSchemaAttributes
& SchemaAttribute::EXTENSIBLE
;
149 if (aValidAttributes
!= aSchemaAttributes
)
150 m_aContext
.raiseIllegalArgumentException("Schema builder: Illegal attribute specified for node.",2);
152 return (aValidAttributes
!= 0);
154 // -----------------------------------------------------------------------------
156 void SAL_CALL
SchemaBuilder::startGroupTemplate( const backenduno::TemplateIdentifier
& aTemplate
, sal_Int16 aAttributes
)
157 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
159 if (aTemplate
.Component
.getLength() == 0)
160 m_aContext
.raiseIllegalArgumentException("Schema builder: Starting template without owning component",1);
162 m_aContext
.startActiveComponent(aTemplate
.Component
);
164 if (m_aData
.hasTemplate(aTemplate
.Name
))
165 m_aContext
.raiseElementExistException("Schema builder: Template already exists",aTemplate
.Name
);
167 rtl::OUString aName
= m_aData
.getTemplateAccessor(aTemplate
);
168 bool bExtensible
= isExtensible(aAttributes
);
170 std::auto_ptr
<ISubtree
> aTemplateTree
=
171 m_aFactory
.createGroup(aName
,bExtensible
,getTemplateBaseAttributes());
173 ISubtree
* pTree
= m_aData
.addTemplate(aTemplateTree
,aTemplate
);
175 m_aContext
.pushNode(pTree
);
177 // -----------------------------------------------------------------------------
179 void SAL_CALL
SchemaBuilder::startSetTemplate( const backenduno::TemplateIdentifier
& aTemplate
, sal_Int16 aAttributes
, const backenduno::TemplateIdentifier
& aItemType
)
180 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
182 if (aTemplate
.Component
.getLength() == 0)
183 m_aContext
.raiseIllegalArgumentException("Schema builder: Starting template without owning component",1);
185 m_aContext
.startActiveComponent(aTemplate
.Component
);
187 if (m_aData
.hasTemplate(aTemplate
.Name
))
188 m_aContext
.raiseElementExistException("Schema builder: Template already exists",aTemplate
.Name
);
190 rtl::OUString aName
= m_aData
.getTemplateAccessor(aTemplate
);
191 backenduno::TemplateIdentifier aFullType
= m_aContext
.completeComponent(aItemType
);
192 bool bExtensible
= isExtensible(aAttributes
);
194 std::auto_ptr
<ISubtree
> aTemplateTree
=
195 m_aFactory
.createSet( aName
,aFullType
,bExtensible
,getTemplateBaseAttributes());
197 ISubtree
* pTree
= m_aData
.addTemplate(aTemplateTree
,aTemplate
);
199 m_aContext
.pushNode(pTree
);
201 // -----------------------------------------------------------------------------
203 void SAL_CALL
SchemaBuilder::endTemplate( )
204 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
206 m_aContext
.popNode();
208 m_aContext
.endActiveComponent();
210 // -----------------------------------------------------------------------------
212 void SAL_CALL
SchemaBuilder::startGroup( const rtl::OUString
& aName
, sal_Int16 aAttributes
)
213 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
215 bool bExtensible
= isExtensible(aAttributes
);
217 std::auto_ptr
<ISubtree
> aTree
= m_aFactory
.createGroup(aName
,bExtensible
,getNodeAttributes());
219 ISubtree
* pTree
= m_aContext
.addNodeToCurrent(aTree
);
221 m_aContext
.pushNode(pTree
);
223 // -----------------------------------------------------------------------------
225 void SAL_CALL
SchemaBuilder::startSet( const rtl::OUString
& aName
, sal_Int16 aAttributes
, const backenduno::TemplateIdentifier
& aItemType
)
226 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
228 backenduno::TemplateIdentifier aFullType
= m_aContext
.completeComponent(aItemType
);
229 bool bExtensible
= isExtensible(aAttributes
);
231 std::auto_ptr
<ISubtree
> aTree
= m_aFactory
.createSet(aName
,aFullType
,bExtensible
,getNodeAttributes());
233 ISubtree
* pTree
= m_aContext
.addNodeToCurrent(aTree
);
235 m_aContext
.pushNode(pTree
);
237 // -----------------------------------------------------------------------------
239 void SAL_CALL
SchemaBuilder::endNode( )
240 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
242 m_aContext
.popNode();
244 if (m_aContext
.isDone())
245 m_aContext
.raiseMalformedDataException("Schema builder: Incorrect Termination");
247 // -----------------------------------------------------------------------------
249 node::Attributes
SchemaBuilder::makePropertyAttributes(sal_Int16 aSchemaAttributes
) const
251 const sal_uInt16 c_AllPropertyAttributes
=
252 SchemaAttribute::REQUIRED
| SchemaAttribute::LOCALIZED
;
254 if ((aSchemaAttributes
& c_AllPropertyAttributes
) != aSchemaAttributes
)
255 m_aContext
.raiseIllegalArgumentException("SchemaBuilder: Unreckognized Attribute for Property",2);
257 node::Attributes aAttributes
= getNodeAttributes();
259 if (aSchemaAttributes
& SchemaAttribute::REQUIRED
)
260 aAttributes
.setNullable (false);
264 // -----------------------------------------------------------------------------
266 void SAL_CALL
SchemaBuilder::addProperty( const rtl::OUString
& aName
, sal_Int16 aAttributes
, const uno::Type
& aType
)
267 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
269 // TODO: add type validation
270 node::Attributes aValueAttributes
= makePropertyAttributes(aAttributes
);
272 if (aAttributes
& SchemaAttribute::LOCALIZED
)
274 std::auto_ptr
<ISubtree
> aLocalizedProp
=
275 m_aFactory
.createLocalizedContainer(aName
,aType
,aValueAttributes
);
277 m_aContext
.addLocalizedToCurrent(aLocalizedProp
);
281 std::auto_ptr
<ValueNode
> aPropertyValue
=
282 m_aFactory
.getNodeFactory().createNullValueNode(aName
,aType
,aValueAttributes
);
284 m_aContext
.addPropertyToCurrent(aPropertyValue
);
287 // -----------------------------------------------------------------------------
289 void SAL_CALL
SchemaBuilder::addPropertyWithDefault( const rtl::OUString
& aName
, sal_Int16 aAttributes
, const uno::Any
& aDefaultValue
)
290 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
292 // TODO: add parameter validation
293 node::Attributes aValueAttributes
= makePropertyAttributes(aAttributes
);
295 if (aAttributes
& SchemaAttribute::LOCALIZED
)
297 std::auto_ptr
<ISubtree
> aLocalizedProp
=
298 m_aFactory
.createLocalizedContainer(aName
,aDefaultValue
.getValueType(),aValueAttributes
);
300 std::auto_ptr
<ValueNode
> aPropertyValue
=
301 m_aFactory
.getNodeFactory().createValueNode(localehelper::getDefaultLanguage(),aDefaultValue
,aValueAttributes
);
303 aLocalizedProp
->addChild( base_ptr(aPropertyValue
) );
305 m_aContext
.addLocalizedToCurrent(aLocalizedProp
);
309 std::auto_ptr
<ValueNode
> aPropertyValue
=
310 m_aFactory
.getNodeFactory().createValueNode(aName
,aDefaultValue
,aValueAttributes
);
313 m_aContext
.addPropertyToCurrent( aPropertyValue
);
316 // -----------------------------------------------------------------------------
318 void SAL_CALL
SchemaBuilder::addInstance( const rtl::OUString
& aName
, const backenduno::TemplateIdentifier
& aTemplate
)
319 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
321 backenduno::TemplateIdentifier aFullType
= m_aContext
.completeComponent(aTemplate
);
323 std::auto_ptr
<ISubtree
> aPlaceHolder
=
324 m_aFactory
.createPlaceHolder(aName
,aFullType
);
326 m_aContext
.addNodeToCurrent(aPlaceHolder
);
328 // -----------------------------------------------------------------------------
330 void SAL_CALL
SchemaBuilder::addItemType( const backenduno::TemplateIdentifier
& aItemType
)
331 throw (backenduno::MalformedDataException
, lang::WrappedTargetException
, uno::RuntimeException
)
333 if ( m_aContext
.getCurrentParent().getElementTemplateName() != aItemType
.Name
||
334 m_aContext
.getCurrentParent().getElementTemplateModule() != m_aContext
.getTemplateComponent(aItemType
) )
336 OSL_ENSURE(false, "SchemaBuilder: Multiple ItemTypes for Sets are currently not supported");
337 m_aContext
.raiseMalformedDataException("SchemaBuilder: Unsupported Feature: Multiple ItemTypes for Sets");
340 // -----------------------------------------------------------------------------
341 // -----------------------------------------------------------------------------
343 node::Attributes
SchemaBuilder::getNodeAttributes() const
345 node::Attributes aResult
= m_aContext
.getCurrentAttributes();
346 aResult
.setState( node::isDefault
);
349 // -----------------------------------------------------------------------------
351 node::Attributes
SchemaBuilder::getComponentRootAttributes()
353 node::Attributes aResult
;
354 aResult
.setState( node::isDefault
);
357 // -----------------------------------------------------------------------------
359 node::Attributes
SchemaBuilder::getTemplateBaseAttributes()
361 node::Attributes aResult
;
362 aResult
.setState( node::isReplaced
);
365 // -----------------------------------------------------------------------------
366 // -----------------------------------------------------------------------------
370 class SubstitutionHelper
: NodeModification
372 MergedComponentData
& m_rData
;
373 DataBuilderContext m_aContext
;
374 ComponentDataFactory m_aFactory
;
376 std::vector
< rtl::OUString
> m_aReplacementList
;
377 std::vector
< ISubtree
const * > m_aTemplateStack
;
379 SubstitutionHelper(DataBuilderContext
const & aBaseContext
, MergedComponentData
& _rData
, uno::XInterface
* _pContext
)
381 , m_aContext(aBaseContext
,_pContext
)
382 , m_aReplacementList()
386 void substituteInData();
388 void substituteInComponent(ISubtree
* _pComponent
);
389 void substituteInNode(ISubtree
& _rNode
);
390 void substituteInList();
392 void substitute(rtl::OUString
const & _aName
);
394 virtual void handle(ValueNode
&);
395 virtual void handle(ISubtree
&);
398 // -----------------------------------------------------------------------------
400 void SchemaBuilder::substituteInstances()
402 SubstitutionHelper
helper(m_aContext
, m_aData
, static_cast<backenduno::XSchemaHandler
*>(this));
404 helper
.substituteInData();
406 // -----------------------------------------------------------------------------
407 // -----------------------------------------------------------------------------
410 // -----------------------------------------------------------------------------
411 void SubstitutionHelper::substituteInData()
413 if (m_rData
.hasTemplates())
414 substituteInComponent(m_rData
.getTemplatesTree());
416 if (m_rData
.hasSchema())
417 substituteInComponent(m_rData
.getSchemaTree());
419 // -----------------------------------------------------------------------------
421 void SubstitutionHelper::substituteInComponent(ISubtree
* _pComponent
)
423 OSL_ENSURE(_pComponent
,"ERROR: Trying to substitute in NULL component");
427 m_aContext
.startActiveComponent(_pComponent
->getName());
428 this->substituteInNode(*_pComponent
);
429 m_aContext
.endActiveComponent();
432 // -----------------------------------------------------------------------------
434 void SubstitutionHelper::substituteInNode(ISubtree
& _rNode
)
436 std::vector
< rtl::OUString
> aSaveInstances
;
437 aSaveInstances
.swap(m_aReplacementList
);
439 // todo: own stack to check against infinite recursion
440 m_aContext
.pushNode(&_rNode
);
442 this->applyToChildren(_rNode
); // fill the list
444 this->substituteInList();
446 m_aContext
.popNode();
448 aSaveInstances
.swap(m_aReplacementList
);
450 // -----------------------------------------------------------------------------
452 void SubstitutionHelper::substituteInList()
454 for(std::vector
< rtl::OUString
>::iterator it
= m_aReplacementList
.begin();
455 it
!= m_aReplacementList
.end(); ++it
)
457 this->substitute(*it
);
460 // -----------------------------------------------------------------------------
462 void SubstitutionHelper::substitute(rtl::OUString
const & _aName
)
465 ISubtree
& rParent
= m_aContext
.getCurrentParent();
467 std::auto_ptr
<INode
> pReplacedNode
= rParent
.removeChild(_aName
);
468 OSL_ASSERT( pReplacedNode
.get() != NULL
);
470 ISubtree
* pReplacedInstance
= pReplacedNode
->asISubtree();
471 OSL_ASSERT( pReplacedInstance
!= NULL
);
473 backenduno::TemplateIdentifier aTemplateName
= m_aFactory
.getInstanceType(*pReplacedInstance
);
474 if (aTemplateName
.Component
== m_aContext
.getActiveComponent())
476 if (ISubtree
const * pTemplate
= m_rData
.findTemplate(aTemplateName
.Name
))
478 std::vector
< ISubtree
const * >::iterator beg
= m_aTemplateStack
.begin(), end
= m_aTemplateStack
.end();
479 if (std::find(beg
,end
,pTemplate
) != end
)
480 m_aContext
.raiseMalformedDataException("SchemaBuilder: Could not expand instances: Template is recursive");
482 m_aTemplateStack
.push_back(pTemplate
);
484 std::auto_ptr
< INode
> pTemplateInstance
= pTemplate
->clone();
486 pTemplateInstance
->setName(_aName
);
487 // TODO: adjust state/attributes here (?)
489 ISubtree
* pAddedTree
= rParent
.addChild(pTemplateInstance
)->asISubtree();
491 OSL_ENSURE(pAddedTree
, "Could not obtain added template instance");
493 this->substituteInNode(*pAddedTree
);
495 m_aTemplateStack
.pop_back();
499 m_aContext
.raiseMalformedDataException("SchemaBuilder: Could not expand instances: Template not found");
502 //Import Template from different component
505 TemplateRequest
aTemplateRequest(aTemplateName
.Name
,
506 aTemplateName
.Component
);
507 ResultHolder
< TemplateInstance
> aResult
= m_aContext
.getTemplateData( aTemplateRequest
);
509 std::auto_ptr
<INode
> pTemplateInstance
= aResult
.extractDataAndClear();
510 pTemplateInstance
->setName(_aName
);
512 // Add template instance - must be a tree as any template
514 rParent
.addChild(pTemplateInstance
)->asISubtree() );
517 // -----------------------------------------------------------------------------
519 void SubstitutionHelper::handle(ValueNode
&)
522 // -----------------------------------------------------------------------------
524 void SubstitutionHelper::handle(ISubtree
& _rTree
)
526 if (m_aFactory
.isInstancePlaceHolder(_rTree
))
527 m_aReplacementList
.push_back(_rTree
.getName());
530 substituteInNode(_rTree
);
532 // -----------------------------------------------------------------------------
534 // -----------------------------------------------------------------------------
535 // -----------------------------------------------------------------------------
536 } // namespace backend
538 // -------------------------------------------------------------------------
539 } // namespace configmgr