1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <connectivity/sdbcx/VCollection.hxx>
23 #include <connectivity/sdbcx/VDescriptor.hxx>
24 #include <connectivity/dbexception.hxx>
25 #include <comphelper/enumhelper.hxx>
26 #include <comphelper/container.hxx>
27 #include <comphelper/types.hxx>
28 #include <comphelper/property.hxx>
29 #include "TConnection.hxx"
30 #include <rtl/ustrbuf.hxx>
31 #include "resource/common_res.hrc"
32 #include "resource/sharedresources.hxx"
34 using namespace connectivity::sdbcx
;
35 using namespace connectivity
;
36 using namespace comphelper
;
37 using namespace ::cppu
;
38 using namespace ::com::sun::star::beans
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::lang
;
41 using namespace ::com::sun::star::sdbc
;
42 using namespace ::com::sun::star::container
;
43 using namespace ::com::sun::star::util
;
47 template < typename T
> class OHardRefMap
: public connectivity::sdbcx::IObjectCollection
49 typedef ::std::multimap
< OUString
, T
, ::comphelper::UStringMixLess
> ObjectMap
;
50 typedef typename
ObjectMap::iterator ObjectIter
;
51 typedef typename
ObjectMap::value_type ObjectEntry
;
54 // this combination of map and vector is used to have a fast name and index access
55 ::std::vector
< ObjectIter
> m_aElements
; // hold the iterators which point to map
56 ObjectMap m_aNameMap
; // hold the elements and a name
58 OHardRefMap(bool _bCase
)
62 virtual ~OHardRefMap() override
66 virtual bool exists(const OUString
& _sName
) override
68 return m_aNameMap
.find(_sName
) != m_aNameMap
.end();
71 virtual bool empty() override
73 return m_aNameMap
.empty();
76 virtual void swapAll() override
78 ::std::vector
< ObjectIter
>(m_aElements
).swap(m_aElements
);
79 ObjectMap(m_aNameMap
).swap(m_aNameMap
);
82 virtual void swap() override
84 ::std::vector
< ObjectIter
>().swap(m_aElements
);
86 OSL_ENSURE( m_aNameMap
.empty(), "swap: what did disposeElements do?" );
87 ObjectMap( m_aNameMap
).swap( m_aNameMap
);
88 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
89 // swapping. This way, it's ensured that the compare object held by these maps is preserved
90 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
91 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
92 // it's case-sensitive flag would have an unpredictable value.
95 virtual void clear() override
101 virtual void insert(const OUString
& _sName
,const ObjectType
& _xObject
) override
103 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sName
,_xObject
)));
106 virtual void reFill(const TStringVector
&_rVector
) override
108 OSL_ENSURE(!m_aNameMap
.size(),"OCollection::reFill: collection isn't empty");
109 m_aElements
.reserve(_rVector
.size());
111 for(TStringVector::const_iterator i
=_rVector
.begin(); i
!= _rVector
.end();++i
)
112 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(*i
,ObjectType())));
115 virtual bool rename(const OUString
& _sOldName
, const OUString
& _sNewName
) override
118 ObjectIter aIter
= m_aNameMap
.find(_sOldName
);
119 if ( aIter
!= m_aNameMap
.end() )
121 typename ::std::vector
< ObjectIter
>::iterator aFind
= ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
);
122 if(m_aElements
.end() != aFind
)
124 (*aFind
) = m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sNewName
,(*aFind
)->second
));
125 m_aNameMap
.erase(aIter
);
133 virtual sal_Int32
size() override
135 return static_cast<sal_Int32
>(m_aNameMap
.size());
138 virtual Sequence
< OUString
> getElementNames() override
140 Sequence
< OUString
> aNameList(m_aElements
.size());
142 OUString
* pStringArray
= aNameList
.getArray();
143 typename ::std::vector
< ObjectIter
>::const_iterator aEnd
= m_aElements
.end();
144 for(typename ::std::vector
< ObjectIter
>::const_iterator aIter
= m_aElements
.begin(); aIter
!= aEnd
;++aIter
,++pStringArray
)
145 *pStringArray
= (*aIter
)->first
;
150 virtual OUString
getName(sal_Int32 _nIndex
) override
152 return m_aElements
[_nIndex
]->first
;
155 virtual void disposeAndErase(sal_Int32 _nIndex
) override
157 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
158 Reference
<XComponent
> xComp(m_aElements
[_nIndex
]->second
.get(),UNO_QUERY
);
159 ::comphelper::disposeComponent(xComp
);
160 m_aElements
[_nIndex
]->second
= T();
162 OUString sName
= m_aElements
[_nIndex
]->first
;
163 m_aElements
.erase(m_aElements
.begin()+_nIndex
);
164 m_aNameMap
.erase(sName
);
167 virtual void disposeElements() override
169 for( ObjectIter aIter
= m_aNameMap
.begin(); aIter
!= m_aNameMap
.end(); ++aIter
)
171 Reference
<XComponent
> xComp(aIter
->second
.get(),UNO_QUERY
);
174 ::comphelper::disposeComponent(xComp
);
175 (*aIter
).second
= T();
182 virtual sal_Int32
findColumn( const OUString
& columnName
) override
184 ObjectIter aIter
= m_aNameMap
.find(columnName
);
185 OSL_ENSURE(aIter
!= m_aNameMap
.end(),"findColumn:: Illegal name!");
186 return m_aElements
.size() - (m_aElements
.end() - ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
));
189 virtual ObjectType
getObject(sal_Int32 _nIndex
) override
191 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
192 return m_aElements
[_nIndex
]->second
;
195 virtual ObjectType
getObject(const OUString
& columnName
) override
197 return m_aNameMap
.find(columnName
)->second
;
200 virtual void setObject(sal_Int32 _nIndex
,const ObjectType
& _xObject
) override
202 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
203 m_aElements
[_nIndex
]->second
= _xObject
;
206 bool isCaseSensitive() const override
208 return m_aNameMap
.key_comp().isCaseSensitive();
214 IObjectCollection::~IObjectCollection() {}
216 IMPLEMENT_SERVICE_INFO(OCollection
,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
218 OCollection::OCollection(::cppu::OWeakObject
& _rParent
220 , ::osl::Mutex
& _rMutex
221 , const TStringVector
&_rVector
222 , bool _bUseIndexOnly
224 :m_aContainerListeners(_rMutex
)
225 ,m_aRefreshListeners(_rMutex
)
228 ,m_bUseIndexOnly(_bUseIndexOnly
)
232 m_pElements
.reset(new OHardRefMap
< ObjectType
>(_bCase
));
236 m_pElements
.reset(new OHardRefMap
< WeakReference
< XPropertySet
> >(_bCase
));
238 m_pElements
->reFill(_rVector
);
241 OCollection::~OCollection()
245 Any SAL_CALL
OCollection::queryInterface( const Type
& rType
) throw (RuntimeException
, std::exception
)
247 if ( m_bUseIndexOnly
&& rType
== cppu::UnoType
<XNameAccess
>::get() )
251 return OCollectionBase::queryInterface( rType
);
254 Sequence
< Type
> SAL_CALL
OCollection::getTypes() throw (RuntimeException
, std::exception
)
256 if ( m_bUseIndexOnly
)
258 Sequence
< Type
> aTypes(OCollectionBase::getTypes());
259 Type
* pBegin
= aTypes
.getArray();
260 Type
* pEnd
= pBegin
+ aTypes
.getLength();
262 ::std::vector
<Type
> aOwnTypes
;
263 aOwnTypes
.reserve(aTypes
.getLength());
264 Type aType
= cppu::UnoType
<XNameAccess
>::get();
265 for(;pBegin
!= pEnd
; ++pBegin
)
267 if ( *pBegin
!= aType
)
268 aOwnTypes
.push_back(*pBegin
);
270 return Sequence
< Type
>(aOwnTypes
.data(), aOwnTypes
.size());
272 return OCollectionBase::getTypes( );
275 void OCollection::clear_NoDispose()
277 ::osl::MutexGuard
aGuard(m_rMutex
);
279 m_pElements
->clear();
280 m_pElements
->swapAll();
284 void OCollection::disposing()
286 m_aContainerListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
287 m_aRefreshListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
289 ::osl::MutexGuard
aGuard(m_rMutex
);
296 Any SAL_CALL
OCollection::getByIndex( sal_Int32 Index
) throw(IndexOutOfBoundsException
, WrappedTargetException
, RuntimeException
, std::exception
)
298 ::osl::MutexGuard
aGuard(m_rMutex
);
299 if (Index
< 0 || Index
>= m_pElements
->size() )
300 throw IndexOutOfBoundsException(OUString::number(Index
),static_cast<XTypeProvider
*>(this));
302 return makeAny(getObject(Index
));
305 Any SAL_CALL
OCollection::getByName( const OUString
& aName
) throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
, std::exception
)
307 ::osl::MutexGuard
aGuard(m_rMutex
);
309 if ( !m_pElements
->exists(aName
) )
311 ::connectivity::SharedResources aResources
;
312 const OUString
sError( aResources
.getResourceStringWithSubstitution(
316 throw NoSuchElementException( sError
, static_cast< XTypeProvider
* >( this ) );
319 return makeAny(getObject(m_pElements
->findColumn(aName
)));
322 Sequence
< OUString
> SAL_CALL
OCollection::getElementNames( ) throw(RuntimeException
, std::exception
)
324 ::osl::MutexGuard
aGuard(m_rMutex
);
325 return m_pElements
->getElementNames();
328 void SAL_CALL
OCollection::refresh( ) throw(RuntimeException
, std::exception
)
330 ::osl::MutexGuard
aGuard(m_rMutex
);
335 EventObject
aEvt(static_cast<XTypeProvider
*>(this));
336 m_aRefreshListeners
.notifyEach( &XRefreshListener::refreshed
, aEvt
);
339 void OCollection::reFill(const TStringVector
&_rVector
)
341 m_pElements
->reFill(_rVector
);
344 // XDataDescriptorFactory
345 Reference
< XPropertySet
> SAL_CALL
OCollection::createDataDescriptor( ) throw(RuntimeException
, std::exception
)
347 ::osl::MutexGuard
aGuard(m_rMutex
);
349 return createDescriptor();
352 OUString
OCollection::getNameForObject(const ObjectType
& _xObject
)
354 OSL_ENSURE(_xObject
.is(),"OCollection::getNameForObject: Object is NULL!");
356 _xObject
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sName
;
361 void SAL_CALL
OCollection::appendByDescriptor( const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, ElementExistException
, RuntimeException
, std::exception
)
363 ::osl::ClearableMutexGuard
aGuard(m_rMutex
);
365 OUString sName
= getNameForObject( descriptor
);
367 if ( m_pElements
->exists(sName
) )
368 throw ElementExistException(sName
,static_cast<XTypeProvider
*>(this));
370 ObjectType xNewlyCreated
= appendObject( sName
, descriptor
);
371 if ( !xNewlyCreated
.is() )
372 throw RuntimeException();
374 ODescriptor
* pDescriptor
= ODescriptor::getImplementation( xNewlyCreated
);
376 pDescriptor
->setNew( false );
378 sName
= getNameForObject( xNewlyCreated
);
379 if ( !m_pElements
->exists( sName
) ) // this may happen when the derived class included it itself
380 m_pElements
->insert( sName
, xNewlyCreated
);
382 // notify our container listeners
383 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(sName
), makeAny(xNewlyCreated
), Any());
385 m_aContainerListeners
.notifyEach( &XContainerListener::elementInserted
, aEvent
);
389 void SAL_CALL
OCollection::dropByName( const OUString
& elementName
) throw(SQLException
, NoSuchElementException
, RuntimeException
, std::exception
)
391 ::osl::MutexGuard
aGuard(m_rMutex
);
393 if ( !m_pElements
->exists(elementName
) )
394 throw NoSuchElementException(elementName
,static_cast<XTypeProvider
*>(this));
396 dropImpl(m_pElements
->findColumn(elementName
));
399 void SAL_CALL
OCollection::dropByIndex( sal_Int32 index
) throw(SQLException
, IndexOutOfBoundsException
, RuntimeException
, std::exception
)
401 ::osl::MutexGuard
aGuard(m_rMutex
);
402 if(index
<0 || index
>= getCount())
403 throw IndexOutOfBoundsException(OUString::number(index
),static_cast<XTypeProvider
*>(this));
408 void OCollection::dropImpl(sal_Int32 _nIndex
, bool _bReallyDrop
)
410 OUString elementName
= m_pElements
->getName(_nIndex
);
413 dropObject(_nIndex
,elementName
);
415 m_pElements
->disposeAndErase(_nIndex
);
417 // notify our container listeners
418 notifyElementRemoved(elementName
);
421 void OCollection::notifyElementRemoved(const OUString
& _sName
)
423 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sName
), Any(), Any());
424 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
425 OInterfaceIteratorHelper2
aListenerLoop(m_aContainerListeners
);
426 while (aListenerLoop
.hasMoreElements())
427 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementRemoved(aEvent
);
430 sal_Int32 SAL_CALL
OCollection::findColumn( const OUString
& columnName
) throw(SQLException
, RuntimeException
, std::exception
)
432 if ( !m_pElements
->exists(columnName
) )
434 ::dbtools::throwInvalidColumnException( columnName
, static_cast< XIndexAccess
*>(this) );
435 #if !(defined(_MSC_VER) && defined(ENABLE_LTO))
440 return m_pElements
->findColumn(columnName
) + 1; // because columns start at one
443 Reference
< XEnumeration
> SAL_CALL
OCollection::createEnumeration( ) throw(RuntimeException
, std::exception
)
445 ::osl::MutexGuard
aGuard(m_rMutex
);
446 return new OEnumerationByIndex( static_cast< XIndexAccess
*>(this));
449 void SAL_CALL
OCollection::addContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
, std::exception
)
451 m_aContainerListeners
.addInterface(_rxListener
);
455 void SAL_CALL
OCollection::removeContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
, std::exception
)
457 m_aContainerListeners
.removeInterface(_rxListener
);
460 void SAL_CALL
OCollection::acquire() throw()
465 void SAL_CALL
OCollection::release() throw()
470 Type SAL_CALL
OCollection::getElementType( ) throw(RuntimeException
, std::exception
)
472 return cppu::UnoType
<XPropertySet
>::get();
475 sal_Bool SAL_CALL
OCollection::hasElements( ) throw(RuntimeException
, std::exception
)
477 ::osl::MutexGuard
aGuard(m_rMutex
);
478 return !m_pElements
->empty();
481 sal_Int32 SAL_CALL
OCollection::getCount( ) throw(RuntimeException
, std::exception
)
483 ::osl::MutexGuard
aGuard(m_rMutex
);
484 return m_pElements
->size();
487 sal_Bool SAL_CALL
OCollection::hasByName( const OUString
& aName
) throw(RuntimeException
, std::exception
)
489 ::osl::MutexGuard
aGuard(m_rMutex
);
490 return m_pElements
->exists(aName
);
493 void SAL_CALL
OCollection::addRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
, std::exception
)
495 m_aRefreshListeners
.addInterface(l
);
498 void SAL_CALL
OCollection::removeRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
, std::exception
)
500 m_aRefreshListeners
.removeInterface(l
);
503 void OCollection::insertElement(const OUString
& _sElementName
,const ObjectType
& _xElement
)
505 OSL_ENSURE(!m_pElements
->exists(_sElementName
),"Element already exists");
506 if ( !m_pElements
->exists(_sElementName
) )
507 m_pElements
->insert(_sElementName
,_xElement
);
510 void OCollection::renameObject(const OUString
& _sOldName
, const OUString
& _sNewName
)
512 OSL_ENSURE(m_pElements
->exists(_sOldName
),"Element doesn't exist");
513 OSL_ENSURE(!m_pElements
->exists(_sNewName
),"Element already exists");
514 OSL_ENSURE(!_sNewName
.isEmpty(),"New name must not be empty!");
515 OSL_ENSURE(!_sOldName
.isEmpty(),"Old name must not be empty!");
517 if ( m_pElements
->rename(_sOldName
,_sNewName
) )
519 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sNewName
), makeAny(m_pElements
->getObject(_sNewName
)),makeAny(_sOldName
));
520 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
521 OInterfaceIteratorHelper2
aListenerLoop(m_aContainerListeners
);
522 while (aListenerLoop
.hasMoreElements())
523 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementReplaced(aEvent
);
527 ObjectType
OCollection::getObject(sal_Int32 _nIndex
)
529 ObjectType xName
= m_pElements
->getObject(_nIndex
);
534 xName
= createObject(m_pElements
->getName(_nIndex
));
536 catch(const SQLException
& e
)
540 dropImpl(_nIndex
,false);
542 catch(const Exception
& )
545 throw WrappedTargetException(e
.Message
,static_cast<XTypeProvider
*>(this),makeAny(e
));
547 m_pElements
->setObject(_nIndex
,xName
);
552 void OCollection::disposeElements()
554 m_pElements
->disposeElements();
557 Reference
< XPropertySet
> OCollection::createDescriptor()
559 OSL_FAIL("createDescriptor() needs to be overridden when used!");
560 throw SQLException();
563 ObjectType
OCollection::cloneDescriptor( const ObjectType
& _descriptor
)
565 ObjectType
xNewDescriptor( createDescriptor() );
566 ::comphelper::copyProperties( _descriptor
, xNewDescriptor
);
567 return xNewDescriptor
;
570 ObjectType
OCollection::appendObject( const OUString
& /*_rForName*/, const Reference
< XPropertySet
>& descriptor
)
572 return cloneDescriptor( descriptor
);
575 void OCollection::dropObject(sal_Int32
/*_nPos*/, const OUString
& /*_sElementName*/)
580 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */