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