1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_dbaccess.hxx"
30 
31 #ifndef _DBA_CORE_QUERYCONTAINER_HXX_
32 #include "querycontainer.hxx"
33 #endif
34 #ifndef DBACCESS_SHARED_DBASTRINGS_HRC
35 #include "dbastrings.hrc"
36 #endif
37 #ifndef _DBA_COREAPI_QUERY_HXX_
38 #include "query.hxx"
39 #endif
40 #ifndef DBACCESS_OBJECTNAMEAPPROVAL_HXX
41 #include "objectnameapproval.hxx"
42 #endif
43 #ifndef DBA_CONTAINERLISTENER_HXX
44 #include "ContainerListener.hxx"
45 #endif
46 #ifndef DBACCESS_VETO_HXX
47 #include "veto.hxx"
48 #endif
49 
50 /** === begin UNO includes === **/
51 #ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
52 #include <com/sun/star/beans/XPropertySet.hpp>
53 #endif
54 #ifndef _COM_SUN_STAR_CONTAINER_XCONTAINER_HPP_
55 #include <com/sun/star/container/XContainer.hpp>
56 #endif
57 #ifndef _COM_SUN_STAR_SDBC_XCONNECTION_HPP_
58 #include <com/sun/star/sdbc/XConnection.hpp>
59 #endif
60 #ifndef _COM_SUN_STAR_CONTAINER_XCONTAINERAPPROVEBROADCASTER_HPP_
61 #include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
62 #endif
63 /** === end UNO includes === **/
64 
65 #ifndef _DBHELPER_DBEXCEPTION_HXX_
66 #include <connectivity/dbexception.hxx>
67 #endif
68 
69 #ifndef _TOOLS_DEBUG_HXX
70 #include <tools/debug.hxx>
71 #endif
72 #ifndef _COMPHELPER_ENUMHELPER_HXX_
73 #include <comphelper/enumhelper.hxx>
74 #endif
75 #ifndef _COMPHELPER_UNO3_HXX_
76 #include <comphelper/uno3.hxx>
77 #endif
78 #ifndef _COMPHELPER_PROPERTY_HXX_
79 #include <comphelper/property.hxx>
80 #endif
81 #ifndef _COMPHELPER_SEQUENCE_HXX_
82 #include <comphelper/sequence.hxx>
83 #endif
84 #ifndef _COMPHELPER_EXTRACT_HXX_
85 #include <comphelper/extract.hxx>
86 #endif
87 #ifndef _CPPUHELPER_EXC_HLP_HXX_
88 #include <cppuhelper/exc_hlp.hxx>
89 #endif
90 
91 using namespace dbtools;
92 using namespace ::com::sun::star::uno;
93 using namespace ::com::sun::star::ucb;
94 using namespace ::com::sun::star::lang;
95 using namespace ::com::sun::star::beans;
96 using namespace ::com::sun::star::sdb;
97 using namespace ::com::sun::star::sdbc;
98 using namespace ::com::sun::star::sdbcx;
99 using namespace ::com::sun::star::container;
100 using namespace ::com::sun::star::util;
101 using namespace ::osl;
102 using namespace ::comphelper;
103 using namespace ::cppu;
104 
105 //........................................................................
106 namespace dbaccess
107 {
108 //........................................................................
109 
110 //==========================================================================
111 //= OQueryContainer
112 //==========================================================================
113 DBG_NAME(OQueryContainer)
114 //------------------------------------------------------------------------------
115 OQueryContainer::OQueryContainer(
116 				  const Reference< XNameContainer >& _rxCommandDefinitions
117 				, const Reference< XConnection >& _rxConn
118 				, const Reference< XMultiServiceFactory >& _rxORB,
119 				::dbtools::IWarningsContainer* _pWarnings)
120 	:ODefinitionContainer(_rxORB,NULL,TContentPtr(new ODefinitionContainer_Impl))
121 	,m_pWarnings( _pWarnings )
122 	,m_xCommandDefinitions(_rxCommandDefinitions)
123 	,m_xConnection(_rxConn)
124 {
125 	DBG_CTOR(OQueryContainer, NULL);
126 
127 	increment(m_refCount);
128 	{
129 	    m_pCommandsListener = new OContainerListener( *this, m_aMutex );
130 	    m_pCommandsListener->acquire();
131 
132 		Reference< XContainer >	xContainer( m_xCommandDefinitions, UNO_QUERY_THROW );
133 		xContainer->addContainerListener( m_pCommandsListener );
134 
135 		Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY_THROW );
136         xContainerApprove->addContainerApproveListener( m_pCommandsListener );
137 
138 		// fill my structures
139 	    ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
140 		Sequence< ::rtl::OUString > sDefinitionNames = m_xCommandDefinitions->getElementNames();
141 		const ::rtl::OUString* pDefinitionName = sDefinitionNames.getConstArray();
142 		const ::rtl::OUString* pEnd = pDefinitionName + sDefinitionNames.getLength();
143 		for ( ; pDefinitionName != pEnd; ++pDefinitionName )
144 		{
145 			rDefinitions.insert( *pDefinitionName, TContentPtr() );
146 			m_aDocuments.push_back(m_aDocumentMap.insert(Documents::value_type(*pDefinitionName,Documents::mapped_type())).first);
147 		}
148 	}
149 	decrement(m_refCount);
150 
151     setElementApproval( PContainerApprove( new ObjectNameApproval( _rxConn, ObjectNameApproval::TypeQuery ) ) );
152 }
153 
154 //------------------------------------------------------------------------------
155 OQueryContainer::~OQueryContainer()
156 {
157 	DBG_DTOR(OQueryContainer, NULL);
158 	//	dispose();
159 		//	maybe we're already disposed, but this should be uncritical
160 }
161 // -----------------------------------------------------------------------------
162 IMPLEMENT_FORWARD_XINTERFACE2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
163 
164 //------------------------------------------------------------------------------
165 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
166 
167 //------------------------------------------------------------------------------
168 void OQueryContainer::disposing()
169 {
170 	ODefinitionContainer::disposing();
171 	MutexGuard aGuard(m_aMutex);
172     if ( !m_xCommandDefinitions.is() )
173         // already disposed
174         return;
175 
176 	if ( m_pCommandsListener )
177     {
178 	    Reference< XContainer >	xContainer( m_xCommandDefinitions, UNO_QUERY );
179 	    xContainer->removeContainerListener( m_pCommandsListener );
180 	    Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY );
181 	    xContainerApprove->removeContainerApproveListener( m_pCommandsListener );
182 
183         m_pCommandsListener->dispose();
184 		m_pCommandsListener->release();
185 	    m_pCommandsListener = NULL;
186     }
187 
188 	m_xCommandDefinitions	= NULL;
189 	m_xConnection			= NULL;
190 }
191 
192 // XServiceInfo
193 //------------------------------------------------------------------------------
194 IMPLEMENT_SERVICE_INFO2(OQueryContainer, "com.sun.star.sdb.dbaccess.OQueryContainer", SERVICE_SDBCX_CONTAINER, SERVICE_SDB_QUERIES)
195 
196 // XDataDescriptorFactory
197 //--------------------------------------------------------------------------
198 Reference< XPropertySet > SAL_CALL OQueryContainer::createDataDescriptor(  ) throw(RuntimeException)
199 {
200 	return new OQueryDescriptor();
201 }
202 
203 // XAppend
204 //------------------------------------------------------------------------------
205 void SAL_CALL OQueryContainer::appendByDescriptor( const Reference< XPropertySet >& _rxDesc ) throw(SQLException, ElementExistException, RuntimeException)
206 {
207 	ResettableMutexGuard aGuard(m_aMutex);
208     if ( !m_xCommandDefinitions.is() )
209         throw DisposedException( ::rtl::OUString(), *this );
210 
211 	// first clone this object's CommandDefinition part
212     Reference< XPropertySet > xCommandDefinitionPart( m_aContext.createComponent( (::rtl::OUString)SERVICE_SDB_QUERYDEFINITION ), UNO_QUERY_THROW );
213 	::comphelper::copyProperties( _rxDesc, xCommandDefinitionPart );
214     // TODO : the columns part of the descriptor has to be copied
215 
216     // create a wrapper for the object (*before* inserting into our command definition container)
217 	Reference< XContent > xNewObject( implCreateWrapper( Reference< XContent>( xCommandDefinitionPart, UNO_QUERY_THROW ) ) );
218 
219 	::rtl::OUString sNewObjectName;
220 	_rxDesc->getPropertyValue(PROPERTY_NAME) >>= sNewObjectName;
221 
222     try
223     {
224         notifyByName( aGuard, sNewObjectName, xNewObject, NULL, E_INSERTED, ApproveListeners );
225     }
226     catch( const Exception& )
227     {
228         disposeComponent( xNewObject );
229         disposeComponent( xCommandDefinitionPart );
230         throw;
231     }
232 
233     // insert the basic object into the definition container
234 	{
235 		m_eDoingCurrently =	INSERTING;
236 		OAutoActionReset aAutoReset(this);
237 		m_xCommandDefinitions->insertByName(sNewObjectName, makeAny(xCommandDefinitionPart));
238 	}
239 
240     implAppend( sNewObjectName, xNewObject );
241 	notifyByName( aGuard, sNewObjectName, xNewObject, NULL, E_INSERTED, ContainerListemers );
242 }
243 
244 // XDrop
245 //------------------------------------------------------------------------------
246 void SAL_CALL OQueryContainer::dropByName( const ::rtl::OUString& _rName ) throw(SQLException, NoSuchElementException, RuntimeException)
247 {
248 	MutexGuard aGuard(m_aMutex);
249 	if ( !checkExistence(_rName) )
250 		throw NoSuchElementException(_rName,*this);
251 
252 	if ( !m_xCommandDefinitions.is() )
253         throw DisposedException( ::rtl::OUString(), *this );
254 
255 	// now simply forward the remove request to the CommandDefinition container, we're a listener for the removal
256 	// and thus we do everything neccessary in ::elementRemoved
257 	m_xCommandDefinitions->removeByName(_rName);
258 }
259 
260 //------------------------------------------------------------------------------
261 void SAL_CALL OQueryContainer::dropByIndex( sal_Int32 _nIndex ) throw(SQLException, IndexOutOfBoundsException, RuntimeException)
262 {
263 	MutexGuard aGuard(m_aMutex);
264 	if ((_nIndex<0) || (_nIndex>getCount()))
265 		throw IndexOutOfBoundsException();
266 
267 	if ( !m_xCommandDefinitions.is() )
268         throw DisposedException( ::rtl::OUString(), *this );
269 
270     ::rtl::OUString sName;
271 	Reference<XPropertySet> xProp(Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY)->getByIndex(_nIndex),UNO_QUERY);
272 	if ( xProp.is() )
273 		xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
274 
275 	dropByName(sName);
276 }
277 //------------------------------------------------------------------------------
278 void SAL_CALL OQueryContainer::elementInserted( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException)
279 {
280 	Reference< XContent > xNewElement;
281 	::rtl::OUString sElementName;
282 	_rEvent.Accessor >>= sElementName;
283 	{
284 		MutexGuard aGuard(m_aMutex);
285 		if (INSERTING == m_eDoingCurrently)
286 			// nothing to do, we're inserting via an "appendByDescriptor"
287 			return;
288 
289 		DBG_ASSERT(sElementName.getLength(), "OQueryContainer::elementInserted : invalid name !");
290 		DBG_ASSERT(m_aDocumentMap.find(sElementName) == m_aDocumentMap.end(), "OQueryContainer::elementInserted         : oops .... we're inconsistent with our master container !");
291 		if (!sElementName.getLength() || hasByName(sElementName))
292 			return;
293 
294 		// insert an own new element
295 		xNewElement = implCreateWrapper(sElementName);
296 	}
297 	insertByName(sElementName,makeAny(xNewElement));
298 }
299 
300 //------------------------------------------------------------------------------
301 void SAL_CALL OQueryContainer::elementRemoved( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException)
302 {
303 	::rtl::OUString sAccessor;
304 	_rEvent.Accessor >>= sAccessor;
305 	{
306 		DBG_ASSERT(sAccessor.getLength(), "OQueryContainer::elementRemoved : invalid name !");
307 		DBG_ASSERT(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementRemoved : oops .... we're inconsistent with our master container !");
308 		if ( !sAccessor.getLength() || !hasByName(sAccessor) )
309 			return;
310 	}
311 	removeByName(sAccessor);
312 }
313 
314 //------------------------------------------------------------------------------
315 void SAL_CALL OQueryContainer::elementReplaced( const ::com::sun::star::container::ContainerEvent& _rEvent ) throw(::com::sun::star::uno::RuntimeException)
316 {
317 	Reference< XPropertySet > xReplacedElement;
318 	Reference< XContent > xNewElement;
319 	::rtl::OUString sAccessor;
320 	_rEvent.Accessor >>= sAccessor;
321 
322 	{
323 		MutexGuard aGuard(m_aMutex);
324 		DBG_ASSERT(sAccessor.getLength(), "OQueryContainer::elementReplaced : invalid name !");
325 		DBG_ASSERT(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementReplaced         : oops .... we're inconsistent with our master container !");
326 		if (!sAccessor.getLength() || !hasByName(sAccessor))
327 			return;
328 
329 		xNewElement = implCreateWrapper(sAccessor);
330 	}
331 
332 	replaceByName(sAccessor,makeAny(xNewElement));
333 }
334 
335 //------------------------------------------------------------------------------
336 Reference< XVeto > SAL_CALL OQueryContainer::approveInsertElement( const ContainerEvent& Event ) throw (WrappedTargetException, RuntimeException)
337 {
338     ::rtl::OUString sName;
339     OSL_VERIFY( Event.Accessor >>= sName );
340     Reference< XContent > xElement( Event.Element, UNO_QUERY_THROW );
341 
342     Reference< XVeto > xReturn;
343     try
344     {
345         getElementApproval()->approveElement( sName, xElement.get() );
346     }
347     catch( const Exception& )
348     {
349         xReturn = new Veto( ::rtl::OUString(), ::cppu::getCaughtException() );
350     }
351     return xReturn;
352 }
353 
354 //------------------------------------------------------------------------------
355 Reference< XVeto > SAL_CALL OQueryContainer::approveReplaceElement( const ContainerEvent& /*Event*/ ) throw (WrappedTargetException, RuntimeException)
356 {
357     return NULL;
358 }
359 
360 //------------------------------------------------------------------------------
361 Reference< XVeto > SAL_CALL OQueryContainer::approveRemoveElement( const ContainerEvent& /*Event*/ ) throw (WrappedTargetException, RuntimeException)
362 {
363     return NULL;
364 }
365 
366 //------------------------------------------------------------------------------
367 void SAL_CALL OQueryContainer::disposing( const ::com::sun::star::lang::EventObject& _rSource ) throw(::com::sun::star::uno::RuntimeException)
368 {
369 	if (_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinitions, UNO_QUERY).get())
370 	{	// our "master container" (with the command definitions) is beeing disposed
371 		DBG_ERROR("OQueryContainer::disposing : nobody should dispose the CommandDefinition container before disposing my connection !");
372 		dispose();
373 	}
374 	else
375 	{
376 		Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
377 		// it's one of our documents ....
378 		Documents::iterator aIter = m_aDocumentMap.begin();
379 		Documents::iterator aEnd = m_aDocumentMap.end();
380 		for	(;aIter != aEnd;++aIter )
381 		{
382 			if ( xSource == aIter->second.get() )
383 			{
384 				m_xCommandDefinitions->removeByName(aIter->first);
385 				break;
386 			}
387 		}
388 		ODefinitionContainer::disposing(_rSource);
389 	}
390 }
391 
392 // -----------------------------------------------------------------------------
393 ::rtl::OUString OQueryContainer::determineContentType() const
394 {
395     return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.org.openoffice.DatabaseQueryContainer" ) );
396 }
397 
398 // -----------------------------------------------------------------------------
399 Reference< XContent > OQueryContainer::implCreateWrapper(const ::rtl::OUString& _rName)
400 {
401 	Reference< XContent > xObject(m_xCommandDefinitions->getByName(_rName),UNO_QUERY);
402 	return implCreateWrapper(xObject);
403 }
404 
405 //--------------------------------------------------------------------------
406 Reference< XContent > OQueryContainer::implCreateWrapper(const Reference< XContent >& _rxCommandDesc)
407 {
408 	Reference<XNameContainer> xContainer(_rxCommandDesc,UNO_QUERY);
409 	Reference< XContent > xReturn;
410 	if ( xContainer .is() )
411 	{
412 		xReturn = new OQueryContainer( xContainer, m_xConnection, m_aContext.getLegacyServiceFactory(), m_pWarnings );
413 	}
414 	else
415 	{
416 		OQuery* pNewObject = new OQuery( Reference< XPropertySet >( _rxCommandDesc, UNO_QUERY ), m_xConnection, m_aContext.getLegacyServiceFactory() );
417 		xReturn = pNewObject;
418 
419 		pNewObject->setWarningsContainer( m_pWarnings );
420 //		pNewObject->getColumns();
421         // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the
422         // QueryInQuery test in dbaccess/qa/complex/dbaccess ...
423 	}
424 
425 	return xReturn;
426 }
427 //--------------------------------------------------------------------------
428 Reference< XContent > OQueryContainer::createObject( const ::rtl::OUString& _rName)
429 {
430 	return implCreateWrapper(_rName);
431 }
432 // -----------------------------------------------------------------------------
433 sal_Bool OQueryContainer::checkExistence(const ::rtl::OUString& _rName)
434 {
435 	sal_Bool bRet = sal_False;
436 	if ( !m_bInPropertyChange )
437 	{
438 		bRet = m_xCommandDefinitions->hasByName(_rName);
439 		Documents::iterator aFind = m_aDocumentMap.find(_rName);
440 		if ( !bRet && aFind != m_aDocumentMap.end() )
441 		{
442 			m_aDocuments.erase( ::std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
443 			m_aDocumentMap.erase(aFind);
444 		}
445 		else if ( bRet && aFind == m_aDocumentMap.end() )
446 		{
447 			implAppend(_rName,NULL);
448 		}
449 	}
450 	return bRet;
451 }
452 //--------------------------------------------------------------------------
453 sal_Bool SAL_CALL OQueryContainer::hasElements( ) throw (RuntimeException)
454 {
455 	MutexGuard aGuard(m_aMutex);
456 	return m_xCommandDefinitions->hasElements();
457 }
458 // -----------------------------------------------------------------------------
459 sal_Int32 SAL_CALL OQueryContainer::getCount(  ) throw(RuntimeException)
460 {
461 	MutexGuard aGuard(m_aMutex);
462 	return Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY)->getCount();
463 }
464 // -----------------------------------------------------------------------------
465 Sequence< ::rtl::OUString > SAL_CALL OQueryContainer::getElementNames(  ) throw(RuntimeException)
466 {
467 	MutexGuard aGuard(m_aMutex);
468 
469 	return m_xCommandDefinitions->getElementNames();
470 }
471 
472 //........................................................................
473 }	// namespace dbaccess
474 //........................................................................
475 
476