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: querycontainer.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_dbaccess.hxx"
34 #ifndef _DBA_CORE_QUERYCONTAINER_HXX_
35 #include "querycontainer.hxx"
37 #ifndef DBACCESS_SHARED_DBASTRINGS_HRC
38 #include "dbastrings.hrc"
40 #ifndef _DBA_COREAPI_QUERY_HXX_
43 #ifndef DBACCESS_OBJECTNAMEAPPROVAL_HXX
44 #include "objectnameapproval.hxx"
46 #ifndef DBA_CONTAINERLISTENER_HXX
47 #include "ContainerListener.hxx"
49 #ifndef DBACCESS_VETO_HXX
53 /** === begin UNO includes === **/
54 #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
55 #include <com/sun/star/beans/XPropertySet.hpp>
57 #ifndef _COM_SUN_STAR_CONTAINER_XCONTAINER_HPP_
58 #include <com/sun/star/container/XContainer.hpp>
60 #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_
61 #include <com/sun/star/sdbc/XConnection.hpp>
63 #ifndef _COM_SUN_STAR_CONTAINER_XCONTAINERAPPROVEBROADCASTER_HPP_
64 #include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
66 /** === end UNO includes === **/
68 #ifndef _DBHELPER_DBEXCEPTION_HXX_
69 #include <connectivity/dbexception.hxx>
72 #ifndef _TOOLS_DEBUG_HXX
73 #include <tools/debug.hxx>
75 #ifndef _COMPHELPER_ENUMHELPER_HXX_
76 #include <comphelper/enumhelper.hxx>
78 #ifndef _COMPHELPER_UNO3_HXX_
79 #include <comphelper/uno3.hxx>
81 #ifndef _COMPHELPER_PROPERTY_HXX_
82 #include <comphelper/property.hxx>
84 #ifndef _COMPHELPER_SEQUENCE_HXX_
85 #include <comphelper/sequence.hxx>
87 #ifndef _COMPHELPER_EXTRACT_HXX_
88 #include <comphelper/extract.hxx>
90 #ifndef _CPPUHELPER_EXC_HLP_HXX_
91 #include <cppuhelper/exc_hlp.hxx>
94 using namespace dbtools
;
95 using namespace ::com::sun::star::uno
;
96 using namespace ::com::sun::star::ucb
;
97 using namespace ::com::sun::star::lang
;
98 using namespace ::com::sun::star::beans
;
99 using namespace ::com::sun::star::sdb
;
100 using namespace ::com::sun::star::sdbc
;
101 using namespace ::com::sun::star::sdbcx
;
102 using namespace ::com::sun::star::container
;
103 using namespace ::com::sun::star::util
;
104 using namespace ::osl
;
105 using namespace ::comphelper
;
106 using namespace ::cppu
;
108 //........................................................................
111 //........................................................................
113 //==========================================================================
115 //==========================================================================
116 DBG_NAME(OQueryContainer
)
117 //------------------------------------------------------------------------------
118 OQueryContainer::OQueryContainer(
119 const Reference
< XNameContainer
>& _rxCommandDefinitions
120 , const Reference
< XConnection
>& _rxConn
121 , const Reference
< XMultiServiceFactory
>& _rxORB
,
122 ::dbtools::IWarningsContainer
* _pWarnings
)
123 :ODefinitionContainer(_rxORB
,NULL
,TContentPtr(new ODefinitionContainer_Impl
))
124 ,m_pWarnings( _pWarnings
)
125 ,m_xCommandDefinitions(_rxCommandDefinitions
)
126 ,m_xConnection(_rxConn
)
128 DBG_CTOR(OQueryContainer
, NULL
);
130 increment(m_refCount
);
132 m_pCommandsListener
= new OContainerListener( *this, m_aMutex
);
133 m_pCommandsListener
->acquire();
135 Reference
< XContainer
> xContainer( m_xCommandDefinitions
, UNO_QUERY_THROW
);
136 xContainer
->addContainerListener( m_pCommandsListener
);
138 Reference
< XContainerApproveBroadcaster
> xContainerApprove( m_xCommandDefinitions
, UNO_QUERY_THROW
);
139 xContainerApprove
->addContainerApproveListener( m_pCommandsListener
);
141 // fill my structures
142 ODefinitionContainer_Impl
& rDefinitions( getDefinitions() );
143 Sequence
< ::rtl::OUString
> sDefinitionNames
= m_xCommandDefinitions
->getElementNames();
144 const ::rtl::OUString
* pDefinitionName
= sDefinitionNames
.getConstArray();
145 const ::rtl::OUString
* pEnd
= pDefinitionName
+ sDefinitionNames
.getLength();
146 for ( ; pDefinitionName
!= pEnd
; ++pDefinitionName
)
148 rDefinitions
.insert( *pDefinitionName
, TContentPtr() );
149 m_aDocuments
.push_back(m_aDocumentMap
.insert(Documents::value_type(*pDefinitionName
,Documents::mapped_type())).first
);
152 decrement(m_refCount
);
154 setElementApproval( PContainerApprove( new ObjectNameApproval( _rxConn
, ObjectNameApproval::TypeQuery
) ) );
157 //------------------------------------------------------------------------------
158 OQueryContainer::~OQueryContainer()
160 DBG_DTOR(OQueryContainer
, NULL
);
162 // maybe we're already disposed, but this should be uncritical
164 // -----------------------------------------------------------------------------
165 IMPLEMENT_FORWARD_XINTERFACE2( OQueryContainer
,ODefinitionContainer
,OQueryContainer_Base
)
166 //------------------------------------------------------------------------------
167 void OQueryContainer::disposing()
169 ODefinitionContainer::disposing();
170 MutexGuard
aGuard(m_aMutex
);
171 if ( !m_xCommandDefinitions
.is() )
175 if ( m_pCommandsListener
)
177 Reference
< XContainer
> xContainer( m_xCommandDefinitions
, UNO_QUERY
);
178 xContainer
->removeContainerListener( m_pCommandsListener
);
179 Reference
< XContainerApproveBroadcaster
> xContainerApprove( m_xCommandDefinitions
, UNO_QUERY
);
180 xContainerApprove
->removeContainerApproveListener( m_pCommandsListener
);
182 m_pCommandsListener
->dispose();
183 m_pCommandsListener
->release();
184 m_pCommandsListener
= NULL
;
187 m_xCommandDefinitions
= NULL
;
188 m_xConnection
= NULL
;
192 //------------------------------------------------------------------------------
193 IMPLEMENT_SERVICE_INFO2(OQueryContainer
, "com.sun.star.sdb.dbaccess.OQueryContainer", SERVICE_SDBCX_CONTAINER
, SERVICE_SDB_QUERIES
)
195 // XDataDescriptorFactory
196 //--------------------------------------------------------------------------
197 Reference
< XPropertySet
> SAL_CALL
OQueryContainer::createDataDescriptor( ) throw(RuntimeException
)
199 return new OQueryDescriptor();
203 //------------------------------------------------------------------------------
204 void SAL_CALL
OQueryContainer::appendByDescriptor( const Reference
< XPropertySet
>& _rxDesc
) throw(SQLException
, ElementExistException
, RuntimeException
)
206 ResettableMutexGuard
aGuard(m_aMutex
);
207 if ( !m_xCommandDefinitions
.is() )
208 throw DisposedException( ::rtl::OUString(), *this );
210 // first clone this object's CommandDefinition part
211 Reference
< XPropertySet
> xCommandDefinitionPart( m_aContext
.createComponent( (::rtl::OUString
)SERVICE_SDB_QUERYDEFINITION
), UNO_QUERY_THROW
);
212 ::comphelper::copyProperties( _rxDesc
, xCommandDefinitionPart
);
213 // TODO : the columns part of the descriptor has to be copied
215 // create a wrapper for the object (*before* inserting into our command definition container)
216 Reference
< XContent
> xNewObject( implCreateWrapper( Reference
< XContent
>( xCommandDefinitionPart
, UNO_QUERY_THROW
) ) );
218 ::rtl::OUString sNewObjectName
;
219 _rxDesc
->getPropertyValue(PROPERTY_NAME
) >>= sNewObjectName
;
223 notifyByName( aGuard
, sNewObjectName
, xNewObject
, NULL
, E_INSERTED
, ApproveListeners
);
225 catch( const Exception
& )
227 disposeComponent( xNewObject
);
228 disposeComponent( xCommandDefinitionPart
);
232 // insert the basic object into the definition container
234 m_eDoingCurrently
= INSERTING
;
235 OAutoActionReset
aAutoReset(this);
236 m_xCommandDefinitions
->insertByName(sNewObjectName
, makeAny(xCommandDefinitionPart
));
239 implAppend( sNewObjectName
, xNewObject
);
240 notifyByName( aGuard
, sNewObjectName
, xNewObject
, NULL
, E_INSERTED
, ContainerListemers
);
244 //------------------------------------------------------------------------------
245 void SAL_CALL
OQueryContainer::dropByName( const ::rtl::OUString
& _rName
) throw(SQLException
, NoSuchElementException
, RuntimeException
)
247 MutexGuard
aGuard(m_aMutex
);
248 if ( !checkExistence(_rName
) )
249 throw NoSuchElementException(_rName
,*this);
251 if ( !m_xCommandDefinitions
.is() )
252 throw DisposedException( ::rtl::OUString(), *this );
254 // now simply forward the remove request to the CommandDefinition container, we're a listener for the removal
255 // and thus we do everything neccessary in ::elementRemoved
256 m_xCommandDefinitions
->removeByName(_rName
);
259 //------------------------------------------------------------------------------
260 void SAL_CALL
OQueryContainer::dropByIndex( sal_Int32 _nIndex
) throw(SQLException
, IndexOutOfBoundsException
, RuntimeException
)
262 MutexGuard
aGuard(m_aMutex
);
263 if ((_nIndex
<0) || (_nIndex
>getCount()))
264 throw IndexOutOfBoundsException();
266 if ( !m_xCommandDefinitions
.is() )
267 throw DisposedException( ::rtl::OUString(), *this );
269 ::rtl::OUString sName
;
270 Reference
<XPropertySet
> xProp(Reference
<XIndexAccess
>(m_xCommandDefinitions
,UNO_QUERY
)->getByIndex(_nIndex
),UNO_QUERY
);
272 xProp
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
276 //------------------------------------------------------------------------------
277 void SAL_CALL
OQueryContainer::elementInserted( const ::com::sun::star::container::ContainerEvent
& _rEvent
) throw(::com::sun::star::uno::RuntimeException
)
279 Reference
< XContent
> xNewElement
;
280 ::rtl::OUString sElementName
;
281 _rEvent
.Accessor
>>= sElementName
;
283 MutexGuard
aGuard(m_aMutex
);
284 if (INSERTING
== m_eDoingCurrently
)
285 // nothing to do, we're inserting via an "appendByDescriptor"
288 DBG_ASSERT(sElementName
.getLength(), "OQueryContainer::elementInserted : invalid name !");
289 DBG_ASSERT(m_aDocumentMap
.find(sElementName
) == m_aDocumentMap
.end(), "OQueryContainer::elementInserted : oops .... we're inconsistent with our master container !");
290 if (!sElementName
.getLength() || hasByName(sElementName
))
293 // insert an own new element
294 xNewElement
= implCreateWrapper(sElementName
);
296 insertByName(sElementName
,makeAny(xNewElement
));
299 //------------------------------------------------------------------------------
300 void SAL_CALL
OQueryContainer::elementRemoved( const ::com::sun::star::container::ContainerEvent
& _rEvent
) throw(::com::sun::star::uno::RuntimeException
)
302 ::rtl::OUString sAccessor
;
303 _rEvent
.Accessor
>>= sAccessor
;
305 DBG_ASSERT(sAccessor
.getLength(), "OQueryContainer::elementRemoved : invalid name !");
306 DBG_ASSERT(m_aDocumentMap
.find(sAccessor
) != m_aDocumentMap
.end(), "OQueryContainer::elementRemoved : oops .... we're inconsistent with our master container !");
307 if ( !sAccessor
.getLength() || !hasByName(sAccessor
) )
310 removeByName(sAccessor
);
313 //------------------------------------------------------------------------------
314 void SAL_CALL
OQueryContainer::elementReplaced( const ::com::sun::star::container::ContainerEvent
& _rEvent
) throw(::com::sun::star::uno::RuntimeException
)
316 Reference
< XPropertySet
> xReplacedElement
;
317 Reference
< XContent
> xNewElement
;
318 ::rtl::OUString sAccessor
;
319 _rEvent
.Accessor
>>= sAccessor
;
322 MutexGuard
aGuard(m_aMutex
);
323 DBG_ASSERT(sAccessor
.getLength(), "OQueryContainer::elementReplaced : invalid name !");
324 DBG_ASSERT(m_aDocumentMap
.find(sAccessor
) != m_aDocumentMap
.end(), "OQueryContainer::elementReplaced : oops .... we're inconsistent with our master container !");
325 if (!sAccessor
.getLength() || !hasByName(sAccessor
))
328 xNewElement
= implCreateWrapper(sAccessor
);
331 replaceByName(sAccessor
,makeAny(xNewElement
));
334 //------------------------------------------------------------------------------
335 Reference
< XVeto
> SAL_CALL
OQueryContainer::approveInsertElement( const ContainerEvent
& Event
) throw (WrappedTargetException
, RuntimeException
)
337 ::rtl::OUString sName
;
338 OSL_VERIFY( Event
.Accessor
>>= sName
);
339 Reference
< XContent
> xElement( Event
.Element
, UNO_QUERY_THROW
);
341 Reference
< XVeto
> xReturn
;
344 getElementApproval()->approveElement( sName
, xElement
.get() );
346 catch( const Exception
& )
348 xReturn
= new Veto( ::rtl::OUString(), ::cppu::getCaughtException() );
353 //------------------------------------------------------------------------------
354 Reference
< XVeto
> SAL_CALL
OQueryContainer::approveReplaceElement( const ContainerEvent
& /*Event*/ ) throw (WrappedTargetException
, RuntimeException
)
359 //------------------------------------------------------------------------------
360 Reference
< XVeto
> SAL_CALL
OQueryContainer::approveRemoveElement( const ContainerEvent
& /*Event*/ ) throw (WrappedTargetException
, RuntimeException
)
365 //------------------------------------------------------------------------------
366 void SAL_CALL
OQueryContainer::disposing( const ::com::sun::star::lang::EventObject
& _rSource
) throw(::com::sun::star::uno::RuntimeException
)
368 if (_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinitions
, UNO_QUERY
).get())
369 { // our "master container" (with the command definitions) is beeing disposed
370 DBG_ERROR("OQueryContainer::disposing : nobody should dispose the CommandDefinition container before disposing my connection !");
375 Reference
< XContent
> xSource(_rSource
.Source
, UNO_QUERY
);
376 // it's one of our documents ....
377 Documents::iterator aIter
= m_aDocumentMap
.begin();
378 Documents::iterator aEnd
= m_aDocumentMap
.end();
379 for (;aIter
!= aEnd
;++aIter
)
381 if ( xSource
== aIter
->second
.get() )
383 m_xCommandDefinitions
->removeByName(aIter
->first
);
387 ODefinitionContainer::disposing(_rSource
);
391 // -----------------------------------------------------------------------------
392 ::rtl::OUString
OQueryContainer::determineContentType() const
394 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQueryContainer" ) );
397 // -----------------------------------------------------------------------------
398 Reference
< XContent
> OQueryContainer::implCreateWrapper(const ::rtl::OUString
& _rName
)
400 Reference
< XContent
> xObject(m_xCommandDefinitions
->getByName(_rName
),UNO_QUERY
);
401 return implCreateWrapper(xObject
);
404 //--------------------------------------------------------------------------
405 Reference
< XContent
> OQueryContainer::implCreateWrapper(const Reference
< XContent
>& _rxCommandDesc
)
407 Reference
<XNameContainer
> xContainer(_rxCommandDesc
,UNO_QUERY
);
408 Reference
< XContent
> xReturn
;
409 if ( xContainer
.is() )
411 xReturn
= new OQueryContainer( xContainer
, m_xConnection
, m_aContext
.getLegacyServiceFactory(), m_pWarnings
);
415 OQuery
* pNewObject
= new OQuery( Reference
< XPropertySet
>( _rxCommandDesc
, UNO_QUERY
), m_xConnection
, m_aContext
.getLegacyServiceFactory() );
416 xReturn
= pNewObject
;
418 pNewObject
->setWarningsContainer( m_pWarnings
);
419 // pNewObject->getColumns();
420 // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the
421 // QueryInQuery test in dbaccess/qa/complex/dbaccess ...
426 //--------------------------------------------------------------------------
427 Reference
< XContent
> OQueryContainer::createObject( const ::rtl::OUString
& _rName
)
429 return implCreateWrapper(_rName
);
431 // -----------------------------------------------------------------------------
432 sal_Bool
OQueryContainer::checkExistence(const ::rtl::OUString
& _rName
)
434 sal_Bool bRet
= sal_False
;
435 if ( !m_bInPropertyChange
)
437 bRet
= m_xCommandDefinitions
->hasByName(_rName
);
438 Documents::iterator aFind
= m_aDocumentMap
.find(_rName
);
439 if ( !bRet
&& aFind
!= m_aDocumentMap
.end() )
441 m_aDocuments
.erase( ::std::find(m_aDocuments
.begin(),m_aDocuments
.end(),aFind
));
442 m_aDocumentMap
.erase(aFind
);
444 else if ( bRet
&& aFind
== m_aDocumentMap
.end() )
446 implAppend(_rName
,NULL
);
451 //--------------------------------------------------------------------------
452 sal_Bool SAL_CALL
OQueryContainer::hasElements( ) throw (RuntimeException
)
454 MutexGuard
aGuard(m_aMutex
);
455 return m_xCommandDefinitions
->hasElements();
457 // -----------------------------------------------------------------------------
458 sal_Int32 SAL_CALL
OQueryContainer::getCount( ) throw(RuntimeException
)
460 MutexGuard
aGuard(m_aMutex
);
461 return Reference
<XIndexAccess
>(m_xCommandDefinitions
,UNO_QUERY
)->getCount();
463 // -----------------------------------------------------------------------------
464 Sequence
< ::rtl::OUString
> SAL_CALL
OQueryContainer::getElementNames( ) throw(RuntimeException
)
466 MutexGuard
aGuard(m_aMutex
);
468 return m_xCommandDefinitions
->getElementNames();
471 //........................................................................
472 } // namespace dbaccess
473 //........................................................................