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 .
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
;
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
;
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
59 OHardRefMap(bool _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
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
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
);
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
;
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
);
180 ::comphelper::disposeComponent(xComp
);
181 (*aIter
).second
= T();
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
232 , ::osl::Mutex
& _rMutex
233 , const TStringVector
&_rVector
234 , bool _bUseIndexOnly
236 :m_aContainerListeners(_rMutex
)
237 ,m_aRefreshListeners(_rMutex
)
240 ,m_bUseIndexOnly(_bUseIndexOnly
)
244 m_pElements
.reset(new OHardRefMap
< ObjectType
>(_bCase
));
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
)) )
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
);
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(
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
);
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!");
369 _xObject
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sName
;
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
);
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());
398 m_aContainerListeners
.notifyEach( &XContainerListener::elementInserted
, aEvent
);
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));
421 void OCollection::dropImpl(sal_Int32 _nIndex
, bool _bReallyDrop
)
423 OUString elementName
= m_pElements
->getName(_nIndex
);
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) );
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()
476 void SAL_CALL
OCollection::release() throw()
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
);
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
);
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: */