LibreOffice Module dbaccess (master) 1
querycontainer.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <querycontainer.hxx>
21#include "query.hxx"
22#include <strings.hxx>
24#include <veto.hxx>
25
26#include <com/sun/star/beans/XPropertySet.hpp>
27#include <com/sun/star/container/XContainer.hpp>
28#include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
29#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
30#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
31#include <com/sun/star/sdbc/XConnection.hpp>
32#include <com/sun/star/sdb/QueryDefinition.hpp>
33
34#include <osl/diagnose.h>
35#include <comphelper/uno3.hxx>
37#include <comphelper/types.hxx>
39
40using namespace dbtools;
41using namespace ::com::sun::star::uno;
42using namespace ::com::sun::star::ucb;
43using namespace ::com::sun::star::lang;
44using namespace ::com::sun::star::beans;
45using namespace ::com::sun::star::sdb;
46using namespace ::com::sun::star::sdbc;
47using namespace ::com::sun::star::sdbcx;
48using namespace ::com::sun::star::container;
49using namespace ::com::sun::star::util;
50using namespace ::osl;
51using namespace ::comphelper;
52using namespace ::cppu;
53
54namespace dbaccess
55{
56
57// OQueryContainer
58
60 const Reference< XNameContainer >& _rxCommandDefinitions
61 , const Reference< XConnection >& _rxConn
62 , const Reference< XComponentContext >& _rxORB,
65 ,m_pWarnings( _pWarnings )
66 ,m_xCommandDefinitions(_rxCommandDefinitions)
67 ,m_xConnection(_rxConn)
68 ,m_eDoingCurrently(AggregateAction::NONE)
69{
70}
71
73{
74 Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY_THROW );
75 xContainer->addContainerListener( this );
76
77 Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY_THROW );
78 xContainerApprove->addContainerApproveListener( this );
79
80 // fill my structures
82 Sequence< OUString > sDefinitionNames = m_xCommandDefinitions->getElementNames();
83 const OUString* pDefinitionName = sDefinitionNames.getConstArray();
84 const OUString* pEnd = pDefinitionName + sDefinitionNames.getLength();
85 for ( ; pDefinitionName != pEnd; ++pDefinitionName )
86 {
87 rDefinitions.insert( *pDefinitionName, TContentPtr() );
88 m_aDocuments.push_back(m_aDocumentMap.emplace( *pDefinitionName,Documents::mapped_type()).first);
89 }
90
91 setElementApproval( std::make_shared<ObjectNameApproval>( m_xConnection, ObjectNameApproval::TypeQuery ) );
92}
93
95 const Reference< XNameContainer >& _rxCommandDefinitions
96 , const Reference< XConnection >& _rxConn
97 , const Reference< XComponentContext >& _rxORB,
99{
101 new OQueryContainer(
102 _rxCommandDefinitions, _rxConn, _rxORB, _pWarnings));
103 c->init();
104 return c;
105}
106
108{
109 // dispose();
110 // maybe we're already disposed, but this should be uncritical
111}
112
114
116
117void OQueryContainer::disposing()
118{
120 MutexGuard aGuard(m_aMutex);
121 if ( !m_xCommandDefinitions.is() )
122 // already disposed
123 return;
124
125 Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY );
126 xContainer->removeContainerListener( this );
127 Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY );
128 xContainerApprove->removeContainerApproveListener( this );
129
130 m_xCommandDefinitions = nullptr;
131 m_xConnection = nullptr;
132}
133
134// XServiceInfo
136 {
137 return "com.sun.star.sdb.dbaccess.OQueryContainer";
138 }
139sal_Bool SAL_CALL OQueryContainer::supportsService(const OUString& _rServiceName)
140 {
141 const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
142 for (const OUString& s : aSupported)
143 if (s == _rServiceName)
144 return true;
145
146 return false;
147 }
148css::uno::Sequence< OUString > SAL_CALL OQueryContainer::getSupportedServiceNames()
149{
151}
152
153// XDataDescriptorFactory
154Reference< XPropertySet > SAL_CALL OQueryContainer::createDataDescriptor( )
155{
156 return new OQueryDescriptor();
157}
158
159// XAppend
160void SAL_CALL OQueryContainer::appendByDescriptor( const Reference< XPropertySet >& _rxDesc )
161{
162 ResettableMutexGuard aGuard(m_aMutex);
163 if ( !m_xCommandDefinitions.is() )
164 throw DisposedException( OUString(), *this );
165
166 // first clone this object's CommandDefinition part
167 Reference< css::sdb::XQueryDefinition > xCommandDefinitionPart = css::sdb::QueryDefinition::create(m_aContext);
168
169 ::comphelper::copyProperties( _rxDesc, Reference<XPropertySet>(xCommandDefinitionPart, UNO_QUERY_THROW) );
170 // TODO : the columns part of the descriptor has to be copied
171
172 // create a wrapper for the object (*before* inserting into our command definition container)
173 Reference< XContent > xNewObject( implCreateWrapper( Reference< XContent>( xCommandDefinitionPart, UNO_QUERY_THROW ) ) );
174
175 OUString sNewObjectName;
176 _rxDesc->getPropertyValue(PROPERTY_NAME) >>= sNewObjectName;
177
178 try
179 {
180 notifyByName( aGuard, sNewObjectName, xNewObject, nullptr, E_INSERTED, ApproveListeners );
181 }
182 catch (const WrappedTargetException& e)
183 {
184 disposeComponent( xNewObject );
185 disposeComponent( xCommandDefinitionPart );
186 throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
187 }
188 catch (const Exception&)
189 {
190 disposeComponent( xNewObject );
191 disposeComponent( xCommandDefinitionPart );
192 throw;
193 }
194
195 // insert the basic object into the definition container
196 {
198 OAutoActionReset aAutoReset(*this);
199 m_xCommandDefinitions->insertByName(sNewObjectName, Any(xCommandDefinitionPart));
200 }
201
202 implAppend( sNewObjectName, xNewObject );
203 try
204 {
205 notifyByName( aGuard, sNewObjectName, xNewObject, nullptr, E_INSERTED, ContainerListemers );
206 }
207 catch (const WrappedTargetException& e)
208 {
209 throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
210 }
211}
212
213// XDrop
214void SAL_CALL OQueryContainer::dropByName( const OUString& _rName )
215{
216 MutexGuard aGuard(m_aMutex);
217 if ( !checkExistence(_rName) )
218 throw NoSuchElementException(_rName,*this);
219
220 if ( !m_xCommandDefinitions.is() )
221 throw DisposedException( OUString(), *this );
222
223 // now simply forward the remove request to the CommandDefinition container, we're a listener for the removal
224 // and thus we do everything necessary in ::elementRemoved
225 m_xCommandDefinitions->removeByName(_rName);
226}
227
228void SAL_CALL OQueryContainer::dropByIndex( sal_Int32 _nIndex )
229{
230 MutexGuard aGuard(m_aMutex);
231 if ((_nIndex<0) || (_nIndex>getCount()))
232 throw IndexOutOfBoundsException();
233
234 if ( !m_xCommandDefinitions.is() )
235 throw DisposedException( OUString(), *this );
236
237 OUString sName;
238 Reference<XPropertySet> xProp(Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY_THROW)->getByIndex(_nIndex),UNO_QUERY);
239 if ( xProp.is() )
240 xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
241
243}
244
245void SAL_CALL OQueryContainer::elementInserted( const css::container::ContainerEvent& _rEvent )
246{
247 Reference< XContent > xNewElement;
248 OUString sElementName;
249 _rEvent.Accessor >>= sElementName;
250 {
251 MutexGuard aGuard(m_aMutex);
253 // nothing to do, we're inserting via an "appendByDescriptor"
254 return;
255
256 OSL_ENSURE(!sElementName.isEmpty(), "OQueryContainer::elementInserted : invalid name !");
257 OSL_ENSURE(m_aDocumentMap.find(sElementName) == m_aDocumentMap.end(), "OQueryContainer::elementInserted : oops... we're inconsistent with our master container !");
258 if (sElementName.isEmpty() || hasByName(sElementName))
259 return;
260
261 // insert an own new element
262 xNewElement = implCreateWrapper(sElementName);
263 }
264 insertByName(sElementName,Any(xNewElement));
265}
266
267void SAL_CALL OQueryContainer::elementRemoved( const css::container::ContainerEvent& _rEvent )
268{
269 OUString sAccessor;
270 _rEvent.Accessor >>= sAccessor;
271 {
272 OSL_ENSURE(!sAccessor.isEmpty(), "OQueryContainer::elementRemoved : invalid name !");
273 OSL_ENSURE(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementRemoved : oops... we're inconsistent with our master container !");
274 if ( sAccessor.isEmpty() || !hasByName(sAccessor) )
275 return;
276 }
277 removeByName(sAccessor);
278}
279
280void SAL_CALL OQueryContainer::elementReplaced( const css::container::ContainerEvent& _rEvent )
281{
282 Reference< XContent > xNewElement;
283 OUString sAccessor;
284 _rEvent.Accessor >>= sAccessor;
285
286 {
287 MutexGuard aGuard(m_aMutex);
288 OSL_ENSURE(!sAccessor.isEmpty(), "OQueryContainer::elementReplaced : invalid name !");
289 OSL_ENSURE(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementReplaced : oops... we're inconsistent with our master container !");
290 if (sAccessor.isEmpty() || !hasByName(sAccessor))
291 return;
292
293 xNewElement = implCreateWrapper(sAccessor);
294 }
295
296 replaceByName(sAccessor,Any(xNewElement));
297}
298
299Reference< XVeto > SAL_CALL OQueryContainer::approveInsertElement( const ContainerEvent& Event )
300{
301 OUString sName;
302 OSL_VERIFY( Event.Accessor >>= sName );
303 Reference< XContent > xElement( Event.Element, UNO_QUERY_THROW );
304
305 Reference< XVeto > xReturn;
306 try
307 {
308 getElementApproval()->approveElement( sName );
309 }
310 catch( const Exception& )
311 {
312 xReturn = new Veto( ::cppu::getCaughtException() );
313 }
314 return xReturn;
315}
316
317Reference< XVeto > SAL_CALL OQueryContainer::approveReplaceElement( const ContainerEvent& /*Event*/ )
318{
319 return nullptr;
320}
321
322Reference< XVeto > SAL_CALL OQueryContainer::approveRemoveElement( const ContainerEvent& /*Event*/ )
323{
324 return nullptr;
325}
326
327void SAL_CALL OQueryContainer::disposing( const css::lang::EventObject& _rSource )
328{
329 if (_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinitions, UNO_QUERY).get())
330 { // our "master container" (with the command definitions) is being disposed
331 OSL_FAIL("OQueryContainer::disposing : nobody should dispose the CommandDefinition container before disposing my connection !");
332 dispose();
333 }
334 else
335 {
336 Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
337 // it's one of our documents...
338 for (auto const& document : m_aDocumentMap)
339 {
340 if ( xSource == document.second.get() )
341 {
342 m_xCommandDefinitions->removeByName(document.first);
343 break;
344 }
345 }
347 }
348}
349
351{
352 return "application/vnd.org.openoffice.DatabaseQueryContainer";
353}
354
355Reference< XContent > OQueryContainer::implCreateWrapper(const OUString& _rName)
356{
357 Reference< XContent > xObject(m_xCommandDefinitions->getByName(_rName),UNO_QUERY);
358 return implCreateWrapper(xObject);
359}
360
361Reference< XContent > OQueryContainer::implCreateWrapper(const Reference< XContent >& _rxCommandDesc)
362{
363 Reference<XNameContainer> xContainer(_rxCommandDesc,UNO_QUERY);
364 Reference< XContent > xReturn;
365 if ( xContainer .is() )
366 {
367 xReturn = create( xContainer, m_xConnection, m_aContext, m_pWarnings ).
368 get();
369 }
370 else
371 {
372 rtl::Reference<OQuery> pNewObject = new OQuery( Reference< XPropertySet >( _rxCommandDesc, UNO_QUERY ), m_xConnection, m_aContext );
373 xReturn = pNewObject;
374
375 pNewObject->setWarningsContainer( m_pWarnings );
376// pNewObject->getColumns();
377 // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the
378 // QueryInQuery test in dbaccess/qa/complex/dbaccess ...
379 }
380
381 return xReturn;
382}
383
384Reference< XContent > OQueryContainer::createObject( const OUString& _rName)
385{
386 return implCreateWrapper(_rName);
387}
388
389bool OQueryContainer::checkExistence(const OUString& _rName)
390{
391 bool bRet = false;
392 if ( !m_bInPropertyChange )
393 {
394 bRet = m_xCommandDefinitions->hasByName(_rName);
395 Documents::const_iterator aFind = m_aDocumentMap.find(_rName);
396 if ( !bRet && aFind != m_aDocumentMap.end() )
397 {
398 m_aDocuments.erase( std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
399 m_aDocumentMap.erase(aFind);
400 }
401 else if ( bRet && aFind == m_aDocumentMap.end() )
402 {
403 implAppend(_rName,nullptr);
404 }
405 }
406 return bRet;
407}
408
410{
411 MutexGuard aGuard(m_aMutex);
412 return m_xCommandDefinitions->hasElements();
413}
414
415sal_Int32 SAL_CALL OQueryContainer::getCount( )
416{
417 MutexGuard aGuard(m_aMutex);
418 return Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY_THROW)->getCount();
419}
420
421Sequence< OUString > SAL_CALL OQueryContainer::getElementNames( )
422{
423 MutexGuard aGuard(m_aMutex);
424
425 return m_xCommandDefinitions->getElementNames();
426}
427
428} // namespace dbaccess
429
430/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OptionalString sName
mutable::osl::Mutex m_aMutex
const css::uno::Reference< css::uno::XComponentContext > m_aContext
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
void insert(const OUString &_rName, TContentPtr _pDefinition)
const ODefinitionContainer_Impl & getDefinitions() const
void implAppend(const OUString &_rName, const css::uno::Reference< css::ucb::XContent > &_rxNewObject)
append a new object to the container.
virtual void SAL_CALL replaceByName(const OUString &_rName, const css::uno::Any &aElement) override
virtual sal_Bool SAL_CALL hasByName(const OUString &aName) override
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
void notifyByName(::osl::ResettableMutexGuard &_rGuard, const OUString &_rName, const css::uno::Reference< css::ucb::XContent > &_xNewElement, const css::uno::Reference< css::ucb::XContent > &xOldElement, ContainerOperation _eOperation, ListenerType _eType)
notifies our container/approve listeners
virtual void SAL_CALL insertByName(const OUString &_rName, const css::uno::Any &aElement) override
virtual void SAL_CALL disposing() override
virtual OUString SAL_CALL getImplementationName() override
const PContainerApprove & getElementApproval() const
virtual css::uno::Any SAL_CALL getByIndex(sal_Int32 _nIndex) override
virtual void SAL_CALL removeByName(const OUString &_rName) override
std::vector< Documents::iterator > m_aDocuments
void setElementApproval(PContainerApprove _pElementApproval)
Additionally to our own approvals which new elements must pass, derived classes can specify an additi...
virtual sal_Bool SAL_CALL hasElements() override
static rtl::Reference< OQueryContainer > create(const css::uno::Reference< css::container::XNameContainer > &_rxCommandDefinitions, const css::uno::Reference< css::sdbc::XConnection > &_rxConn, const css::uno::Reference< css::uno::XComponentContext > &_rxORB, ::dbtools::WarningsContainer *_pWarnings)
css::uno::Reference< css::container::XNameContainer > m_xCommandDefinitions
virtual void SAL_CALL dropByName(const OUString &elementName) override
virtual bool checkExistence(const OUString &_rName) override
quickly checks if there already is an element with a given name.
virtual css::uno::Reference< css::ucb::XContent > createObject(const OUString &_rName) override
create an object from its persistent data within the configuration.
virtual void SAL_CALL appendByDescriptor(const css::uno::Reference< css::beans::XPropertySet > &descriptor) override
css::uno::Reference< css::ucb::XContent > implCreateWrapper(const OUString &_rName)
create a query object wrapping a CommandDefinition given by name.
virtual ~OQueryContainer() override
virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveRemoveElement(const css::container::ContainerEvent &Event) override
virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor() override
virtual void SAL_CALL disposing() override
css::uno::Reference< css::sdbc::XConnection > m_xConnection
virtual void SAL_CALL elementInserted(const css::container::ContainerEvent &Event) override
virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveReplaceElement(const css::container::ContainerEvent &Event) override
virtual sal_Int32 SAL_CALL getCount() override
virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent &Event) override
virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override
virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent &Event) override
virtual void SAL_CALL dropByIndex(sal_Int32 index) override
virtual OUString determineContentType() const override
AggregateAction m_eDoingCurrently
::dbtools::WarningsContainer * m_pWarnings
OQueryContainer(const css::uno::Reference< css::container::XNameContainer > &_rxCommandDefinitions, const css::uno::Reference< css::sdbc::XConnection > &_rxConn, const css::uno::Reference< css::uno::XComponentContext > &_rxORB, ::dbtools::WarningsContainer *_pWarnings)
ctor of the container.
virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveInsertElement(const css::container::ContainerEvent &Event) override
implements css::util::XVeto
Definition: veto.hxx:35
std::mutex m_aMutex
NONE
@ Exception
void disposeComponent(css::uno::Reference< TYPE > &_rxComp)
std::shared_ptr< OContentHelper_Impl > TContentPtr
std::shared_ptr< T > make_shared(Args &&... args)
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
void dispose()
Reference< XConnection > m_xConnection
Definition: objectnames.cxx:79
IMPLEMENT_FORWARD_XTYPEPROVIDER2(OStatement, OStatementBase, OStatement_IFACE)
IMPLEMENT_FORWARD_XINTERFACE2(OStatement, OStatementBase, OStatement_IFACE)
constexpr OUStringLiteral SERVICE_SDBCX_CONTAINER
Definition: strings.hxx:171
constexpr OUStringLiteral SERVICE_SDB_QUERIES
Definition: strings.hxx:194
constexpr OUStringLiteral PROPERTY_NAME(u"Name")
unsigned char sal_Bool