1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "querycontainer.hxx"
22 #include "dbastrings.hrc"
24 #include "objectnameapproval.hxx"
25 #include "ContainerListener.hxx"
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/container/XContainer.hpp>
30 #include <com/sun/star/sdbc/XConnection.hpp>
31 #include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
33 #include <connectivity/dbexception.hxx>
35 #include <tools/debug.hxx>
36 #include <osl/diagnose.h>
37 #include <comphelper/enumhelper.hxx>
38 #include <comphelper/uno3.hxx>
39 #include <comphelper/property.hxx>
40 #include <comphelper/sequence.hxx>
41 #include <comphelper/extract.hxx>
42 #include <cppuhelper/exc_hlp.hxx>
44 using namespace dbtools
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::ucb
;
47 using namespace ::com::sun::star::lang
;
48 using namespace ::com::sun::star::beans
;
49 using namespace ::com::sun::star::sdb
;
50 using namespace ::com::sun::star::sdbc
;
51 using namespace ::com::sun::star::sdbcx
;
52 using namespace ::com::sun::star::container
;
53 using namespace ::com::sun::star::util
;
54 using namespace ::osl
;
55 using namespace ::comphelper
;
56 using namespace ::cppu
;
61 //==========================================================================
63 //==========================================================================
64 DBG_NAME(OQueryContainer
)
66 OQueryContainer::OQueryContainer(
67 const Reference
< XNameContainer
>& _rxCommandDefinitions
68 , const Reference
< XConnection
>& _rxConn
69 , const Reference
< XMultiServiceFactory
>& _rxORB
,
70 ::dbtools::IWarningsContainer
* _pWarnings
)
71 :ODefinitionContainer(_rxORB
,NULL
,TContentPtr(new ODefinitionContainer_Impl
))
72 ,m_pWarnings( _pWarnings
)
73 ,m_xCommandDefinitions(_rxCommandDefinitions
)
74 ,m_xConnection(_rxConn
)
76 DBG_CTOR(OQueryContainer
, NULL
);
78 increment(m_refCount
);
80 m_pCommandsListener
= new OContainerListener( *this, m_aMutex
);
81 m_pCommandsListener
->acquire();
83 Reference
< XContainer
> xContainer( m_xCommandDefinitions
, UNO_QUERY_THROW
);
84 xContainer
->addContainerListener( m_pCommandsListener
);
86 Reference
< XContainerApproveBroadcaster
> xContainerApprove( m_xCommandDefinitions
, UNO_QUERY_THROW
);
87 xContainerApprove
->addContainerApproveListener( m_pCommandsListener
);
90 ODefinitionContainer_Impl
& rDefinitions( getDefinitions() );
91 Sequence
< ::rtl::OUString
> sDefinitionNames
= m_xCommandDefinitions
->getElementNames();
92 const ::rtl::OUString
* pDefinitionName
= sDefinitionNames
.getConstArray();
93 const ::rtl::OUString
* pEnd
= pDefinitionName
+ sDefinitionNames
.getLength();
94 for ( ; pDefinitionName
!= pEnd
; ++pDefinitionName
)
96 rDefinitions
.insert( *pDefinitionName
, TContentPtr() );
97 m_aDocuments
.push_back(m_aDocumentMap
.insert(Documents::value_type(*pDefinitionName
,Documents::mapped_type())).first
);
100 decrement(m_refCount
);
102 setElementApproval( PContainerApprove( new ObjectNameApproval( _rxConn
, ObjectNameApproval::TypeQuery
) ) );
105 OQueryContainer::~OQueryContainer()
107 DBG_DTOR(OQueryContainer
, NULL
);
109 // maybe we're already disposed, but this should be uncritical
112 IMPLEMENT_FORWARD_XINTERFACE2( OQueryContainer
,ODefinitionContainer
,OQueryContainer_Base
)
114 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryContainer
,ODefinitionContainer
,OQueryContainer_Base
)
116 void OQueryContainer::disposing()
118 ODefinitionContainer::disposing();
119 MutexGuard
aGuard(m_aMutex
);
120 if ( !m_xCommandDefinitions
.is() )
124 if ( m_pCommandsListener
)
126 Reference
< XContainer
> xContainer( m_xCommandDefinitions
, UNO_QUERY
);
127 xContainer
->removeContainerListener( m_pCommandsListener
);
128 Reference
< XContainerApproveBroadcaster
> xContainerApprove( m_xCommandDefinitions
, UNO_QUERY
);
129 xContainerApprove
->removeContainerApproveListener( m_pCommandsListener
);
131 m_pCommandsListener
->dispose();
132 m_pCommandsListener
->release();
133 m_pCommandsListener
= NULL
;
136 m_xCommandDefinitions
= NULL
;
137 m_xConnection
= NULL
;
141 IMPLEMENT_SERVICE_INFO2(OQueryContainer
, "com.sun.star.sdb.dbaccess.OQueryContainer", SERVICE_SDBCX_CONTAINER
.ascii
, SERVICE_SDB_QUERIES
.ascii
)
143 // XDataDescriptorFactory
144 Reference
< XPropertySet
> SAL_CALL
OQueryContainer::createDataDescriptor( ) throw(RuntimeException
)
146 return new OQueryDescriptor();
150 void SAL_CALL
OQueryContainer::appendByDescriptor( const Reference
< XPropertySet
>& _rxDesc
) throw(SQLException
, ElementExistException
, RuntimeException
)
152 ResettableMutexGuard
aGuard(m_aMutex
);
153 if ( !m_xCommandDefinitions
.is() )
154 throw DisposedException( ::rtl::OUString(), *this );
156 // first clone this object's CommandDefinition part
157 Reference
< XPropertySet
> xCommandDefinitionPart( m_aContext
.createComponent( (::rtl::OUString
)SERVICE_SDB_QUERYDEFINITION
), UNO_QUERY_THROW
);
158 ::comphelper::copyProperties( _rxDesc
, xCommandDefinitionPart
);
159 // TODO : the columns part of the descriptor has to be copied
161 // create a wrapper for the object (*before* inserting into our command definition container)
162 Reference
< XContent
> xNewObject( implCreateWrapper( Reference
< XContent
>( xCommandDefinitionPart
, UNO_QUERY_THROW
) ) );
164 ::rtl::OUString sNewObjectName
;
165 _rxDesc
->getPropertyValue(PROPERTY_NAME
) >>= sNewObjectName
;
169 notifyByName( aGuard
, sNewObjectName
, xNewObject
, NULL
, E_INSERTED
, ApproveListeners
);
171 catch( const Exception
& )
173 disposeComponent( xNewObject
);
174 disposeComponent( xCommandDefinitionPart
);
178 // insert the basic object into the definition container
180 m_eDoingCurrently
= INSERTING
;
181 OAutoActionReset
aAutoReset(this);
182 m_xCommandDefinitions
->insertByName(sNewObjectName
, makeAny(xCommandDefinitionPart
));
185 implAppend( sNewObjectName
, xNewObject
);
186 notifyByName( aGuard
, sNewObjectName
, xNewObject
, NULL
, E_INSERTED
, ContainerListemers
);
190 void SAL_CALL
OQueryContainer::dropByName( const ::rtl::OUString
& _rName
) throw(SQLException
, NoSuchElementException
, RuntimeException
)
192 MutexGuard
aGuard(m_aMutex
);
193 if ( !checkExistence(_rName
) )
194 throw NoSuchElementException(_rName
,*this);
196 if ( !m_xCommandDefinitions
.is() )
197 throw DisposedException( ::rtl::OUString(), *this );
199 // now simply forward the remove request to the CommandDefinition container, we're a listener for the removal
200 // and thus we do everything neccessary in ::elementRemoved
201 m_xCommandDefinitions
->removeByName(_rName
);
204 void SAL_CALL
OQueryContainer::dropByIndex( sal_Int32 _nIndex
) throw(SQLException
, IndexOutOfBoundsException
, RuntimeException
)
206 MutexGuard
aGuard(m_aMutex
);
207 if ((_nIndex
<0) || (_nIndex
>getCount()))
208 throw IndexOutOfBoundsException();
210 if ( !m_xCommandDefinitions
.is() )
211 throw DisposedException( ::rtl::OUString(), *this );
213 ::rtl::OUString sName
;
214 Reference
<XPropertySet
> xProp(Reference
<XIndexAccess
>(m_xCommandDefinitions
,UNO_QUERY
)->getByIndex(_nIndex
),UNO_QUERY
);
216 xProp
->getPropertyValue(PROPERTY_NAME
) >>= sName
;
221 void SAL_CALL
OQueryContainer::elementInserted( const ::com::sun::star::container::ContainerEvent
& _rEvent
) throw(::com::sun::star::uno::RuntimeException
)
223 Reference
< XContent
> xNewElement
;
224 ::rtl::OUString sElementName
;
225 _rEvent
.Accessor
>>= sElementName
;
227 MutexGuard
aGuard(m_aMutex
);
228 if (INSERTING
== m_eDoingCurrently
)
229 // nothing to do, we're inserting via an "appendByDescriptor"
232 OSL_ENSURE(!sElementName
.isEmpty(), "OQueryContainer::elementInserted : invalid name !");
233 OSL_ENSURE(m_aDocumentMap
.find(sElementName
) == m_aDocumentMap
.end(), "OQueryContainer::elementInserted : oops .... we're inconsistent with our master container !");
234 if (sElementName
.isEmpty() || hasByName(sElementName
))
237 // insert an own new element
238 xNewElement
= implCreateWrapper(sElementName
);
240 insertByName(sElementName
,makeAny(xNewElement
));
243 void SAL_CALL
OQueryContainer::elementRemoved( const ::com::sun::star::container::ContainerEvent
& _rEvent
) throw(::com::sun::star::uno::RuntimeException
)
245 ::rtl::OUString sAccessor
;
246 _rEvent
.Accessor
>>= sAccessor
;
248 OSL_ENSURE(!sAccessor
.isEmpty(), "OQueryContainer::elementRemoved : invalid name !");
249 OSL_ENSURE(m_aDocumentMap
.find(sAccessor
) != m_aDocumentMap
.end(), "OQueryContainer::elementRemoved : oops .... we're inconsistent with our master container !");
250 if ( sAccessor
.isEmpty() || !hasByName(sAccessor
) )
253 removeByName(sAccessor
);
256 void SAL_CALL
OQueryContainer::elementReplaced( const ::com::sun::star::container::ContainerEvent
& _rEvent
) throw(::com::sun::star::uno::RuntimeException
)
258 Reference
< XPropertySet
> xReplacedElement
;
259 Reference
< XContent
> xNewElement
;
260 ::rtl::OUString sAccessor
;
261 _rEvent
.Accessor
>>= sAccessor
;
264 MutexGuard
aGuard(m_aMutex
);
265 OSL_ENSURE(!sAccessor
.isEmpty(), "OQueryContainer::elementReplaced : invalid name !");
266 OSL_ENSURE(m_aDocumentMap
.find(sAccessor
) != m_aDocumentMap
.end(), "OQueryContainer::elementReplaced : oops .... we're inconsistent with our master container !");
267 if (sAccessor
.isEmpty() || !hasByName(sAccessor
))
270 xNewElement
= implCreateWrapper(sAccessor
);
273 replaceByName(sAccessor
,makeAny(xNewElement
));
276 Reference
< XVeto
> SAL_CALL
OQueryContainer::approveInsertElement( const ContainerEvent
& Event
) throw (WrappedTargetException
, RuntimeException
)
278 ::rtl::OUString sName
;
279 OSL_VERIFY( Event
.Accessor
>>= sName
);
280 Reference
< XContent
> xElement( Event
.Element
, UNO_QUERY_THROW
);
282 Reference
< XVeto
> xReturn
;
285 getElementApproval()->approveElement( sName
, xElement
.get() );
287 catch( const Exception
& )
289 xReturn
= new Veto( ::rtl::OUString(), ::cppu::getCaughtException() );
294 Reference
< XVeto
> SAL_CALL
OQueryContainer::approveReplaceElement( const ContainerEvent
& /*Event*/ ) throw (WrappedTargetException
, RuntimeException
)
299 Reference
< XVeto
> SAL_CALL
OQueryContainer::approveRemoveElement( const ContainerEvent
& /*Event*/ ) throw (WrappedTargetException
, RuntimeException
)
304 void SAL_CALL
OQueryContainer::disposing( const ::com::sun::star::lang::EventObject
& _rSource
) throw(::com::sun::star::uno::RuntimeException
)
306 if (_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinitions
, UNO_QUERY
).get())
307 { // our "master container" (with the command definitions) is being disposed
308 OSL_FAIL("OQueryContainer::disposing : nobody should dispose the CommandDefinition container before disposing my connection !");
313 Reference
< XContent
> xSource(_rSource
.Source
, UNO_QUERY
);
314 // it's one of our documents ....
315 Documents::iterator aIter
= m_aDocumentMap
.begin();
316 Documents::iterator aEnd
= m_aDocumentMap
.end();
317 for (;aIter
!= aEnd
;++aIter
)
319 if ( xSource
== aIter
->second
.get() )
321 m_xCommandDefinitions
->removeByName(aIter
->first
);
325 ODefinitionContainer::disposing(_rSource
);
329 ::rtl::OUString
OQueryContainer::determineContentType() const
331 return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQueryContainer" ) );
334 Reference
< XContent
> OQueryContainer::implCreateWrapper(const ::rtl::OUString
& _rName
)
336 Reference
< XContent
> xObject(m_xCommandDefinitions
->getByName(_rName
),UNO_QUERY
);
337 return implCreateWrapper(xObject
);
340 Reference
< XContent
> OQueryContainer::implCreateWrapper(const Reference
< XContent
>& _rxCommandDesc
)
342 Reference
<XNameContainer
> xContainer(_rxCommandDesc
,UNO_QUERY
);
343 Reference
< XContent
> xReturn
;
344 if ( xContainer
.is() )
346 xReturn
= new OQueryContainer( xContainer
, m_xConnection
, m_aContext
.getLegacyServiceFactory(), m_pWarnings
);
350 OQuery
* pNewObject
= new OQuery( Reference
< XPropertySet
>( _rxCommandDesc
, UNO_QUERY
), m_xConnection
, m_aContext
.getLegacyServiceFactory() );
351 xReturn
= pNewObject
;
353 pNewObject
->setWarningsContainer( m_pWarnings
);
354 // pNewObject->getColumns();
355 // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the
356 // QueryInQuery test in dbaccess/qa/complex/dbaccess ...
362 Reference
< XContent
> OQueryContainer::createObject( const ::rtl::OUString
& _rName
)
364 return implCreateWrapper(_rName
);
367 sal_Bool
OQueryContainer::checkExistence(const ::rtl::OUString
& _rName
)
369 sal_Bool bRet
= sal_False
;
370 if ( !m_bInPropertyChange
)
372 bRet
= m_xCommandDefinitions
->hasByName(_rName
);
373 Documents::iterator aFind
= m_aDocumentMap
.find(_rName
);
374 if ( !bRet
&& aFind
!= m_aDocumentMap
.end() )
376 m_aDocuments
.erase( ::std::find(m_aDocuments
.begin(),m_aDocuments
.end(),aFind
));
377 m_aDocumentMap
.erase(aFind
);
379 else if ( bRet
&& aFind
== m_aDocumentMap
.end() )
381 implAppend(_rName
,NULL
);
387 sal_Bool SAL_CALL
OQueryContainer::hasElements( ) throw (RuntimeException
)
389 MutexGuard
aGuard(m_aMutex
);
390 return m_xCommandDefinitions
->hasElements();
393 sal_Int32 SAL_CALL
OQueryContainer::getCount( ) throw(RuntimeException
)
395 MutexGuard
aGuard(m_aMutex
);
396 return Reference
<XIndexAccess
>(m_xCommandDefinitions
,UNO_QUERY
)->getCount();
399 Sequence
< ::rtl::OUString
> SAL_CALL
OQueryContainer::getElementNames( ) throw(RuntimeException
)
401 MutexGuard
aGuard(m_aMutex
);
403 return m_xCommandDefinitions
->getElementNames();
406 } // namespace dbaccess
407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */