Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / sdbcx / VCollection.cxx
blob76d0692b8dc4469476aab2e4c77641cda54e6b12
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <algorithm>
22 #include <stdio.h>
23 #include "connectivity/sdbcx/VCollection.hxx"
24 #include "connectivity/sdbcx/VDescriptor.hxx"
25 #include "connectivity/dbexception.hxx"
26 #include <comphelper/enumhelper.hxx>
27 #include <comphelper/container.hxx>
28 #include <comphelper/types.hxx>
29 #include <comphelper/property.hxx>
30 #include "TConnection.hxx"
31 #include <rtl/ustrbuf.hxx>
32 #include "resource/common_res.hrc"
33 #include "resource/sharedresources.hxx"
35 using namespace connectivity::sdbcx;
36 using namespace connectivity;
37 using namespace comphelper;
38 using namespace ::cppu;
39 using namespace ::com::sun::star::beans;
40 using namespace ::com::sun::star::uno;
41 using namespace ::com::sun::star::lang;
42 using namespace ::com::sun::star::sdbc;
43 using namespace ::com::sun::star::container;
44 using namespace ::com::sun::star::util;
46 namespace
48 template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
50 typedef ::std::multimap< OUString, T , ::comphelper::UStringMixLess> ObjectMap;
51 typedef typename ObjectMap::iterator ObjectIter;
52 typedef typename ObjectMap::value_type ObjectEntry;
54 // private:
55 // this combination of map and vector is used to have a fast name and index access
56 ::std::vector< ObjectIter > m_aElements; // hold the iterators which point to map
57 ObjectMap m_aNameMap; // hold the elements and a name
58 public:
59 OHardRefMap(bool _bCase)
60 : m_aNameMap(_bCase)
63 virtual ~OHardRefMap()
67 virtual void reserve(size_t nLength) SAL_OVERRIDE
69 m_aElements.reserve(nLength);
72 virtual bool exists(const OUString& _sName ) SAL_OVERRIDE
74 return m_aNameMap.find(_sName) != m_aNameMap.end();
77 virtual bool empty() SAL_OVERRIDE
79 return m_aNameMap.empty();
82 virtual void swapAll() SAL_OVERRIDE
84 ::std::vector< ObjectIter >(m_aElements).swap(m_aElements);
85 ObjectMap(m_aNameMap).swap(m_aNameMap);
88 virtual void swap() SAL_OVERRIDE
90 ::std::vector< ObjectIter >().swap(m_aElements);
92 OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
93 ObjectMap( m_aNameMap ).swap( m_aNameMap );
94 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
95 // swapping. This way, it's ensured that the compare object held by these maps is preserved
96 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
97 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
98 // it's case-sensitive flag would have an unpredictable value.
101 virtual void clear() SAL_OVERRIDE
103 m_aElements.clear();
104 m_aNameMap.clear();
107 virtual void insert(const OUString& _sName,const ObjectType& _xObject) SAL_OVERRIDE
109 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
112 virtual void reFill(const TStringVector &_rVector) SAL_OVERRIDE
114 OSL_ENSURE(!m_aNameMap.size(),"OCollection::reFill: collection isn't empty");
115 m_aElements.reserve(_rVector.size());
117 for(TStringVector::const_iterator i=_rVector.begin(); i != _rVector.end();++i)
118 m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(*i,ObjectType())));
121 virtual bool rename(const OUString& _sOldName, const OUString& _sNewName) SAL_OVERRIDE
123 bool bRet = false;
124 ObjectIter aIter = m_aNameMap.find(_sOldName);
125 if ( aIter != m_aNameMap.end() )
127 typename ::std::vector< ObjectIter >::iterator aFind = ::std::find(m_aElements.begin(),m_aElements.end(),aIter);
128 if(m_aElements.end() != aFind)
130 (*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
131 m_aNameMap.erase(aIter);
133 bRet = true;
136 return bRet;
139 virtual sal_Int32 size() SAL_OVERRIDE
141 return static_cast<sal_Int32>(m_aNameMap.size());
144 virtual Sequence< OUString > getElementNames() SAL_OVERRIDE
146 Sequence< OUString > aNameList(m_aElements.size());
148 OUString* pStringArray = aNameList.getArray();
149 typename ::std::vector< ObjectIter >::const_iterator aEnd = m_aElements.end();
150 for(typename ::std::vector< ObjectIter >::const_iterator aIter = m_aElements.begin(); aIter != aEnd;++aIter,++pStringArray)
151 *pStringArray = (*aIter)->first;
153 return aNameList;
156 virtual OUString getName(sal_Int32 _nIndex) SAL_OVERRIDE
158 return m_aElements[_nIndex]->first;
161 virtual void disposeAndErase(sal_Int32 _nIndex) SAL_OVERRIDE
163 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
164 Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
165 ::comphelper::disposeComponent(xComp);
166 m_aElements[_nIndex]->second = T();
168 OUString sName = m_aElements[_nIndex]->first;
169 m_aElements.erase(m_aElements.begin()+_nIndex);
170 m_aNameMap.erase(sName);
173 virtual void disposeElements() SAL_OVERRIDE
175 for( ObjectIter aIter = m_aNameMap.begin(); aIter != m_aNameMap.end(); ++aIter)
177 Reference<XComponent> xComp(aIter->second.get(),UNO_QUERY);
178 if ( xComp.is() )
180 ::comphelper::disposeComponent(xComp);
181 (*aIter).second = T();
184 m_aElements.clear();
185 m_aNameMap.clear();
188 virtual sal_Int32 findColumn( const OUString& columnName ) SAL_OVERRIDE
190 ObjectIter aIter = m_aNameMap.find(columnName);
191 OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
192 return m_aElements.size() - (m_aElements.end() - ::std::find(m_aElements.begin(),m_aElements.end(),aIter));
195 virtual OUString findColumnAtIndex( sal_Int32 _nIndex) SAL_OVERRIDE
197 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
198 return m_aElements[_nIndex]->first;
201 virtual ObjectType getObject(sal_Int32 _nIndex) SAL_OVERRIDE
203 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
204 return m_aElements[_nIndex]->second;
207 virtual ObjectType getObject(const OUString& columnName) SAL_OVERRIDE
209 return m_aNameMap.find(columnName)->second;
212 virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject) SAL_OVERRIDE
214 OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
215 m_aElements[_nIndex]->second = _xObject;
218 bool isCaseSensitive() const SAL_OVERRIDE
220 return m_aNameMap.key_comp().isCaseSensitive();
226 IObjectCollection::~IObjectCollection() {}
228 IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
230 OCollection::OCollection(::cppu::OWeakObject& _rParent
231 , bool _bCase
232 , ::osl::Mutex& _rMutex
233 , const TStringVector &_rVector
234 , bool _bUseIndexOnly
235 , bool _bUseHardRef)
236 :m_aContainerListeners(_rMutex)
237 ,m_aRefreshListeners(_rMutex)
238 ,m_rParent(_rParent)
239 ,m_rMutex(_rMutex)
240 ,m_bUseIndexOnly(_bUseIndexOnly)
242 if ( _bUseHardRef )
244 m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
246 else
248 m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
250 m_pElements->reFill(_rVector);
253 OCollection::~OCollection()
257 Any SAL_CALL OCollection::queryInterface( const Type & rType ) throw (RuntimeException, std::exception)
259 if ( m_bUseIndexOnly && rType == ::getCppuType(static_cast< Reference< XNameAccess > *> (NULL)) )
261 return Any();
263 return OCollectionBase::queryInterface( rType );
266 Sequence< Type > SAL_CALL OCollection::getTypes() throw (RuntimeException, std::exception)
268 if ( m_bUseIndexOnly )
270 Sequence< Type > aTypes(OCollectionBase::getTypes());
271 Type* pBegin = aTypes.getArray();
272 Type* pEnd = pBegin + aTypes.getLength();
274 ::std::vector<Type> aOwnTypes;
275 aOwnTypes.reserve(aTypes.getLength());
276 Type aType = ::getCppuType(static_cast< Reference<XNameAccess> *>(NULL));
277 for(;pBegin != pEnd; ++pBegin)
279 if ( *pBegin != aType )
280 aOwnTypes.push_back(*pBegin);
282 Type* pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0];
283 return Sequence< Type >(pTypes,aOwnTypes.size());
285 return OCollectionBase::getTypes( );
288 void OCollection::clear_NoDispose()
290 ::osl::MutexGuard aGuard(m_rMutex);
292 m_pElements->clear();
293 m_pElements->swapAll();
297 void OCollection::disposing(void)
299 m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
300 m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
302 ::osl::MutexGuard aGuard(m_rMutex);
304 disposeElements();
306 m_pElements->swap();
309 Any SAL_CALL OCollection::getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException, std::exception)
311 ::osl::MutexGuard aGuard(m_rMutex);
312 if (Index < 0 || Index >= m_pElements->size() )
313 throw IndexOutOfBoundsException(OUString::number(Index),static_cast<XTypeProvider*>(this));
315 return makeAny(getObject(Index));
318 Any SAL_CALL OCollection::getByName( const OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException, std::exception)
320 ::osl::MutexGuard aGuard(m_rMutex);
322 if ( !m_pElements->exists(aName) )
324 ::connectivity::SharedResources aResources;
325 const OUString sError( aResources.getResourceStringWithSubstitution(
326 STR_NO_ELEMENT_NAME,
327 "$name$", aName
328 ) );
329 throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
332 return makeAny(getObject(m_pElements->findColumn(aName)));
335 Sequence< OUString > SAL_CALL OCollection::getElementNames( ) throw(RuntimeException, std::exception)
337 ::osl::MutexGuard aGuard(m_rMutex);
338 return m_pElements->getElementNames();
341 void SAL_CALL OCollection::refresh( ) throw(RuntimeException, std::exception)
343 ::osl::MutexGuard aGuard(m_rMutex);
345 disposeElements();
347 impl_refresh();
348 EventObject aEvt(static_cast<XTypeProvider*>(this));
349 m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
352 void OCollection::reFill(const TStringVector &_rVector)
354 m_pElements->reFill(_rVector);
357 // XDataDescriptorFactory
358 Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor( ) throw(RuntimeException, std::exception)
360 ::osl::MutexGuard aGuard(m_rMutex);
362 return createDescriptor();
365 OUString OCollection::getNameForObject(const ObjectType& _xObject)
367 OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
368 OUString sName;
369 _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
370 return sName;
373 // XAppend
374 void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor ) throw(SQLException, ElementExistException, RuntimeException, std::exception)
376 ::osl::ClearableMutexGuard aGuard(m_rMutex);
378 OUString sName = getNameForObject( descriptor );
380 if ( m_pElements->exists(sName) )
381 throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
383 ObjectType xNewlyCreated = appendObject( sName, descriptor );
384 if ( !xNewlyCreated.is() )
385 throw RuntimeException();
387 ODescriptor* pDescriptor = ODescriptor::getImplementation( xNewlyCreated );
388 if ( pDescriptor )
389 pDescriptor->setNew( false );
391 sName = getNameForObject( xNewlyCreated );
392 if ( !m_pElements->exists( sName ) ) // this may happen when the derived class included it itself
393 m_pElements->insert( sName, xNewlyCreated );
395 // notify our container listeners
396 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xNewlyCreated), Any());
397 aGuard.clear();
398 m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
401 // XDrop
402 void SAL_CALL OCollection::dropByName( const OUString& elementName ) throw(SQLException, NoSuchElementException, RuntimeException, std::exception)
404 ::osl::MutexGuard aGuard(m_rMutex);
406 if ( !m_pElements->exists(elementName) )
407 throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
409 dropImpl(m_pElements->findColumn(elementName));
412 void SAL_CALL OCollection::dropByIndex( sal_Int32 index ) throw(SQLException, IndexOutOfBoundsException, RuntimeException, std::exception)
414 ::osl::MutexGuard aGuard(m_rMutex);
415 if(index <0 || index >= getCount())
416 throw IndexOutOfBoundsException(OUString::number(index),static_cast<XTypeProvider*>(this));
418 dropImpl(index);
421 void OCollection::dropImpl(sal_Int32 _nIndex, bool _bReallyDrop)
423 OUString elementName = m_pElements->getName(_nIndex);
425 if ( _bReallyDrop )
426 dropObject(_nIndex,elementName);
428 m_pElements->disposeAndErase(_nIndex);
430 // notify our container listeners
431 notifyElementRemoved(elementName);
434 void OCollection::notifyElementRemoved(const OUString& _sName)
436 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sName), Any(), Any());
437 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
438 OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
439 while (aListenerLoop.hasMoreElements())
440 static_cast<XContainerListener*>(aListenerLoop.next())->elementRemoved(aEvent);
443 sal_Int32 SAL_CALL OCollection::findColumn( const OUString& columnName ) throw(SQLException, RuntimeException, std::exception)
445 if ( !m_pElements->exists(columnName) )
447 ::dbtools::throwInvalidColumnException( columnName, static_cast< XIndexAccess*>(this) );
448 assert(false);
451 return m_pElements->findColumn(columnName) + 1; // because columns start at one
454 Reference< XEnumeration > SAL_CALL OCollection::createEnumeration( ) throw(RuntimeException, std::exception)
456 ::osl::MutexGuard aGuard(m_rMutex);
457 return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
460 void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException, std::exception)
462 m_aContainerListeners.addInterface(_rxListener);
466 void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException, std::exception)
468 m_aContainerListeners.removeInterface(_rxListener);
471 void SAL_CALL OCollection::acquire() throw()
473 m_rParent.acquire();
476 void SAL_CALL OCollection::release() throw()
478 m_rParent.release();
481 Type SAL_CALL OCollection::getElementType( ) throw(RuntimeException, std::exception)
483 return::getCppuType(static_cast< Reference< XPropertySet>*>(NULL));
486 sal_Bool SAL_CALL OCollection::hasElements( ) throw(RuntimeException, std::exception)
488 ::osl::MutexGuard aGuard(m_rMutex);
489 return !m_pElements->empty();
492 sal_Int32 SAL_CALL OCollection::getCount( ) throw(RuntimeException, std::exception)
494 ::osl::MutexGuard aGuard(m_rMutex);
495 return m_pElements->size();
498 sal_Bool SAL_CALL OCollection::hasByName( const OUString& aName ) throw(RuntimeException, std::exception)
500 ::osl::MutexGuard aGuard(m_rMutex);
501 return m_pElements->exists(aName);
504 void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException, std::exception)
506 m_aRefreshListeners.addInterface(l);
509 void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException, std::exception)
511 m_aRefreshListeners.removeInterface(l);
514 void OCollection::insertElement(const OUString& _sElementName,const ObjectType& _xElement)
516 OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
517 if ( !m_pElements->exists(_sElementName) )
518 m_pElements->insert(_sElementName,_xElement);
521 void OCollection::renameObject(const OUString& _sOldName, const OUString& _sNewName)
523 OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
524 OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
525 OSL_ENSURE(!_sNewName.isEmpty(),"New name must not be empty!");
526 OSL_ENSURE(!_sOldName.isEmpty(),"Old name must not be empty!");
528 if ( m_pElements->rename(_sOldName,_sNewName) )
530 ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sNewName), makeAny(m_pElements->getObject(_sNewName)),makeAny(_sOldName));
531 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
532 OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
533 while (aListenerLoop.hasMoreElements())
534 static_cast<XContainerListener*>(aListenerLoop.next())->elementReplaced(aEvent);
538 ObjectType OCollection::getObject(sal_Int32 _nIndex)
540 ObjectType xName = m_pElements->getObject(_nIndex);
541 if ( !xName.is() )
545 xName = createObject(m_pElements->getName(_nIndex));
547 catch(const SQLException& e)
551 dropImpl(_nIndex,false);
553 catch(const Exception& )
556 throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),makeAny(e));
558 m_pElements->setObject(_nIndex,xName);
560 return xName;
563 void OCollection::disposeElements()
565 m_pElements->disposeElements();
568 Reference< XPropertySet > OCollection::createDescriptor()
570 OSL_FAIL("Need to be overloaded when used!");
571 throw SQLException();
574 ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
576 ObjectType xNewDescriptor( createDescriptor() );
577 ::comphelper::copyProperties( _descriptor, xNewDescriptor );
578 return xNewDescriptor;
581 ObjectType OCollection::appendObject( const OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
583 return cloneDescriptor( descriptor );
586 void OCollection::dropObject(sal_Int32 /*_nPos*/, const OUString& /*_sElementName*/)
591 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */