Bump for 3.6-28
[LibreOffice.git] / connectivity / source / sdbcx / VCollection.cxx
blobc4f76eef2d876a1f7a9464ce0f0afd72976c60f8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <algorithm>
31 #include <stdio.h>
32 #include "connectivity/sdbcx/VCollection.hxx"
33 #include "connectivity/sdbcx/VDescriptor.hxx"
34 #include "connectivity/dbexception.hxx"
35 #include <comphelper/enumhelper.hxx>
36 #include <comphelper/container.hxx>
37 #include <comphelper/types.hxx>
38 #include <comphelper/property.hxx>
39 #include "TConnection.hxx"
40 #include <rtl/ustrbuf.hxx>
41 #include "resource/common_res.hrc"
42 #include "resource/sharedresources.hxx"
44 using namespace connectivity::sdbcx;
45 using namespace connectivity;
46 using namespace comphelper;
47 using namespace ::cppu;
48 using namespace ::com::sun::star::beans;
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::sdbc;
52 using namespace ::com::sun::star::container;
53 using namespace ::com::sun::star::util;
55 namespace
57 template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
59 typedef ::std::multimap< ::rtl::OUString, T , ::comphelper::UStringMixLess> ObjectMap;
60 typedef typename ObjectMap::iterator ObjectIter;
61 typedef typename ObjectMap::value_type ObjectEntry;
63 // private:
64 // this combination of map and vector is used to have a fast name and index access
65 ::std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
66 ObjectMap m_aNameMap; // hold the elements and a name
67 public:
68 OHardRefMap(sal_Bool _bCase)
69 : m_aNameMap(_bCase ? true : false)
72 virtual ~OHardRefMap()
76 virtual void reserve(size_t nLength)
78 m_aElements.reserve(nLength);
80 // -----------------------------------------------------------------------------
81 virtual bool exists(const ::rtl::OUString& _sName )
83 return m_aNameMap.find(_sName) != m_aNameMap.end();
85 // -----------------------------------------------------------------------------
86 virtual bool empty()
88 return m_aNameMap.empty();
90 // -----------------------------------------------------------------------------
91 virtual void swapAll()
93 ::std::vector< ObjectIter >(m_aElements).swap(m_aElements);
94 ObjectMap(m_aNameMap).swap(m_aNameMap);
96 // -----------------------------------------------------------------------------
97 virtual void swap()
99 ::std::vector< ObjectIter >().swap(m_aElements);
101 OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
102 ObjectMap( m_aNameMap ).swap( m_aNameMap );
103 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
104 // swapping. This way, it's ensured that the compare object held by these maps is preserved
105 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
106 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
107 // it's case-sensitive flag would have an unpredictable value.
109 // -----------------------------------------------------------------------------
110 virtual void clear()
112 m_aElements.clear();
113 m_aNameMap.clear();
115 // -----------------------------------------------------------------------------
116 virtual void insert(const ::rtl::OUString& _sName,const ObjectType& _xObject)
118 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
120 // -----------------------------------------------------------------------------
121 virtual void reFill(const TStringVector &_rVector)
123 OSL_ENSURE(!m_aNameMap.size(),"OCollection::reFill: collection isn't empty");
124 m_aElements.reserve(_rVector.size());
126 for(TStringVector::const_iterator i=_rVector.begin(); i != _rVector.end();++i)
127 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(*i,ObjectType())));
129 // -----------------------------------------------------------------------------
130 virtual bool rename(const ::rtl::OUString _sOldName,const ::rtl::OUString _sNewName)
132 bool bRet = false;
133 ObjectIter aIter = m_aNameMap.find(_sOldName);
134 if ( aIter != m_aNameMap.end() )
136 typename ::std::vector< ObjectIter >::iterator aFind = ::std::find(m_aElements.begin(),m_aElements.end(),aIter);
137 if(m_aElements.end() != aFind)
139 (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
140 m_aNameMap.erase(aIter);
142 bRet = true;
145 return bRet;
147 // -----------------------------------------------------------------------------
148 virtual sal_Int32 size()
150 return static_cast<sal_Int32>(m_aNameMap.size());
152 // -----------------------------------------------------------------------------
153 virtual Sequence< ::rtl::OUString > getElementNames()
155 Sequence< ::rtl::OUString > aNameList(m_aElements.size());
157 ::rtl::OUString* pStringArray = aNameList.getArray();
158 typename ::std::vector< ObjectIter >::const_iterator aEnd = m_aElements.end();
159 for(typename ::std::vector< ObjectIter >::const_iterator aIter = m_aElements.begin(); aIter != aEnd;++aIter,++pStringArray)
160 *pStringArray = (*aIter)->first;
162 return aNameList;
164 // -----------------------------------------------------------------------------
165 virtual ::rtl::OUString getName(sal_Int32 _nIndex)
167 return m_aElements[_nIndex]->first;
169 // -----------------------------------------------------------------------------
170 virtual void disposeAndErase(sal_Int32 _nIndex)
172 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
173 Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
174 ::comphelper::disposeComponent(xComp);
175 m_aElements[_nIndex]->second = T();
177 ::rtl::OUString sName = m_aElements[_nIndex]->first;
178 m_aElements.erase(m_aElements.begin()+_nIndex);
179 m_aNameMap.erase(sName);
181 // -----------------------------------------------------------------------------
182 virtual void disposeElements()
184 for( ObjectIter aIter = m_aNameMap.begin(); aIter != m_aNameMap.end(); ++aIter)
186 Reference<XComponent> xComp(aIter->second.get(),UNO_QUERY);
187 if ( xComp.is() )
189 ::comphelper::disposeComponent(xComp);
190 (*aIter).second = T();
193 m_aElements.clear();
194 m_aNameMap.clear();
196 // -----------------------------------------------------------------------------
197 virtual sal_Int32 findColumn( const ::rtl::OUString& columnName )
199 ObjectIter aIter = m_aNameMap.find(columnName);
200 OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
201 return m_aElements.size() - (m_aElements.end() - ::std::find(m_aElements.begin(),m_aElements.end(),aIter));
203 // -----------------------------------------------------------------------------
204 virtual ::rtl::OUString findColumnAtIndex( sal_Int32 _nIndex)
206 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
207 return m_aElements[_nIndex]->first;
209 // -----------------------------------------------------------------------------
210 virtual ObjectType getObject(sal_Int32 _nIndex)
212 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
213 return m_aElements[_nIndex]->second;
215 // -----------------------------------------------------------------------------
216 virtual ObjectType getObject(const ::rtl::OUString& columnName)
218 return m_aNameMap.find(columnName)->second;
220 // -----------------------------------------------------------------------------
221 virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject)
223 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
224 m_aElements[_nIndex]->second = _xObject;
226 // -----------------------------------------------------------------------------
227 sal_Bool isCaseSensitive() const
229 return m_aNameMap.key_comp().isCaseSensitive();
231 // -----------------------------------------------------------------------------
235 IObjectCollection::~IObjectCollection() {}
237 IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
239 OCollection::OCollection(::cppu::OWeakObject& _rParent
240 , sal_Bool _bCase
241 , ::osl::Mutex& _rMutex
242 , const TStringVector &_rVector
243 , sal_Bool _bUseIndexOnly
244 , sal_Bool _bUseHardRef)
245 :m_aContainerListeners(_rMutex)
246 ,m_aRefreshListeners(_rMutex)
247 ,m_rParent(_rParent)
248 ,m_rMutex(_rMutex)
249 ,m_bUseIndexOnly(_bUseIndexOnly)
251 if ( _bUseHardRef )
253 m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
255 else
257 m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
259 m_pElements->reFill(_rVector);
261 // -------------------------------------------------------------------------
262 OCollection::~OCollection()
265 // -----------------------------------------------------------------------------
266 Any SAL_CALL OCollection::queryInterface( const Type & rType ) throw (RuntimeException)
268 if ( m_bUseIndexOnly && rType == ::getCppuType(static_cast< Reference< XNameAccess > *> (NULL)) )
270 return Any();
272 return OCollectionBase::queryInterface( rType );
274 // -----------------------------------------------------------------------------
275 Sequence< Type > SAL_CALL OCollection::getTypes() throw (RuntimeException)
277 if ( m_bUseIndexOnly )
279 Sequence< Type > aTypes(OCollectionBase::getTypes());
280 Type* pBegin = aTypes.getArray();
281 Type* pEnd = pBegin + aTypes.getLength();
283 ::std::vector<Type> aOwnTypes;
284 aOwnTypes.reserve(aTypes.getLength());
285 Type aType = ::getCppuType(static_cast< Reference<XNameAccess> *>(NULL));
286 for(;pBegin != pEnd; ++pBegin)
288 if ( *pBegin != aType )
289 aOwnTypes.push_back(*pBegin);
291 Type* pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0];
292 return Sequence< Type >(pTypes,aOwnTypes.size());
294 return OCollectionBase::getTypes( );
296 // -------------------------------------------------------------------------
297 void OCollection::clear_NoDispose()
299 ::osl::MutexGuard aGuard(m_rMutex);
301 m_pElements->clear();
302 m_pElements->swapAll();
305 // -------------------------------------------------------------------------
306 void OCollection::disposing(void)
308 m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
309 m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
311 ::osl::MutexGuard aGuard(m_rMutex);
313 disposeElements();
315 m_pElements->swap();
317 // -------------------------------------------------------------------------
318 Any SAL_CALL OCollection::getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
320 ::osl::MutexGuard aGuard(m_rMutex);
321 if (Index < 0 || Index >= m_pElements->size() )
322 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(Index),static_cast<XTypeProvider*>(this));
324 return makeAny(getObject(Index));
326 // -------------------------------------------------------------------------
327 Any SAL_CALL OCollection::getByName( const ::rtl::OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
329 ::osl::MutexGuard aGuard(m_rMutex);
331 if ( !m_pElements->exists(aName) )
333 ::connectivity::SharedResources aResources;
334 const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
335 STR_NO_ELEMENT_NAME,
336 "$name$", aName
337 ) );
338 throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
341 return makeAny(getObject(m_pElements->findColumn(aName)));
343 // -------------------------------------------------------------------------
344 Sequence< ::rtl::OUString > SAL_CALL OCollection::getElementNames( ) throw(RuntimeException)
346 ::osl::MutexGuard aGuard(m_rMutex);
347 return m_pElements->getElementNames();
349 // -------------------------------------------------------------------------
350 void SAL_CALL OCollection::refresh( ) throw(RuntimeException)
352 ::osl::MutexGuard aGuard(m_rMutex);
354 disposeElements();
356 impl_refresh();
357 EventObject aEvt(static_cast<XTypeProvider*>(this));
358 m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
360 // -----------------------------------------------------------------------------
361 void OCollection::reFill(const TStringVector &_rVector)
363 m_pElements->reFill(_rVector);
365 // -------------------------------------------------------------------------
366 // XDataDescriptorFactory
367 Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( ) throw(RuntimeException)
369 ::osl::MutexGuard aGuard(m_rMutex);
371 return createDescriptor();
373 // -----------------------------------------------------------------------------
374 ::rtl::OUString OCollection::getNameForObject(const ObjectType& _xObject)
376 OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
377 ::rtl::OUString sName;
378 _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
379 return sName;
381 // -------------------------------------------------------------------------
382 // XAppend
383 void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor ) throw(SQLException, ElementExistException, RuntimeException)
385 ::osl::ClearableMutexGuard aGuard(m_rMutex);
387 ::rtl::OUString sName = getNameForObject( descriptor );
389 if ( m_pElements->exists(sName) )
390 throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
392 ObjectType xNewlyCreated = appendObject( sName, descriptor );
393 if ( !xNewlyCreated.is() )
394 throw RuntimeException();
396 ODescriptor* pDescriptor = ODescriptor::getImplementation( xNewlyCreated );
397 if ( pDescriptor )
398 pDescriptor->setNew( sal_False );
400 sName = getNameForObject( xNewlyCreated );
401 if ( !m_pElements->exists( sName ) ) // this may happen when the drived class included it itself
402 m_pElements->insert( sName, xNewlyCreated );
404 // notify our container listeners
405 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xNewlyCreated), Any());
406 aGuard.clear();
407 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
409 // -------------------------------------------------------------------------
410 // XDrop
411 void SAL_CALL OCollection::dropByName( const ::rtl::OUString& elementName ) throw(SQLException, NoSuchElementException, RuntimeException)
413 ::osl::MutexGuard aGuard(m_rMutex);
415 if ( !m_pElements->exists(elementName) )
416 throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
418 dropImpl(m_pElements->findColumn(elementName));
420 // -------------------------------------------------------------------------
421 void SAL_CALL OCollection::dropByIndex( sal_Int32 index ) throw(SQLException, IndexOutOfBoundsException, RuntimeException)
423 ::osl::MutexGuard aGuard(m_rMutex);
424 if(index <0 || index >= getCount())
425 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index),static_cast<XTypeProvider*>(this));
427 dropImpl(index);
429 // -----------------------------------------------------------------------------
430 void OCollection::dropImpl(sal_Int32 _nIndex,sal_Bool _bReallyDrop)
432 ::rtl::OUString elementName = m_pElements->getName(_nIndex);
434 if ( _bReallyDrop )
435 dropObject(_nIndex,elementName);
437 m_pElements->disposeAndErase(_nIndex);
439 // notify our container listeners
440 notifyElementRemoved(elementName);
442 // -----------------------------------------------------------------------------
443 void OCollection::notifyElementRemoved(const ::rtl::OUString& _sName)
445 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sName), Any(), Any());
446 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
447 OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
448 while (aListenerLoop.hasMoreElements())
449 static_cast<XContainerListener*>(aListenerLoop.next())->elementRemoved(aEvent);
451 // -------------------------------------------------------------------------
452 sal_Int32 SAL_CALL OCollection::findColumn( const ::rtl::OUString& columnName ) throw(SQLException, RuntimeException)
454 if ( !m_pElements->exists(columnName) )
456 ::connectivity::SharedResources aResources;
457 const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
458 STR_UNKNOWN_COLUMN_NAME,
459 "$columnname$", columnName
460 ) );
461 ::dbtools::throwGenericSQLException(sError,static_cast< XIndexAccess*>(this));
464 return m_pElements->findColumn(columnName) + 1; // because columns start at one
466 // -------------------------------------------------------------------------
467 Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( ) throw(RuntimeException)
469 ::osl::MutexGuard aGuard(m_rMutex);
470 return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
472 // -----------------------------------------------------------------------------
473 void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
475 m_aContainerListeners.addInterface(_rxListener);
478 //------------------------------------------------------------------------------
479 void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
481 m_aContainerListeners.removeInterface(_rxListener);
483 // -----------------------------------------------------------------------------
484 void SAL_CALL OCollection::acquire() throw()
486 m_rParent.acquire();
488 // -----------------------------------------------------------------------------
489 void SAL_CALL OCollection::release() throw()
491 m_rParent.release();
493 // -----------------------------------------------------------------------------
494 Type SAL_CALL OCollection::getElementType( ) throw(RuntimeException)
496 return::getCppuType(static_cast< Reference< XPropertySet>*>(NULL));
498 // -----------------------------------------------------------------------------
499 sal_Bool SAL_CALL OCollection::hasElements( ) throw(RuntimeException)
501 ::osl::MutexGuard aGuard(m_rMutex);
502 return !m_pElements->empty();
504 // -----------------------------------------------------------------------------
505 sal_Int32 SAL_CALL OCollection::getCount( ) throw(RuntimeException)
507 ::osl::MutexGuard aGuard(m_rMutex);
508 return m_pElements->size();
510 // -----------------------------------------------------------------------------
511 sal_Bool SAL_CALL OCollection::hasByName( const ::rtl::OUString& aName ) throw(RuntimeException)
513 ::osl::MutexGuard aGuard(m_rMutex);
514 return m_pElements->exists(aName);
516 // -----------------------------------------------------------------------------
517 void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException)
519 m_aRefreshListeners.addInterface(l);
521 // -----------------------------------------------------------------------------
522 void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException)
524 m_aRefreshListeners.removeInterface(l);
526 // -----------------------------------------------------------------------------
527 void OCollection::insertElement(const ::rtl::OUString& _sElementName,const ObjectType& _xElement)
529 OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
530 if ( !m_pElements->exists(_sElementName) )
531 m_pElements->insert(_sElementName,_xElement);
533 // -----------------------------------------------------------------------------
534 void OCollection::renameObject(const ::rtl::OUString _sOldName,const ::rtl::OUString _sNewName)
536 OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
537 OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
538 OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!");
539 OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!");
541 if ( m_pElements->rename(_sOldName,_sNewName) )
543 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sNewName), makeAny(m_pElements->getObject(_sNewName)),makeAny(_sOldName));
544 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
545 OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
546 while (aListenerLoop.hasMoreElements())
547 static_cast<XContainerListener*>(aListenerLoop.next())->elementReplaced(aEvent);
550 // -----------------------------------------------------------------------------
551 ObjectType OCollection::getObject(sal_Int32 _nIndex)
553 ObjectType xName = m_pElements->getObject(_nIndex);
554 if ( !xName.is() )
558 xName = createObject(m_pElements->getName(_nIndex));
560 catch(const SQLException& e)
564 dropImpl(_nIndex,sal_False);
566 catch(const Exception& )
569 throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),makeAny(e));
571 m_pElements->setObject(_nIndex,xName);
573 return xName;
575 // -----------------------------------------------------------------------------
576 void OCollection::disposeElements()
578 m_pElements->disposeElements();
580 // -----------------------------------------------------------------------------
581 Reference< XPropertySet > OCollection::createDescriptor()
583 OSL_ASSERT(!"Need to be overloaded when used!");
584 throw SQLException();
586 // -----------------------------------------------------------------------------
587 ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
589 ObjectType xNewDescriptor( createDescriptor() );
590 ::comphelper::copyProperties( _descriptor, xNewDescriptor );
591 return xNewDescriptor;
593 // -----------------------------------------------------------------------------
594 ObjectType OCollection::appendObject( const ::rtl::OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
596 return cloneDescriptor( descriptor );
598 // -----------------------------------------------------------------------------
599 void OCollection::dropObject(sal_Int32 /*_nPos*/,const ::rtl::OUString /*_sElementName*/)
602 // -----------------------------------------------------------------------------
604 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */