1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_connectivity.hxx"
30 
31 #include <algorithm>
32 #include <stdio.h>
33 #include "connectivity/sdbcx/VCollection.hxx"
34 #include "connectivity/sdbcx/VDescriptor.hxx"
35 #include "connectivity/dbexception.hxx"
36 #include <comphelper/enumhelper.hxx>
37 #include <comphelper/container.hxx>
38 #include <comphelper/types.hxx>
39 #include <comphelper/property.hxx>
40 #include "TConnection.hxx"
41 #include <rtl/ustrbuf.hxx>
42 #include "resource/common_res.hrc"
43 #include "resource/sharedresources.hxx"
44 
45 using namespace connectivity::sdbcx;
46 using namespace connectivity;
47 using namespace comphelper;
48 using namespace ::cppu;
49 using namespace ::com::sun::star::beans;
50 using namespace ::com::sun::star::uno;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::sdbc;
53 using namespace ::com::sun::star::container;
54 using namespace ::com::sun::star::util;
55 
56 namespace
57 {
58 	template < typename T> class OHardRefMap : public connectivity::sdbcx::IObjectCollection
59 	{
60 		typedef ::std::multimap< ::rtl::OUString, T , ::comphelper::UStringMixLess> ObjectMap;
61 		typedef typename ObjectMap::iterator   ObjectIter;
62 		typedef typename ObjectMap::value_type ObjectEntry;
63 
64 	//	private:
65 		// this combination of map and vector is used to have a fast name and index access
66 		::std::vector< ObjectIter >				m_aElements;		// hold the iterators which point to map
67 		ObjectMap								m_aNameMap;			// hold the elements and a name
68 	public:
69 		OHardRefMap(sal_Bool _bCase)
70 			: m_aNameMap(_bCase ? true : false)
71 		{
72 		}
73         virtual ~OHardRefMap()
74         {
75         }
76 
77 		virtual void reserve(size_t nLength)
78 		{
79 			m_aElements.reserve(nLength);
80 		}
81 		// -----------------------------------------------------------------------------
82 		virtual bool exists(const ::rtl::OUString& _sName )
83 		{
84 			return m_aNameMap.find(_sName) != m_aNameMap.end();
85 		}
86 		// -----------------------------------------------------------------------------
87 		virtual bool empty()
88 		{
89 			return m_aNameMap.empty();
90 		}
91 		// -----------------------------------------------------------------------------
92 		virtual void swapAll()
93 		{
94 			::std::vector< ObjectIter >(m_aElements).swap(m_aElements);
95 			ObjectMap(m_aNameMap).swap(m_aNameMap);
96 		}
97 		// -----------------------------------------------------------------------------
98 		virtual void swap()
99 		{
100 			::std::vector< ObjectIter >().swap(m_aElements);
101 
102 			OSL_ENSURE( m_aNameMap.empty(), "swap: what did disposeElements do?" );
103 			ObjectMap( m_aNameMap ).swap( m_aNameMap );
104 				// Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
105 				// swapping. This way, it's ensured that the compare object held by these maps is preserved
106 				// during the swap. If we would not do this, the UStringMixLess instance which is used would be
107 				// default constructed (instead of being constructed from the same instance in m_aNameMap), and
108 				// it's case-sensitive flag would have an unpredictable value.
109 				// 2002-01-09 - #106589# - fs@openoffice.org
110 		}
111 		// -----------------------------------------------------------------------------
112 		virtual void clear()
113 		{
114 			m_aElements.clear();
115 			m_aNameMap.clear();
116 		}
117 		// -----------------------------------------------------------------------------
118 		virtual void insert(const ::rtl::OUString& _sName,const ObjectType& _xObject)
119 		{
120 			m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sName,_xObject)));
121 		}
122 		// -----------------------------------------------------------------------------
123 		virtual void reFill(const TStringVector &_rVector)
124 		{
125 			OSL_ENSURE(!m_aNameMap.size(),"OCollection::reFill: collection isn't empty");
126 			m_aElements.reserve(_rVector.size());
127 
128 			for(TStringVector::const_iterator i=_rVector.begin(); i != _rVector.end();++i)
129 				m_aElements.push_back(m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(*i,ObjectType())));
130 		}
131 		// -----------------------------------------------------------------------------
132 		virtual bool rename(const ::rtl::OUString _sOldName,const ::rtl::OUString _sNewName)
133 		{
134 			bool bRet = false;
135 			ObjectIter aIter = m_aNameMap.find(_sOldName);
136 			if ( aIter != m_aNameMap.end() )
137 			{
138 				typename ::std::vector< ObjectIter >::iterator aFind = ::std::find(m_aElements.begin(),m_aElements.end(),aIter);
139 				if(m_aElements.end() != aFind)
140 				{
141 					(*aFind) = m_aNameMap.insert(m_aNameMap.begin(), ObjectEntry(_sNewName,(*aFind)->second));
142 					m_aNameMap.erase(aIter);
143 
144 					bRet = true;
145 				}
146 			}
147 			return bRet;
148 		}
149 		// -----------------------------------------------------------------------------
150 		virtual sal_Int32 size()
151 		{
152 			return static_cast<sal_Int32>(m_aNameMap.size());
153 		}
154 		// -----------------------------------------------------------------------------
155 		virtual Sequence< ::rtl::OUString > getElementNames()
156 		{
157 			Sequence< ::rtl::OUString > aNameList(m_aElements.size());
158 
159 			::rtl::OUString* pStringArray = aNameList.getArray();
160             typename ::std::vector< ObjectIter >::const_iterator aEnd = m_aElements.end();
161 			for(typename ::std::vector< ObjectIter >::const_iterator aIter = m_aElements.begin(); aIter != aEnd;++aIter,++pStringArray)
162 				*pStringArray = (*aIter)->first;
163 
164 			return aNameList;
165 		}
166 		// -----------------------------------------------------------------------------
167 		virtual ::rtl::OUString getName(sal_Int32 _nIndex)
168 		{
169 			return m_aElements[_nIndex]->first;
170 		}
171 		// -----------------------------------------------------------------------------
172 		virtual void disposeAndErase(sal_Int32 _nIndex)
173 		{
174 			OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
175 			Reference<XComponent> xComp(m_aElements[_nIndex]->second.get(),UNO_QUERY);
176 			::comphelper::disposeComponent(xComp);
177 			m_aElements[_nIndex]->second = T();
178 
179 			::rtl::OUString sName = m_aElements[_nIndex]->first;
180 			m_aElements.erase(m_aElements.begin()+_nIndex);
181 			m_aNameMap.erase(sName);
182 		}
183 		// -----------------------------------------------------------------------------
184 		virtual void disposeElements()
185 		{
186 			for( ObjectIter aIter = m_aNameMap.begin(); aIter != m_aNameMap.end(); ++aIter)
187 			{
188 				Reference<XComponent> xComp(aIter->second.get(),UNO_QUERY);
189 				if ( xComp.is() )
190 				{
191 					::comphelper::disposeComponent(xComp);
192 					(*aIter).second = T();
193 				}
194 			}
195 			m_aElements.clear();
196 			m_aNameMap.clear();
197 		}
198 		// -----------------------------------------------------------------------------
199 		virtual sal_Int32 findColumn( const ::rtl::OUString& columnName )
200 		{
201 			ObjectIter aIter = m_aNameMap.find(columnName);
202 			OSL_ENSURE(aIter != m_aNameMap.end(),"findColumn:: Illegal name!");
203 			return m_aElements.size() - (m_aElements.end() - ::std::find(m_aElements.begin(),m_aElements.end(),aIter));
204 		}
205 		// -----------------------------------------------------------------------------
206 		virtual ::rtl::OUString findColumnAtIndex(  sal_Int32 _nIndex)
207 		{
208 			OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
209 			return m_aElements[_nIndex]->first;
210 		}
211 		// -----------------------------------------------------------------------------
212 		virtual ObjectType getObject(sal_Int32 _nIndex)
213 		{
214 			OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
215 			return m_aElements[_nIndex]->second;
216 		}
217 		// -----------------------------------------------------------------------------
218 		virtual ObjectType getObject(const ::rtl::OUString& columnName)
219 		{
220 			return m_aNameMap.find(columnName)->second;
221 		}
222 		// -----------------------------------------------------------------------------
223 		virtual void setObject(sal_Int32 _nIndex,const ObjectType& _xObject)
224 		{
225 			OSL_ENSURE(_nIndex >= 0 && _nIndex < static_cast<sal_Int32>(m_aElements.size()),"Illegal argument!");
226 			m_aElements[_nIndex]->second = _xObject;
227 		}
228 		// -----------------------------------------------------------------------------
229 		sal_Bool isCaseSensitive() const
230 		{
231 			return m_aNameMap.key_comp().isCaseSensitive();
232 		}
233 		// -----------------------------------------------------------------------------
234 	};
235 }
236 // -----------------------------------------------------------------------------
237 
238 IMPLEMENT_SERVICE_INFO(OCollection,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
239 
240 OCollection::OCollection(::cppu::OWeakObject& _rParent
241 						 , sal_Bool _bCase
242 						 , ::osl::Mutex& _rMutex
243 						 , const TStringVector &_rVector
244 						 , sal_Bool _bUseIndexOnly
245 						 , sal_Bool _bUseHardRef)
246                      :m_aContainerListeners(_rMutex)
247 					 ,m_aRefreshListeners(_rMutex)
248 					 ,m_rParent(_rParent)
249 					 ,m_rMutex(_rMutex)
250 					 ,m_bUseIndexOnly(_bUseIndexOnly)
251 {
252 	if ( _bUseHardRef )
253 	{
254 		m_pElements.reset(new OHardRefMap< ObjectType >(_bCase));
255 	}
256 	else
257 	{
258 		m_pElements.reset(new OHardRefMap< WeakReference< XPropertySet> >(_bCase));
259 	}
260 	m_pElements->reFill(_rVector);
261 }
262 // -------------------------------------------------------------------------
263 OCollection::~OCollection()
264 {
265 }
266 // -----------------------------------------------------------------------------
267 Any SAL_CALL OCollection::queryInterface( const Type & rType ) throw (RuntimeException)
268 {
269 	if ( m_bUseIndexOnly && rType == ::getCppuType(static_cast< Reference< XNameAccess > *> (NULL)) )
270 	{
271 		return Any();
272 	}
273 	return OCollectionBase::queryInterface( rType );
274 }
275 // -----------------------------------------------------------------------------
276 Sequence< Type > SAL_CALL OCollection::getTypes() throw (RuntimeException)
277 {
278 	if ( m_bUseIndexOnly )
279 	{
280 		Sequence< Type > aTypes(OCollectionBase::getTypes());
281 		Type* pBegin	= aTypes.getArray();
282 		Type* pEnd		= pBegin + aTypes.getLength();
283 
284 		::std::vector<Type> aOwnTypes;
285 		aOwnTypes.reserve(aTypes.getLength());
286 		Type aType = ::getCppuType(static_cast< Reference<XNameAccess> *>(NULL));
287 		for(;pBegin != pEnd; ++pBegin)
288 		{
289 			if ( *pBegin != aType )
290 				aOwnTypes.push_back(*pBegin);
291 		}
292 		Type* pTypes = aOwnTypes.empty() ? 0 : &aOwnTypes[0];
293 		return Sequence< Type >(pTypes,aOwnTypes.size());
294 	}
295 	return OCollectionBase::getTypes( );
296 }
297 // -------------------------------------------------------------------------
298 void OCollection::clear_NoDispose()
299 {
300 	::osl::MutexGuard aGuard(m_rMutex);
301 
302 	m_pElements->clear();
303 	m_pElements->swapAll();
304 }
305 
306 // -------------------------------------------------------------------------
307 void OCollection::disposing(void)
308 {
309 	m_aContainerListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
310 	m_aRefreshListeners.disposeAndClear(EventObject(static_cast<XTypeProvider*>(this)));
311 
312 	::osl::MutexGuard aGuard(m_rMutex);
313 
314 	disposeElements();
315 
316 	m_pElements->swap();
317 }
318 // -------------------------------------------------------------------------
319 Any SAL_CALL OCollection::getByIndex( sal_Int32 Index ) throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
320 {
321 	::osl::MutexGuard aGuard(m_rMutex);
322 	if (Index < 0 || Index >= m_pElements->size() )
323 		throw IndexOutOfBoundsException(::rtl::OUString::valueOf(Index),static_cast<XTypeProvider*>(this));
324 
325 	return makeAny(getObject(Index));
326 }
327 // -------------------------------------------------------------------------
328 Any SAL_CALL OCollection::getByName( const ::rtl::OUString& aName ) throw(NoSuchElementException, WrappedTargetException, RuntimeException)
329 {
330 	::osl::MutexGuard aGuard(m_rMutex);
331 
332 	if ( !m_pElements->exists(aName) )
333     {
334         ::connectivity::SharedResources aResources;
335         const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
336                 STR_NO_ELEMENT_NAME,
337                 "$name$", aName
338              ) );
339 		throw NoSuchElementException( sError, static_cast< XTypeProvider* >( this ) );
340     }
341 
342 	return makeAny(getObject(m_pElements->findColumn(aName)));
343 }
344 // -------------------------------------------------------------------------
345 Sequence< ::rtl::OUString > SAL_CALL OCollection::getElementNames(  ) throw(RuntimeException)
346 {
347 	::osl::MutexGuard aGuard(m_rMutex);
348 	return m_pElements->getElementNames();
349 }
350 // -------------------------------------------------------------------------
351 void SAL_CALL OCollection::refresh(  ) throw(RuntimeException)
352 {
353 	::osl::MutexGuard aGuard(m_rMutex);
354 
355 	disposeElements();
356 
357 	impl_refresh();
358 	EventObject aEvt(static_cast<XTypeProvider*>(this));
359     m_aRefreshListeners.notifyEach( &XRefreshListener::refreshed, aEvt );
360 }
361 // -----------------------------------------------------------------------------
362 void OCollection::reFill(const TStringVector &_rVector)
363 {
364 	m_pElements->reFill(_rVector);
365 }
366 // -------------------------------------------------------------------------
367 // XDataDescriptorFactory
368 Reference< XPropertySet > SAL_CALL OCollection::createDataDescriptor(  ) throw(RuntimeException)
369 {
370 	::osl::MutexGuard aGuard(m_rMutex);
371 
372 	return createDescriptor();
373 }
374 // -----------------------------------------------------------------------------
375 ::rtl::OUString OCollection::getNameForObject(const ObjectType& _xObject)
376 {
377     OSL_ENSURE(_xObject.is(),"OCollection::getNameForObject: Object is NULL!");
378     ::rtl::OUString sName;
379     _xObject->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sName;
380     return sName;
381 }
382 // -------------------------------------------------------------------------
383 // XAppend
384 void SAL_CALL OCollection::appendByDescriptor( const Reference< XPropertySet >& descriptor ) throw(SQLException, ElementExistException, RuntimeException)
385 {
386 	::osl::ClearableMutexGuard aGuard(m_rMutex);
387 
388     ::rtl::OUString sName = getNameForObject( descriptor );
389 
390 	if ( m_pElements->exists(sName) )
391 		throw ElementExistException(sName,static_cast<XTypeProvider*>(this));
392 
393     ObjectType xNewlyCreated = appendObject( sName, descriptor );
394 	if ( !xNewlyCreated.is() )
395         throw RuntimeException();
396 
397     ODescriptor* pDescriptor = ODescriptor::getImplementation( xNewlyCreated );
398 	if ( pDescriptor )
399 		pDescriptor->setNew( sal_False );
400 
401     sName = getNameForObject( xNewlyCreated );
402 	if ( !m_pElements->exists( sName ) ) // this may happen when the drived class included it itself
403 		m_pElements->insert( sName, xNewlyCreated );
404 
405     // notify our container listeners
406 	ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(sName), makeAny(xNewlyCreated), Any());
407     aGuard.clear();
408     m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
409 }
410 // -------------------------------------------------------------------------
411 // XDrop
412 void SAL_CALL OCollection::dropByName( const ::rtl::OUString& elementName ) throw(SQLException, NoSuchElementException, RuntimeException)
413 {
414 	::osl::MutexGuard aGuard(m_rMutex);
415 
416 	if ( !m_pElements->exists(elementName) )
417 		throw NoSuchElementException(elementName,static_cast<XTypeProvider*>(this));
418 
419 	dropImpl(m_pElements->findColumn(elementName));
420 }
421 // -------------------------------------------------------------------------
422 void SAL_CALL OCollection::dropByIndex( sal_Int32 index ) throw(SQLException, IndexOutOfBoundsException, RuntimeException)
423 {
424 	::osl::MutexGuard aGuard(m_rMutex);
425 	if(index <0 || index >= getCount())
426 		throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index),static_cast<XTypeProvider*>(this));
427 
428 	dropImpl(index);
429 }
430 // -----------------------------------------------------------------------------
431 void OCollection::dropImpl(sal_Int32 _nIndex,sal_Bool _bReallyDrop)
432 {
433 	::rtl::OUString elementName = m_pElements->getName(_nIndex);
434 
435 	if ( _bReallyDrop )
436 		dropObject(_nIndex,elementName);
437 
438 	m_pElements->disposeAndErase(_nIndex);
439 
440 	// notify our container listeners
441 	notifyElementRemoved(elementName);
442 }
443 // -----------------------------------------------------------------------------
444 void OCollection::notifyElementRemoved(const ::rtl::OUString& _sName)
445 {
446 	ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sName), Any(), Any());
447 	// note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
448 	OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
449 	while (aListenerLoop.hasMoreElements())
450 		static_cast<XContainerListener*>(aListenerLoop.next())->elementRemoved(aEvent);
451 }
452 // -------------------------------------------------------------------------
453 sal_Int32 SAL_CALL OCollection::findColumn( const ::rtl::OUString& columnName ) throw(SQLException, RuntimeException)
454 {
455 	if ( !m_pElements->exists(columnName) )
456     {
457         ::connectivity::SharedResources aResources;
458         const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(
459                             STR_UNKNOWN_COLUMN_NAME,
460                             "$columnname$", columnName
461                          ) );
462 		::dbtools::throwGenericSQLException(sError,static_cast< XIndexAccess*>(this));
463     }
464 
465 	return m_pElements->findColumn(columnName) + 1; // because columns start at one
466 }
467 // -------------------------------------------------------------------------
468 Reference< XEnumeration > SAL_CALL OCollection::createEnumeration(  ) throw(RuntimeException)
469 {
470 	::osl::MutexGuard aGuard(m_rMutex);
471     return new OEnumerationByIndex( static_cast< XIndexAccess*>(this));
472 }
473 // -----------------------------------------------------------------------------
474 void SAL_CALL OCollection::addContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
475 {
476 	m_aContainerListeners.addInterface(_rxListener);
477 }
478 
479 //------------------------------------------------------------------------------
480 void SAL_CALL OCollection::removeContainerListener( const Reference< XContainerListener >& _rxListener ) throw(RuntimeException)
481 {
482 	m_aContainerListeners.removeInterface(_rxListener);
483 }
484 // -----------------------------------------------------------------------------
485 void SAL_CALL OCollection::acquire() throw()
486 {
487 	m_rParent.acquire();
488 }
489 // -----------------------------------------------------------------------------
490 void SAL_CALL OCollection::release() throw()
491 {
492 	m_rParent.release();
493 }
494 // -----------------------------------------------------------------------------
495 Type SAL_CALL OCollection::getElementType(  ) throw(RuntimeException)
496 {
497 	return::getCppuType(static_cast< Reference< XPropertySet>*>(NULL));
498 }
499 // -----------------------------------------------------------------------------
500 sal_Bool SAL_CALL OCollection::hasElements(  ) throw(RuntimeException)
501 {
502 	::osl::MutexGuard aGuard(m_rMutex);
503 	return !m_pElements->empty();
504 }
505 // -----------------------------------------------------------------------------
506 sal_Int32 SAL_CALL OCollection::getCount(  ) throw(RuntimeException)
507 {
508 	::osl::MutexGuard aGuard(m_rMutex);
509 	return m_pElements->size();
510 }
511 // -----------------------------------------------------------------------------
512 sal_Bool SAL_CALL OCollection::hasByName( const ::rtl::OUString& aName ) throw(RuntimeException)
513 {
514 	::osl::MutexGuard aGuard(m_rMutex);
515 	return m_pElements->exists(aName);
516 }
517 // -----------------------------------------------------------------------------
518 void SAL_CALL OCollection::addRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException)
519 {
520 	m_aRefreshListeners.addInterface(l);
521 }
522 // -----------------------------------------------------------------------------
523 void SAL_CALL OCollection::removeRefreshListener( const Reference< XRefreshListener >& l ) throw(RuntimeException)
524 {
525 	m_aRefreshListeners.removeInterface(l);
526 }
527 // -----------------------------------------------------------------------------
528 void OCollection::insertElement(const ::rtl::OUString& _sElementName,const ObjectType& _xElement)
529 {
530 	OSL_ENSURE(!m_pElements->exists(_sElementName),"Element already exists");
531 	if ( !m_pElements->exists(_sElementName) )
532 		m_pElements->insert(_sElementName,_xElement);
533 }
534 // -----------------------------------------------------------------------------
535 void OCollection::renameObject(const ::rtl::OUString _sOldName,const ::rtl::OUString _sNewName)
536 {
537 	OSL_ENSURE(m_pElements->exists(_sOldName),"Element doesn't exist");
538 	OSL_ENSURE(!m_pElements->exists(_sNewName),"Element already exists");
539 	OSL_ENSURE(_sNewName.getLength(),"New name must not be empty!");
540 	OSL_ENSURE(_sOldName.getLength(),"New name must not be empty!");
541 
542 	if ( m_pElements->rename(_sOldName,_sNewName) )
543 	{
544 		ContainerEvent aEvent(static_cast<XContainer*>(this), makeAny(_sNewName), makeAny(m_pElements->getObject(_sNewName)),makeAny(_sOldName));
545 		// note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
546 		OInterfaceIteratorHelper aListenerLoop(m_aContainerListeners);
547 		while (aListenerLoop.hasMoreElements())
548 			static_cast<XContainerListener*>(aListenerLoop.next())->elementReplaced(aEvent);
549 	}
550 }
551 // -----------------------------------------------------------------------------
552 ObjectType OCollection::getObject(sal_Int32 _nIndex)
553 {
554 	ObjectType xName = m_pElements->getObject(_nIndex);
555 	if ( !xName.is() )
556 	{
557 		try
558 		{
559 			xName = createObject(m_pElements->getName(_nIndex));
560 		}
561 		catch(const SQLException& e)
562 		{
563 			try
564 			{
565 				dropImpl(_nIndex,sal_False);
566 			}
567 			catch(const Exception& )
568 			{
569 			}
570 			throw WrappedTargetException(e.Message,static_cast<XTypeProvider*>(this),makeAny(e));
571 		}
572 		m_pElements->setObject(_nIndex,xName);
573 	}
574 	return xName;
575 }
576 // -----------------------------------------------------------------------------
577 void OCollection::disposeElements()
578 {
579 	m_pElements->disposeElements();
580 }
581 // -----------------------------------------------------------------------------
582 Reference< XPropertySet > OCollection::createDescriptor()
583 {
584 	OSL_ASSERT(!"Need to be overloaded when used!");
585 	throw SQLException();
586 }
587 // -----------------------------------------------------------------------------
588 ObjectType OCollection::cloneDescriptor( const ObjectType& _descriptor )
589 {
590 	ObjectType xNewDescriptor( createDescriptor() );
591 	::comphelper::copyProperties( _descriptor, xNewDescriptor );
592 	return xNewDescriptor;
593 }
594 // -----------------------------------------------------------------------------
595 ObjectType OCollection::appendObject( const ::rtl::OUString& /*_rForName*/, const Reference< XPropertySet >& descriptor )
596 {
597     return cloneDescriptor( descriptor );
598 }
599 // -----------------------------------------------------------------------------
600 void OCollection::dropObject(sal_Int32 /*_nPos*/,const ::rtl::OUString /*_sElementName*/)
601 {
602 }
603 // -----------------------------------------------------------------------------
604