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()
66 virtual void reserve(size_t nLength
) SAL_OVERRIDE
68 m_aElements
.reserve(nLength
);
71 virtual bool exists(const OUString
& _sName
) SAL_OVERRIDE
73 return m_aNameMap
.find(_sName
) != m_aNameMap
.end();
76 virtual bool empty() SAL_OVERRIDE
78 return m_aNameMap
.empty();
81 virtual void swapAll() SAL_OVERRIDE
83 ::std::vector
< ObjectIter
>(m_aElements
).swap(m_aElements
);
84 ObjectMap(m_aNameMap
).swap(m_aNameMap
);
87 virtual void swap() SAL_OVERRIDE
89 ::std::vector
< ObjectIter
>().swap(m_aElements
);
91 OSL_ENSURE( m_aNameMap
.empty(), "swap: what did disposeElements do?" );
92 ObjectMap( m_aNameMap
).swap( m_aNameMap
);
93 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
94 // swapping. This way, it's ensured that the compare object held by these maps is preserved
95 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
96 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
97 // it's case-sensitive flag would have an unpredictable value.
100 virtual void clear() SAL_OVERRIDE
106 virtual void insert(const OUString
& _sName
,const ObjectType
& _xObject
) SAL_OVERRIDE
108 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sName
,_xObject
)));
111 virtual void reFill(const TStringVector
&_rVector
) SAL_OVERRIDE
113 OSL_ENSURE(!m_aNameMap
.size(),"OCollection::reFill: collection isn't empty");
114 m_aElements
.reserve(_rVector
.size());
116 for(TStringVector::const_iterator i
=_rVector
.begin(); i
!= _rVector
.end();++i
)
117 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(*i
,ObjectType())));
120 virtual bool rename(const OUString
& _sOldName
, const OUString
& _sNewName
) SAL_OVERRIDE
123 ObjectIter aIter
= m_aNameMap
.find(_sOldName
);
124 if ( aIter
!= m_aNameMap
.end() )
126 typename ::std::vector
< ObjectIter
>::iterator aFind
= ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
);
127 if(m_aElements
.end() != aFind
)
129 (*aFind
) = m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sNewName
,(*aFind
)->second
));
130 m_aNameMap
.erase(aIter
);
138 virtual sal_Int32
size() SAL_OVERRIDE
140 return static_cast<sal_Int32
>(m_aNameMap
.size());
143 virtual Sequence
< OUString
> getElementNames() SAL_OVERRIDE
145 Sequence
< OUString
> aNameList(m_aElements
.size());
147 OUString
* pStringArray
= aNameList
.getArray();
148 typename ::std::vector
< ObjectIter
>::const_iterator aEnd
= m_aElements
.end();
149 for(typename ::std::vector
< ObjectIter
>::const_iterator aIter
= m_aElements
.begin(); aIter
!= aEnd
;++aIter
,++pStringArray
)
150 *pStringArray
= (*aIter
)->first
;
155 virtual OUString
getName(sal_Int32 _nIndex
) SAL_OVERRIDE
157 return m_aElements
[_nIndex
]->first
;
160 virtual void disposeAndErase(sal_Int32 _nIndex
) SAL_OVERRIDE
162 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
163 Reference
<XComponent
> xComp(m_aElements
[_nIndex
]->second
.get(),UNO_QUERY
);
164 ::comphelper::disposeComponent(xComp
);
165 m_aElements
[_nIndex
]->second
= T();
167 OUString sName
= m_aElements
[_nIndex
]->first
;
168 m_aElements
.erase(m_aElements
.begin()+_nIndex
);
169 m_aNameMap
.erase(sName
);
172 virtual void disposeElements() SAL_OVERRIDE
174 for( ObjectIter aIter
= m_aNameMap
.begin(); aIter
!= m_aNameMap
.end(); ++aIter
)
176 Reference
<XComponent
> xComp(aIter
->second
.get(),UNO_QUERY
);
179 ::comphelper::disposeComponent(xComp
);
180 (*aIter
).second
= T();
187 virtual sal_Int32
findColumn( const OUString
& columnName
) SAL_OVERRIDE
189 ObjectIter aIter
= m_aNameMap
.find(columnName
);
190 OSL_ENSURE(aIter
!= m_aNameMap
.end(),"findColumn:: Illegal name!");
191 return m_aElements
.size() - (m_aElements
.end() - ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
));
194 virtual OUString
findColumnAtIndex( sal_Int32 _nIndex
) SAL_OVERRIDE
196 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
197 return m_aElements
[_nIndex
]->first
;
200 virtual ObjectType
getObject(sal_Int32 _nIndex
) SAL_OVERRIDE
202 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
203 return m_aElements
[_nIndex
]->second
;
206 virtual ObjectType
getObject(const OUString
& columnName
) SAL_OVERRIDE
208 return m_aNameMap
.find(columnName
)->second
;
211 virtual void setObject(sal_Int32 _nIndex
,const ObjectType
& _xObject
) SAL_OVERRIDE
213 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
214 m_aElements
[_nIndex
]->second
= _xObject
;
217 bool isCaseSensitive() const SAL_OVERRIDE
219 return m_aNameMap
.key_comp().isCaseSensitive();
225 IObjectCollection::~IObjectCollection() {}
227 IMPLEMENT_SERVICE_INFO(OCollection
,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
229 OCollection::OCollection(::cppu::OWeakObject
& _rParent
231 , ::osl::Mutex
& _rMutex
232 , const TStringVector
&_rVector
233 , bool _bUseIndexOnly
235 :m_aContainerListeners(_rMutex
)
236 ,m_aRefreshListeners(_rMutex
)
239 ,m_bUseIndexOnly(_bUseIndexOnly
)
243 m_pElements
.reset(new OHardRefMap
< ObjectType
>(_bCase
));
247 m_pElements
.reset(new OHardRefMap
< WeakReference
< XPropertySet
> >(_bCase
));
249 m_pElements
->reFill(_rVector
);
252 OCollection::~OCollection()
256 Any SAL_CALL
OCollection::queryInterface( const Type
& rType
) throw (RuntimeException
, std::exception
)
258 if ( m_bUseIndexOnly
&& rType
== cppu::UnoType
<XNameAccess
>::get() )
262 return OCollectionBase::queryInterface( rType
);
265 Sequence
< Type
> SAL_CALL
OCollection::getTypes() throw (RuntimeException
, std::exception
)
267 if ( m_bUseIndexOnly
)
269 Sequence
< Type
> aTypes(OCollectionBase::getTypes());
270 Type
* pBegin
= aTypes
.getArray();
271 Type
* pEnd
= pBegin
+ aTypes
.getLength();
273 ::std::vector
<Type
> aOwnTypes
;
274 aOwnTypes
.reserve(aTypes
.getLength());
275 Type aType
= cppu::UnoType
<XNameAccess
>::get();
276 for(;pBegin
!= pEnd
; ++pBegin
)
278 if ( *pBegin
!= aType
)
279 aOwnTypes
.push_back(*pBegin
);
281 return Sequence
< Type
>(aOwnTypes
.data(), aOwnTypes
.size());
283 return OCollectionBase::getTypes( );
286 void OCollection::clear_NoDispose()
288 ::osl::MutexGuard
aGuard(m_rMutex
);
290 m_pElements
->clear();
291 m_pElements
->swapAll();
295 void OCollection::disposing()
297 m_aContainerListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
298 m_aRefreshListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
300 ::osl::MutexGuard
aGuard(m_rMutex
);
307 Any SAL_CALL
OCollection::getByIndex( sal_Int32 Index
) throw(IndexOutOfBoundsException
, WrappedTargetException
, RuntimeException
, std::exception
)
309 ::osl::MutexGuard
aGuard(m_rMutex
);
310 if (Index
< 0 || Index
>= m_pElements
->size() )
311 throw IndexOutOfBoundsException(OUString::number(Index
),static_cast<XTypeProvider
*>(this));
313 return makeAny(getObject(Index
));
316 Any SAL_CALL
OCollection::getByName( const OUString
& aName
) throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
, std::exception
)
318 ::osl::MutexGuard
aGuard(m_rMutex
);
320 if ( !m_pElements
->exists(aName
) )
322 ::connectivity::SharedResources aResources
;
323 const OUString
sError( aResources
.getResourceStringWithSubstitution(
327 throw NoSuchElementException( sError
, static_cast< XTypeProvider
* >( this ) );
330 return makeAny(getObject(m_pElements
->findColumn(aName
)));
333 Sequence
< OUString
> SAL_CALL
OCollection::getElementNames( ) throw(RuntimeException
, std::exception
)
335 ::osl::MutexGuard
aGuard(m_rMutex
);
336 return m_pElements
->getElementNames();
339 void SAL_CALL
OCollection::refresh( ) throw(RuntimeException
, std::exception
)
341 ::osl::MutexGuard
aGuard(m_rMutex
);
346 EventObject
aEvt(static_cast<XTypeProvider
*>(this));
347 m_aRefreshListeners
.notifyEach( &XRefreshListener::refreshed
, aEvt
);
350 void OCollection::reFill(const TStringVector
&_rVector
)
352 m_pElements
->reFill(_rVector
);
355 // XDataDescriptorFactory
356 Reference
< XPropertySet
> SAL_CALL
OCollection::createDataDescriptor( ) throw(RuntimeException
, std::exception
)
358 ::osl::MutexGuard
aGuard(m_rMutex
);
360 return createDescriptor();
363 OUString
OCollection::getNameForObject(const ObjectType
& _xObject
)
365 OSL_ENSURE(_xObject
.is(),"OCollection::getNameForObject: Object is NULL!");
367 _xObject
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sName
;
372 void SAL_CALL
OCollection::appendByDescriptor( const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, ElementExistException
, RuntimeException
, std::exception
)
374 ::osl::ClearableMutexGuard
aGuard(m_rMutex
);
376 OUString sName
= getNameForObject( descriptor
);
378 if ( m_pElements
->exists(sName
) )
379 throw ElementExistException(sName
,static_cast<XTypeProvider
*>(this));
381 ObjectType xNewlyCreated
= appendObject( sName
, descriptor
);
382 if ( !xNewlyCreated
.is() )
383 throw RuntimeException();
385 ODescriptor
* pDescriptor
= ODescriptor::getImplementation( xNewlyCreated
);
387 pDescriptor
->setNew( false );
389 sName
= getNameForObject( xNewlyCreated
);
390 if ( !m_pElements
->exists( sName
) ) // this may happen when the derived class included it itself
391 m_pElements
->insert( sName
, xNewlyCreated
);
393 // notify our container listeners
394 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(sName
), makeAny(xNewlyCreated
), Any());
396 m_aContainerListeners
.notifyEach( &XContainerListener::elementInserted
, aEvent
);
400 void SAL_CALL
OCollection::dropByName( const OUString
& elementName
) throw(SQLException
, NoSuchElementException
, RuntimeException
, std::exception
)
402 ::osl::MutexGuard
aGuard(m_rMutex
);
404 if ( !m_pElements
->exists(elementName
) )
405 throw NoSuchElementException(elementName
,static_cast<XTypeProvider
*>(this));
407 dropImpl(m_pElements
->findColumn(elementName
));
410 void SAL_CALL
OCollection::dropByIndex( sal_Int32 index
) throw(SQLException
, IndexOutOfBoundsException
, RuntimeException
, std::exception
)
412 ::osl::MutexGuard
aGuard(m_rMutex
);
413 if(index
<0 || index
>= getCount())
414 throw IndexOutOfBoundsException(OUString::number(index
),static_cast<XTypeProvider
*>(this));
419 void OCollection::dropImpl(sal_Int32 _nIndex
, bool _bReallyDrop
)
421 OUString elementName
= m_pElements
->getName(_nIndex
);
424 dropObject(_nIndex
,elementName
);
426 m_pElements
->disposeAndErase(_nIndex
);
428 // notify our container listeners
429 notifyElementRemoved(elementName
);
432 void OCollection::notifyElementRemoved(const OUString
& _sName
)
434 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sName
), Any(), Any());
435 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
436 OInterfaceIteratorHelper
aListenerLoop(m_aContainerListeners
);
437 while (aListenerLoop
.hasMoreElements())
438 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementRemoved(aEvent
);
441 sal_Int32 SAL_CALL
OCollection::findColumn( const OUString
& columnName
) throw(SQLException
, RuntimeException
, std::exception
)
443 if ( !m_pElements
->exists(columnName
) )
445 ::dbtools::throwInvalidColumnException( columnName
, static_cast< XIndexAccess
*>(this) );
449 return m_pElements
->findColumn(columnName
) + 1; // because columns start at one
452 Reference
< XEnumeration
> SAL_CALL
OCollection::createEnumeration( ) throw(RuntimeException
, std::exception
)
454 ::osl::MutexGuard
aGuard(m_rMutex
);
455 return new OEnumerationByIndex( static_cast< XIndexAccess
*>(this));
458 void SAL_CALL
OCollection::addContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
, std::exception
)
460 m_aContainerListeners
.addInterface(_rxListener
);
464 void SAL_CALL
OCollection::removeContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
, std::exception
)
466 m_aContainerListeners
.removeInterface(_rxListener
);
469 void SAL_CALL
OCollection::acquire() throw()
474 void SAL_CALL
OCollection::release() throw()
479 Type SAL_CALL
OCollection::getElementType( ) throw(RuntimeException
, std::exception
)
481 return cppu::UnoType
<XPropertySet
>::get();
484 sal_Bool SAL_CALL
OCollection::hasElements( ) throw(RuntimeException
, std::exception
)
486 ::osl::MutexGuard
aGuard(m_rMutex
);
487 return !m_pElements
->empty();
490 sal_Int32 SAL_CALL
OCollection::getCount( ) throw(RuntimeException
, std::exception
)
492 ::osl::MutexGuard
aGuard(m_rMutex
);
493 return m_pElements
->size();
496 sal_Bool SAL_CALL
OCollection::hasByName( const OUString
& aName
) throw(RuntimeException
, std::exception
)
498 ::osl::MutexGuard
aGuard(m_rMutex
);
499 return m_pElements
->exists(aName
);
502 void SAL_CALL
OCollection::addRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
, std::exception
)
504 m_aRefreshListeners
.addInterface(l
);
507 void SAL_CALL
OCollection::removeRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
, std::exception
)
509 m_aRefreshListeners
.removeInterface(l
);
512 void OCollection::insertElement(const OUString
& _sElementName
,const ObjectType
& _xElement
)
514 OSL_ENSURE(!m_pElements
->exists(_sElementName
),"Element already exists");
515 if ( !m_pElements
->exists(_sElementName
) )
516 m_pElements
->insert(_sElementName
,_xElement
);
519 void OCollection::renameObject(const OUString
& _sOldName
, const OUString
& _sNewName
)
521 OSL_ENSURE(m_pElements
->exists(_sOldName
),"Element doesn't exist");
522 OSL_ENSURE(!m_pElements
->exists(_sNewName
),"Element already exists");
523 OSL_ENSURE(!_sNewName
.isEmpty(),"New name must not be empty!");
524 OSL_ENSURE(!_sOldName
.isEmpty(),"Old name must not be empty!");
526 if ( m_pElements
->rename(_sOldName
,_sNewName
) )
528 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sNewName
), makeAny(m_pElements
->getObject(_sNewName
)),makeAny(_sOldName
));
529 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
530 OInterfaceIteratorHelper
aListenerLoop(m_aContainerListeners
);
531 while (aListenerLoop
.hasMoreElements())
532 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementReplaced(aEvent
);
536 ObjectType
OCollection::getObject(sal_Int32 _nIndex
)
538 ObjectType xName
= m_pElements
->getObject(_nIndex
);
543 xName
= createObject(m_pElements
->getName(_nIndex
));
545 catch(const SQLException
& e
)
549 dropImpl(_nIndex
,false);
551 catch(const Exception
& )
554 throw WrappedTargetException(e
.Message
,static_cast<XTypeProvider
*>(this),makeAny(e
));
556 m_pElements
->setObject(_nIndex
,xName
);
561 void OCollection::disposeElements()
563 m_pElements
->disposeElements();
566 Reference
< XPropertySet
> OCollection::createDescriptor()
568 OSL_FAIL("createDescriptor() needs to be overridden when used!");
569 throw SQLException();
572 ObjectType
OCollection::cloneDescriptor( const ObjectType
& _descriptor
)
574 ObjectType
xNewDescriptor( createDescriptor() );
575 ::comphelper::copyProperties( _descriptor
, xNewDescriptor
);
576 return xNewDescriptor
;
579 ObjectType
OCollection::appendObject( const OUString
& /*_rForName*/, const Reference
< XPropertySet
>& descriptor
)
581 return cloneDescriptor( descriptor
);
584 void OCollection::dropObject(sal_Int32
/*_nPos*/, const OUString
& /*_sElementName*/)
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */