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