Line data Source code
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 :
21 : #include "querycontainer.hxx"
22 : #include "dbastrings.hrc"
23 : #include "query.hxx"
24 : #include "objectnameapproval.hxx"
25 : #include "ContainerListener.hxx"
26 : #include "veto.hxx"
27 :
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>
32 :
33 : #include <connectivity/dbexception.hxx>
34 :
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>
43 :
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;
57 :
58 : namespace dbaccess
59 : {
60 :
61 : //==========================================================================
62 : //= OQueryContainer
63 : //==========================================================================
64 : DBG_NAME(OQueryContainer)
65 :
66 0 : OQueryContainer::OQueryContainer(
67 : const Reference< XNameContainer >& _rxCommandDefinitions
68 : , const Reference< XConnection >& _rxConn
69 : , const Reference< XMultiServiceFactory >& _rxORB,
70 : ::dbtools::IWarningsContainer* _pWarnings)
71 0 : :ODefinitionContainer(_rxORB,NULL,TContentPtr(new ODefinitionContainer_Impl))
72 : ,m_pWarnings( _pWarnings )
73 : ,m_xCommandDefinitions(_rxCommandDefinitions)
74 0 : ,m_xConnection(_rxConn)
75 : {
76 : DBG_CTOR(OQueryContainer, NULL);
77 :
78 0 : increment(m_refCount);
79 : {
80 0 : m_pCommandsListener = new OContainerListener( *this, m_aMutex );
81 0 : m_pCommandsListener->acquire();
82 :
83 0 : Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY_THROW );
84 0 : xContainer->addContainerListener( m_pCommandsListener );
85 :
86 0 : Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY_THROW );
87 0 : xContainerApprove->addContainerApproveListener( m_pCommandsListener );
88 :
89 : // fill my structures
90 0 : ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
91 0 : Sequence< ::rtl::OUString > sDefinitionNames = m_xCommandDefinitions->getElementNames();
92 0 : const ::rtl::OUString* pDefinitionName = sDefinitionNames.getConstArray();
93 0 : const ::rtl::OUString* pEnd = pDefinitionName + sDefinitionNames.getLength();
94 0 : for ( ; pDefinitionName != pEnd; ++pDefinitionName )
95 : {
96 0 : rDefinitions.insert( *pDefinitionName, TContentPtr() );
97 0 : m_aDocuments.push_back(m_aDocumentMap.insert(Documents::value_type(*pDefinitionName,Documents::mapped_type())).first);
98 0 : }
99 : }
100 0 : decrement(m_refCount);
101 :
102 0 : setElementApproval( PContainerApprove( new ObjectNameApproval( _rxConn, ObjectNameApproval::TypeQuery ) ) );
103 0 : }
104 :
105 0 : OQueryContainer::~OQueryContainer()
106 : {
107 : DBG_DTOR(OQueryContainer, NULL);
108 : // dispose();
109 : // maybe we're already disposed, but this should be uncritical
110 0 : }
111 :
112 0 : IMPLEMENT_FORWARD_XINTERFACE2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
113 :
114 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
115 :
116 0 : void OQueryContainer::disposing()
117 : {
118 0 : ODefinitionContainer::disposing();
119 0 : MutexGuard aGuard(m_aMutex);
120 0 : if ( !m_xCommandDefinitions.is() )
121 : // already disposed
122 0 : return;
123 :
124 0 : if ( m_pCommandsListener )
125 : {
126 0 : Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY );
127 0 : xContainer->removeContainerListener( m_pCommandsListener );
128 0 : Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY );
129 0 : xContainerApprove->removeContainerApproveListener( m_pCommandsListener );
130 :
131 0 : m_pCommandsListener->dispose();
132 0 : m_pCommandsListener->release();
133 0 : m_pCommandsListener = NULL;
134 : }
135 :
136 0 : m_xCommandDefinitions = NULL;
137 0 : m_xConnection = NULL;
138 : }
139 :
140 : // XServiceInfo
141 0 : IMPLEMENT_SERVICE_INFO2(OQueryContainer, "com.sun.star.sdb.dbaccess.OQueryContainer", SERVICE_SDBCX_CONTAINER.ascii, SERVICE_SDB_QUERIES.ascii)
142 :
143 : // XDataDescriptorFactory
144 0 : Reference< XPropertySet > SAL_CALL OQueryContainer::createDataDescriptor( ) throw(RuntimeException)
145 : {
146 0 : return new OQueryDescriptor();
147 : }
148 :
149 : // XAppend
150 0 : void SAL_CALL OQueryContainer::appendByDescriptor( const Reference< XPropertySet >& _rxDesc ) throw(SQLException, ElementExistException, RuntimeException)
151 : {
152 0 : ResettableMutexGuard aGuard(m_aMutex);
153 0 : if ( !m_xCommandDefinitions.is() )
154 0 : throw DisposedException( ::rtl::OUString(), *this );
155 :
156 : // first clone this object's CommandDefinition part
157 0 : Reference< XPropertySet > xCommandDefinitionPart( m_aContext.createComponent( (::rtl::OUString)SERVICE_SDB_QUERYDEFINITION ), UNO_QUERY_THROW );
158 0 : ::comphelper::copyProperties( _rxDesc, xCommandDefinitionPart );
159 : // TODO : the columns part of the descriptor has to be copied
160 :
161 : // create a wrapper for the object (*before* inserting into our command definition container)
162 0 : Reference< XContent > xNewObject( implCreateWrapper( Reference< XContent>( xCommandDefinitionPart, UNO_QUERY_THROW ) ) );
163 :
164 0 : ::rtl::OUString sNewObjectName;
165 0 : _rxDesc->getPropertyValue(PROPERTY_NAME) >>= sNewObjectName;
166 :
167 : try
168 : {
169 0 : notifyByName( aGuard, sNewObjectName, xNewObject, NULL, E_INSERTED, ApproveListeners );
170 : }
171 0 : catch( const Exception& )
172 : {
173 0 : disposeComponent( xNewObject );
174 0 : disposeComponent( xCommandDefinitionPart );
175 0 : throw;
176 : }
177 :
178 : // insert the basic object into the definition container
179 : {
180 0 : m_eDoingCurrently = INSERTING;
181 0 : OAutoActionReset aAutoReset(this);
182 0 : m_xCommandDefinitions->insertByName(sNewObjectName, makeAny(xCommandDefinitionPart));
183 : }
184 :
185 0 : implAppend( sNewObjectName, xNewObject );
186 0 : notifyByName( aGuard, sNewObjectName, xNewObject, NULL, E_INSERTED, ContainerListemers );
187 0 : }
188 :
189 : // XDrop
190 0 : void SAL_CALL OQueryContainer::dropByName( const ::rtl::OUString& _rName ) throw(SQLException, NoSuchElementException, RuntimeException)
191 : {
192 0 : MutexGuard aGuard(m_aMutex);
193 0 : if ( !checkExistence(_rName) )
194 0 : throw NoSuchElementException(_rName,*this);
195 :
196 0 : if ( !m_xCommandDefinitions.is() )
197 0 : throw DisposedException( ::rtl::OUString(), *this );
198 :
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 0 : m_xCommandDefinitions->removeByName(_rName);
202 0 : }
203 :
204 0 : void SAL_CALL OQueryContainer::dropByIndex( sal_Int32 _nIndex ) throw(SQLException, IndexOutOfBoundsException, RuntimeException)
205 : {
206 0 : MutexGuard aGuard(m_aMutex);
207 0 : if ((_nIndex<0) || (_nIndex>getCount()))
208 0 : throw IndexOutOfBoundsException();
209 :
210 0 : if ( !m_xCommandDefinitions.is() )
211 0 : throw DisposedException( ::rtl::OUString(), *this );
212 :
213 0 : ::rtl::OUString sName;
214 0 : Reference<XPropertySet> xProp(Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY)->getByIndex(_nIndex),UNO_QUERY);
215 0 : if ( xProp.is() )
216 0 : xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
217 :
218 0 : dropByName(sName);
219 0 : }
220 :
221 0 : void SAL_CALL OQueryContainer::elementInserted( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException)
222 : {
223 0 : Reference< XContent > xNewElement;
224 0 : ::rtl::OUString sElementName;
225 0 : _rEvent.Accessor >>= sElementName;
226 : {
227 0 : MutexGuard aGuard(m_aMutex);
228 0 : if (INSERTING == m_eDoingCurrently)
229 : // nothing to do, we're inserting via an "appendByDescriptor"
230 : return;
231 :
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 0 : if (sElementName.isEmpty() || hasByName(sElementName))
235 : return;
236 :
237 : // insert an own new element
238 0 : xNewElement = implCreateWrapper(sElementName);
239 : }
240 0 : insertByName(sElementName,makeAny(xNewElement));
241 : }
242 :
243 0 : void SAL_CALL OQueryContainer::elementRemoved( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException)
244 : {
245 0 : ::rtl::OUString sAccessor;
246 0 : _rEvent.Accessor >>= sAccessor;
247 : {
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 0 : if ( sAccessor.isEmpty() || !hasByName(sAccessor) )
251 0 : return;
252 : }
253 0 : removeByName(sAccessor);
254 : }
255 :
256 0 : void SAL_CALL OQueryContainer::elementReplaced( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException)
257 : {
258 0 : Reference< XPropertySet > xReplacedElement;
259 0 : Reference< XContent > xNewElement;
260 0 : ::rtl::OUString sAccessor;
261 0 : _rEvent.Accessor >>= sAccessor;
262 :
263 : {
264 0 : 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 0 : if (sAccessor.isEmpty() || !hasByName(sAccessor))
268 0 : return;
269 :
270 0 : xNewElement = implCreateWrapper(sAccessor);
271 : }
272 :
273 0 : replaceByName(sAccessor,makeAny(xNewElement));
274 : }
275 :
276 0 : Reference< XVeto > SAL_CALL OQueryContainer::approveInsertElement( const ContainerEvent& Event ) throw (WrappedTargetException, RuntimeException)
277 : {
278 0 : ::rtl::OUString sName;
279 0 : OSL_VERIFY( Event.Accessor >>= sName );
280 0 : Reference< XContent > xElement( Event.Element, UNO_QUERY_THROW );
281 :
282 0 : Reference< XVeto > xReturn;
283 : try
284 : {
285 0 : getElementApproval()->approveElement( sName, xElement.get() );
286 : }
287 0 : catch( const Exception& )
288 : {
289 0 : xReturn = new Veto( ::rtl::OUString(), ::cppu::getCaughtException() );
290 : }
291 0 : return xReturn;
292 : }
293 :
294 0 : Reference< XVeto > SAL_CALL OQueryContainer::approveReplaceElement( const ContainerEvent& /*Event*/ ) throw (WrappedTargetException, RuntimeException)
295 : {
296 0 : return NULL;
297 : }
298 :
299 0 : Reference< XVeto > SAL_CALL OQueryContainer::approveRemoveElement( const ContainerEvent& /*Event*/ ) throw (WrappedTargetException, RuntimeException)
300 : {
301 0 : return NULL;
302 : }
303 :
304 0 : void SAL_CALL OQueryContainer::disposing( const ::com::sun::star::lang::EventObject& _rSource ) throw(::com::sun::star::uno::RuntimeException)
305 : {
306 0 : 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 !");
309 0 : dispose();
310 : }
311 : else
312 : {
313 0 : Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
314 : // it's one of our documents ....
315 0 : Documents::iterator aIter = m_aDocumentMap.begin();
316 0 : Documents::iterator aEnd = m_aDocumentMap.end();
317 0 : for (;aIter != aEnd;++aIter )
318 : {
319 0 : if ( xSource == aIter->second.get() )
320 : {
321 0 : m_xCommandDefinitions->removeByName(aIter->first);
322 0 : break;
323 : }
324 : }
325 0 : ODefinitionContainer::disposing(_rSource);
326 : }
327 0 : }
328 :
329 0 : ::rtl::OUString OQueryContainer::determineContentType() const
330 : {
331 0 : return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQueryContainer" ) );
332 : }
333 :
334 0 : Reference< XContent > OQueryContainer::implCreateWrapper(const ::rtl::OUString& _rName)
335 : {
336 0 : Reference< XContent > xObject(m_xCommandDefinitions->getByName(_rName),UNO_QUERY);
337 0 : return implCreateWrapper(xObject);
338 : }
339 :
340 0 : Reference< XContent > OQueryContainer::implCreateWrapper(const Reference< XContent >& _rxCommandDesc)
341 : {
342 0 : Reference<XNameContainer> xContainer(_rxCommandDesc,UNO_QUERY);
343 0 : Reference< XContent > xReturn;
344 0 : if ( xContainer .is() )
345 : {
346 0 : xReturn = new OQueryContainer( xContainer, m_xConnection, m_aContext.getLegacyServiceFactory(), m_pWarnings );
347 : }
348 : else
349 : {
350 0 : OQuery* pNewObject = new OQuery( Reference< XPropertySet >( _rxCommandDesc, UNO_QUERY ), m_xConnection, m_aContext.getLegacyServiceFactory() );
351 0 : xReturn = pNewObject;
352 :
353 0 : 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 ...
357 : }
358 :
359 0 : return xReturn;
360 : }
361 :
362 0 : Reference< XContent > OQueryContainer::createObject( const ::rtl::OUString& _rName)
363 : {
364 0 : return implCreateWrapper(_rName);
365 : }
366 :
367 0 : sal_Bool OQueryContainer::checkExistence(const ::rtl::OUString& _rName)
368 : {
369 0 : sal_Bool bRet = sal_False;
370 0 : if ( !m_bInPropertyChange )
371 : {
372 0 : bRet = m_xCommandDefinitions->hasByName(_rName);
373 0 : Documents::iterator aFind = m_aDocumentMap.find(_rName);
374 0 : if ( !bRet && aFind != m_aDocumentMap.end() )
375 : {
376 0 : m_aDocuments.erase( ::std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
377 0 : m_aDocumentMap.erase(aFind);
378 : }
379 0 : else if ( bRet && aFind == m_aDocumentMap.end() )
380 : {
381 0 : implAppend(_rName,NULL);
382 : }
383 : }
384 0 : return bRet;
385 : }
386 :
387 0 : sal_Bool SAL_CALL OQueryContainer::hasElements( ) throw (RuntimeException)
388 : {
389 0 : MutexGuard aGuard(m_aMutex);
390 0 : return m_xCommandDefinitions->hasElements();
391 : }
392 :
393 0 : sal_Int32 SAL_CALL OQueryContainer::getCount( ) throw(RuntimeException)
394 : {
395 0 : MutexGuard aGuard(m_aMutex);
396 0 : return Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY)->getCount();
397 : }
398 :
399 0 : Sequence< ::rtl::OUString > SAL_CALL OQueryContainer::getElementNames( ) throw(RuntimeException)
400 : {
401 0 : MutexGuard aGuard(m_aMutex);
402 :
403 0 : return m_xCommandDefinitions->getElementNames();
404 : }
405 :
406 : } // namespace dbaccess
407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|