1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: VCollection.cxx,v $
10 * $Revision: 1.43.56.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
36 #include "connectivity/sdbcx/VCollection.hxx"
37 #include "connectivity/sdbcx/VDescriptor.hxx"
38 #include "connectivity/dbexception.hxx"
39 #include <comphelper/enumhelper.hxx>
40 #include <comphelper/container.hxx>
41 #include <comphelper/types.hxx>
42 #include <comphelper/property.hxx>
43 #include "TConnection.hxx"
44 #include <rtl/ustrbuf.hxx>
45 #include "resource/common_res.hrc"
46 #include "resource/sharedresources.hxx"
48 using namespace connectivity::sdbcx
;
49 using namespace connectivity
;
50 using namespace comphelper
;
51 using namespace ::cppu
;
52 using namespace ::com::sun::star::beans
;
53 using namespace ::com::sun::star::uno
;
54 using namespace ::com::sun::star::lang
;
55 using namespace ::com::sun::star::sdbc
;
56 using namespace ::com::sun::star::container
;
57 using namespace ::com::sun::star::util
;
61 template < typename T
> class OHardRefMap
: public connectivity::sdbcx::IObjectCollection
63 typedef ::std::multimap
< ::rtl::OUString
, T
, ::comphelper::UStringMixLess
> ObjectMap
;
64 typedef typename
ObjectMap::iterator ObjectIter
;
65 typedef typename
ObjectMap::value_type ObjectEntry
;
68 // this combination of map and vector is used to have a fast name and index access
69 ::std::vector
< ObjectIter
> m_aElements
; // hold the iterators which point to map
70 ObjectMap m_aNameMap
; // hold the elements and a name
72 OHardRefMap(sal_Bool _bCase
)
73 : m_aNameMap(_bCase
? true : false)
76 virtual ~OHardRefMap()
80 virtual void reserve(size_t nLength
)
82 m_aElements
.reserve(nLength
);
84 // -----------------------------------------------------------------------------
85 virtual bool exists(const ::rtl::OUString
& _sName
)
87 return m_aNameMap
.find(_sName
) != m_aNameMap
.end();
89 // -----------------------------------------------------------------------------
92 return m_aNameMap
.empty();
94 // -----------------------------------------------------------------------------
95 virtual void swapAll()
97 ::std::vector
< ObjectIter
>(m_aElements
).swap(m_aElements
);
98 ObjectMap(m_aNameMap
).swap(m_aNameMap
);
100 // -----------------------------------------------------------------------------
103 ::std::vector
< ObjectIter
>().swap(m_aElements
);
105 OSL_ENSURE( m_aNameMap
.empty(), "swap: what did disposeElements do?" );
106 ObjectMap( m_aNameMap
).swap( m_aNameMap
);
107 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
108 // swapping. This way, it's ensured that the compare object held by these maps is preserved
109 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
110 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
111 // it's case-sensitive flag would have an unpredictable value.
112 // 2002-01-09 - #106589# - fs@openoffice.org
114 // -----------------------------------------------------------------------------
120 // -----------------------------------------------------------------------------
121 virtual void insert(const ::rtl::OUString
& _sName
,const ObjectType
& _xObject
)
123 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sName
,_xObject
)));
125 // -----------------------------------------------------------------------------
126 virtual void reFill(const TStringVector
&_rVector
)
128 OSL_ENSURE(!m_aNameMap
.size(),"OCollection::reFill: collection isn't empty");
129 m_aElements
.reserve(_rVector
.size());
131 for(TStringVector::const_iterator i
=_rVector
.begin(); i
!= _rVector
.end();++i
)
132 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(*i
,ObjectType())));
134 // -----------------------------------------------------------------------------
135 virtual bool rename(const ::rtl::OUString _sOldName
,const ::rtl::OUString _sNewName
)
138 ObjectIter aIter
= m_aNameMap
.find(_sOldName
);
139 if ( aIter
!= m_aNameMap
.end() )
141 typename ::std::vector
< ObjectIter
>::iterator aFind
= ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
);
142 if(m_aElements
.end() != aFind
)
144 (*aFind
) = m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sNewName
,(*aFind
)->second
));
145 m_aNameMap
.erase(aIter
);
152 // -----------------------------------------------------------------------------
153 virtual sal_Int32
size()
155 return static_cast<sal_Int32
>(m_aNameMap
.size());
157 // -----------------------------------------------------------------------------
158 virtual Sequence
< ::rtl::OUString
> getElementNames()
160 Sequence
< ::rtl::OUString
> aNameList(m_aElements
.size());
162 ::rtl::OUString
* pStringArray
= aNameList
.getArray();
163 typename ::std::vector
< ObjectIter
>::const_iterator aEnd
= m_aElements
.end();
164 for(typename ::std::vector
< ObjectIter
>::const_iterator aIter
= m_aElements
.begin(); aIter
!= aEnd
;++aIter
,++pStringArray
)
165 *pStringArray
= (*aIter
)->first
;
169 // -----------------------------------------------------------------------------
170 virtual ::rtl::OUString
getName(sal_Int32 _nIndex
)
172 return m_aElements
[_nIndex
]->first
;
174 // -----------------------------------------------------------------------------
175 virtual void disposeAndErase(sal_Int32 _nIndex
)
177 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
178 Reference
<XComponent
> xComp(m_aElements
[_nIndex
]->second
.get(),UNO_QUERY
);
179 ::comphelper::disposeComponent(xComp
);
180 m_aElements
[_nIndex
]->second
= T();
182 ::rtl::OUString sName
= m_aElements
[_nIndex
]->first
;
183 m_aElements
.erase(m_aElements
.begin()+_nIndex
);
184 m_aNameMap
.erase(sName
);
186 // -----------------------------------------------------------------------------
187 virtual void disposeElements()
189 for( ObjectIter aIter
= m_aNameMap
.begin(); aIter
!= m_aNameMap
.end(); ++aIter
)
191 Reference
<XComponent
> xComp(aIter
->second
.get(),UNO_QUERY
);
194 ::comphelper::disposeComponent(xComp
);
195 (*aIter
).second
= T();
201 // -----------------------------------------------------------------------------
202 virtual sal_Int32
findColumn( const ::rtl::OUString
& columnName
)
204 ObjectIter aIter
= m_aNameMap
.find(columnName
);
205 OSL_ENSURE(aIter
!= m_aNameMap
.end(),"findColumn:: Illegal name!");
206 return m_aElements
.size() - (m_aElements
.end() - ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
));
208 // -----------------------------------------------------------------------------
209 virtual ::rtl::OUString
findColumnAtIndex( sal_Int32 _nIndex
)
211 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
212 return m_aElements
[_nIndex
]->first
;
214 // -----------------------------------------------------------------------------
215 virtual ObjectType
getObject(sal_Int32 _nIndex
)
217 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
218 return m_aElements
[_nIndex
]->second
;
220 // -----------------------------------------------------------------------------
221 virtual ObjectType
getObject(const ::rtl::OUString
& columnName
)
223 return m_aNameMap
.find(columnName
)->second
;
225 // -----------------------------------------------------------------------------
226 virtual void setObject(sal_Int32 _nIndex
,const ObjectType
& _xObject
)
228 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
229 m_aElements
[_nIndex
]->second
= _xObject
;
231 // -----------------------------------------------------------------------------
232 sal_Bool
isCaseSensitive() const
234 return m_aNameMap
.key_comp().isCaseSensitive();
236 // -----------------------------------------------------------------------------
239 // -----------------------------------------------------------------------------
241 IMPLEMENT_SERVICE_INFO(OCollection
,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
243 OCollection::OCollection(::cppu::OWeakObject
& _rParent
245 , ::osl::Mutex
& _rMutex
246 , const TStringVector
&_rVector
247 , sal_Bool _bUseIndexOnly
248 , sal_Bool _bUseHardRef
)
249 :m_aContainerListeners(_rMutex
)
250 ,m_aRefreshListeners(_rMutex
)
253 ,m_bUseIndexOnly(_bUseIndexOnly
)
257 m_pElements
.reset(new OHardRefMap
< ObjectType
>(_bCase
));
261 m_pElements
.reset(new OHardRefMap
< WeakReference
< XPropertySet
> >(_bCase
));
263 m_pElements
->reFill(_rVector
);
265 // -------------------------------------------------------------------------
266 OCollection::~OCollection()
269 // -----------------------------------------------------------------------------
270 Any SAL_CALL
OCollection::queryInterface( const Type
& rType
) throw (RuntimeException
)
272 if ( m_bUseIndexOnly
&& rType
== ::getCppuType(static_cast< Reference
< XNameAccess
> *> (NULL
)) )
276 return OCollectionBase::queryInterface( rType
);
278 // -----------------------------------------------------------------------------
279 Sequence
< Type
> SAL_CALL
OCollection::getTypes() throw (RuntimeException
)
281 if ( m_bUseIndexOnly
)
283 Sequence
< Type
> aTypes(OCollectionBase::getTypes());
284 Type
* pBegin
= aTypes
.getArray();
285 Type
* pEnd
= pBegin
+ aTypes
.getLength();
287 ::std::vector
<Type
> aOwnTypes
;
288 aOwnTypes
.reserve(aTypes
.getLength());
289 Type aType
= ::getCppuType(static_cast< Reference
<XNameAccess
> *>(NULL
));
290 for(;pBegin
!= pEnd
; ++pBegin
)
292 if ( *pBegin
!= aType
)
293 aOwnTypes
.push_back(*pBegin
);
295 Type
* pTypes
= aOwnTypes
.empty() ? 0 : &aOwnTypes
[0];
296 return Sequence
< Type
>(pTypes
,aOwnTypes
.size());
298 return OCollectionBase::getTypes( );
300 // -------------------------------------------------------------------------
301 void OCollection::clear_NoDispose()
303 ::osl::MutexGuard
aGuard(m_rMutex
);
305 m_pElements
->clear();
306 m_pElements
->swapAll();
309 // -------------------------------------------------------------------------
310 void OCollection::disposing(void)
312 m_aContainerListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
313 m_aRefreshListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
315 ::osl::MutexGuard
aGuard(m_rMutex
);
321 // -------------------------------------------------------------------------
322 Any SAL_CALL
OCollection::getByIndex( sal_Int32 Index
) throw(IndexOutOfBoundsException
, WrappedTargetException
, RuntimeException
)
324 ::osl::MutexGuard
aGuard(m_rMutex
);
325 if (Index
< 0 || Index
>= m_pElements
->size() )
326 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(Index
),static_cast<XTypeProvider
*>(this));
328 return makeAny(getObject(Index
));
330 // -------------------------------------------------------------------------
331 Any SAL_CALL
OCollection::getByName( const ::rtl::OUString
& aName
) throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
)
333 ::osl::MutexGuard
aGuard(m_rMutex
);
335 if ( !m_pElements
->exists(aName
) )
337 ::connectivity::SharedResources aResources
;
338 const ::rtl::OUString
sError( aResources
.getResourceStringWithSubstitution(
342 throw NoSuchElementException( sError
, static_cast< XTypeProvider
* >( this ) );
345 return makeAny(getObject(m_pElements
->findColumn(aName
)));
347 // -------------------------------------------------------------------------
348 Sequence
< ::rtl::OUString
> SAL_CALL
OCollection::getElementNames( ) throw(RuntimeException
)
350 ::osl::MutexGuard
aGuard(m_rMutex
);
351 return m_pElements
->getElementNames();
353 // -------------------------------------------------------------------------
354 void SAL_CALL
OCollection::refresh( ) throw(RuntimeException
)
356 ::osl::MutexGuard
aGuard(m_rMutex
);
361 EventObject
aEvt(static_cast<XTypeProvider
*>(this));
362 m_aRefreshListeners
.notifyEach( &XRefreshListener::refreshed
, aEvt
);
364 // -----------------------------------------------------------------------------
365 void OCollection::reFill(const TStringVector
&_rVector
)
367 m_pElements
->reFill(_rVector
);
369 // -------------------------------------------------------------------------
370 // XDataDescriptorFactory
371 Reference
< XPropertySet
> SAL_CALL
OCollection::createDataDescriptor( ) throw(RuntimeException
)
373 ::osl::MutexGuard
aGuard(m_rMutex
);
375 return createDescriptor();
377 // -----------------------------------------------------------------------------
378 ::rtl::OUString
OCollection::getNameForObject(const ObjectType
& _xObject
)
380 OSL_ENSURE(_xObject
.is(),"OCollection::getNameForObject: Object is NULL!");
381 ::rtl::OUString sName
;
382 _xObject
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sName
;
385 // -------------------------------------------------------------------------
387 void SAL_CALL
OCollection::appendByDescriptor( const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, ElementExistException
, RuntimeException
)
389 ::osl::ClearableMutexGuard
aGuard(m_rMutex
);
391 ::rtl::OUString sName
= getNameForObject( descriptor
);
393 if ( m_pElements
->exists(sName
) )
394 throw ElementExistException(sName
,static_cast<XTypeProvider
*>(this));
396 ObjectType xNewlyCreated
= appendObject( sName
, descriptor
);
397 if ( !xNewlyCreated
.is() )
398 throw RuntimeException();
400 ODescriptor
* pDescriptor
= ODescriptor::getImplementation( xNewlyCreated
);
402 pDescriptor
->setNew( sal_False
);
404 sName
= getNameForObject( xNewlyCreated
);
405 if ( !m_pElements
->exists( sName
) ) // this may happen when the drived class included it itself
406 m_pElements
->insert( sName
, xNewlyCreated
);
408 // notify our container listeners
409 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(sName
), makeAny(xNewlyCreated
), Any());
411 m_aContainerListeners
.notifyEach( &XContainerListener::elementInserted
, aEvent
);
413 // -------------------------------------------------------------------------
415 void SAL_CALL
OCollection::dropByName( const ::rtl::OUString
& elementName
) throw(SQLException
, NoSuchElementException
, RuntimeException
)
417 ::osl::MutexGuard
aGuard(m_rMutex
);
419 if ( !m_pElements
->exists(elementName
) )
420 throw NoSuchElementException(elementName
,static_cast<XTypeProvider
*>(this));
422 dropImpl(m_pElements
->findColumn(elementName
));
424 // -------------------------------------------------------------------------
425 void SAL_CALL
OCollection::dropByIndex( sal_Int32 index
) throw(SQLException
, IndexOutOfBoundsException
, RuntimeException
)
427 ::osl::MutexGuard
aGuard(m_rMutex
);
428 if(index
<0 || index
>= getCount())
429 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index
),static_cast<XTypeProvider
*>(this));
433 // -----------------------------------------------------------------------------
434 void OCollection::dropImpl(sal_Int32 _nIndex
,sal_Bool _bReallyDrop
)
436 ::rtl::OUString elementName
= m_pElements
->getName(_nIndex
);
439 dropObject(_nIndex
,elementName
);
441 m_pElements
->disposeAndErase(_nIndex
);
443 // notify our container listeners
444 notifyElementRemoved(elementName
);
446 // -----------------------------------------------------------------------------
447 void OCollection::notifyElementRemoved(const ::rtl::OUString
& _sName
)
449 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sName
), Any(), Any());
450 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
451 OInterfaceIteratorHelper
aListenerLoop(m_aContainerListeners
);
452 while (aListenerLoop
.hasMoreElements())
453 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementRemoved(aEvent
);
455 // -------------------------------------------------------------------------
456 sal_Int32 SAL_CALL
OCollection::findColumn( const ::rtl::OUString
& columnName
) throw(SQLException
, RuntimeException
)
458 if ( !m_pElements
->exists(columnName
) )
460 ::connectivity::SharedResources aResources
;
461 const ::rtl::OUString
sError( aResources
.getResourceStringWithSubstitution(
462 STR_UNKNOWN_COLUMN_NAME
,
463 "$columnname$", columnName
465 ::dbtools::throwGenericSQLException(sError
,static_cast< XIndexAccess
*>(this));
468 return m_pElements
->findColumn(columnName
) + 1; // because columns start at one
470 // -------------------------------------------------------------------------
471 Reference
< XEnumeration
> SAL_CALL
OCollection::createEnumeration( ) throw(RuntimeException
)
473 ::osl::MutexGuard
aGuard(m_rMutex
);
474 return new OEnumerationByIndex( static_cast< XIndexAccess
*>(this));
476 // -----------------------------------------------------------------------------
477 void SAL_CALL
OCollection::addContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
)
479 m_aContainerListeners
.addInterface(_rxListener
);
482 //------------------------------------------------------------------------------
483 void SAL_CALL
OCollection::removeContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
)
485 m_aContainerListeners
.removeInterface(_rxListener
);
487 // -----------------------------------------------------------------------------
488 void SAL_CALL
OCollection::acquire() throw()
492 // -----------------------------------------------------------------------------
493 void SAL_CALL
OCollection::release() throw()
497 // -----------------------------------------------------------------------------
498 Type SAL_CALL
OCollection::getElementType( ) throw(RuntimeException
)
500 return::getCppuType(static_cast< Reference
< XPropertySet
>*>(NULL
));
502 // -----------------------------------------------------------------------------
503 sal_Bool SAL_CALL
OCollection::hasElements( ) throw(RuntimeException
)
505 ::osl::MutexGuard
aGuard(m_rMutex
);
506 return !m_pElements
->empty();
508 // -----------------------------------------------------------------------------
509 sal_Int32 SAL_CALL
OCollection::getCount( ) throw(RuntimeException
)
511 ::osl::MutexGuard
aGuard(m_rMutex
);
512 return m_pElements
->size();
514 // -----------------------------------------------------------------------------
515 sal_Bool SAL_CALL
OCollection::hasByName( const ::rtl::OUString
& aName
) throw(RuntimeException
)
517 ::osl::MutexGuard
aGuard(m_rMutex
);
518 return m_pElements
->exists(aName
);
520 // -----------------------------------------------------------------------------
521 void SAL_CALL
OCollection::addRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
)
523 m_aRefreshListeners
.addInterface(l
);
525 // -----------------------------------------------------------------------------
526 void SAL_CALL
OCollection::removeRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
)
528 m_aRefreshListeners
.removeInterface(l
);
530 // -----------------------------------------------------------------------------
531 void OCollection::insertElement(const ::rtl::OUString
& _sElementName
,const ObjectType
& _xElement
)
533 OSL_ENSURE(!m_pElements
->exists(_sElementName
),"Element already exists");
534 if ( !m_pElements
->exists(_sElementName
) )
535 m_pElements
->insert(_sElementName
,_xElement
);
537 // -----------------------------------------------------------------------------
538 void OCollection::renameObject(const ::rtl::OUString _sOldName
,const ::rtl::OUString _sNewName
)
540 OSL_ENSURE(m_pElements
->exists(_sOldName
),"Element doesn't exist");
541 OSL_ENSURE(!m_pElements
->exists(_sNewName
),"Element already exists");
542 OSL_ENSURE(_sNewName
.getLength(),"New name must not be empty!");
543 OSL_ENSURE(_sOldName
.getLength(),"New name must not be empty!");
545 if ( m_pElements
->rename(_sOldName
,_sNewName
) )
547 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sNewName
), makeAny(m_pElements
->getObject(_sNewName
)),makeAny(_sOldName
));
548 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
549 OInterfaceIteratorHelper
aListenerLoop(m_aContainerListeners
);
550 while (aListenerLoop
.hasMoreElements())
551 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementReplaced(aEvent
);
554 // -----------------------------------------------------------------------------
555 ObjectType
OCollection::getObject(sal_Int32 _nIndex
)
557 ObjectType xName
= m_pElements
->getObject(_nIndex
);
562 xName
= createObject(m_pElements
->getName(_nIndex
));
564 catch(const SQLException
& e
)
568 dropImpl(_nIndex
,sal_False
);
570 catch(const Exception
& )
573 throw WrappedTargetException(e
.Message
,static_cast<XTypeProvider
*>(this),makeAny(e
));
575 m_pElements
->setObject(_nIndex
,xName
);
579 // -----------------------------------------------------------------------------
580 void OCollection::disposeElements()
582 m_pElements
->disposeElements();
584 // -----------------------------------------------------------------------------
585 Reference
< XPropertySet
> OCollection::createDescriptor()
587 OSL_ASSERT(!"Need to be overloaded when used!");
588 throw SQLException();
590 // -----------------------------------------------------------------------------
591 ObjectType
OCollection::cloneDescriptor( const ObjectType
& _descriptor
)
593 ObjectType
xNewDescriptor( createDescriptor() );
594 ::comphelper::copyProperties( _descriptor
, xNewDescriptor
);
595 return xNewDescriptor
;
597 // -----------------------------------------------------------------------------
598 ObjectType
OCollection::appendObject( const ::rtl::OUString
& /*_rForName*/, const Reference
< XPropertySet
>& descriptor
)
600 return cloneDescriptor( descriptor
);
602 // -----------------------------------------------------------------------------
603 void OCollection::dropObject(sal_Int32
/*_nPos*/,const ::rtl::OUString
/*_sElementName*/)
606 // -----------------------------------------------------------------------------