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