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