1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
32 #include "connectivity/sdbcx/VCollection.hxx"
33 #include "connectivity/sdbcx/VDescriptor.hxx"
34 #include "connectivity/dbexception.hxx"
35 #include <comphelper/enumhelper.hxx>
36 #include <comphelper/container.hxx>
37 #include <comphelper/types.hxx>
38 #include <comphelper/property.hxx>
39 #include "TConnection.hxx"
40 #include <rtl/ustrbuf.hxx>
41 #include "resource/common_res.hrc"
42 #include "resource/sharedresources.hxx"
44 using namespace connectivity::sdbcx
;
45 using namespace connectivity
;
46 using namespace comphelper
;
47 using namespace ::cppu
;
48 using namespace ::com::sun::star::beans
;
49 using namespace ::com::sun::star::uno
;
50 using namespace ::com::sun::star::lang
;
51 using namespace ::com::sun::star::sdbc
;
52 using namespace ::com::sun::star::container
;
53 using namespace ::com::sun::star::util
;
57 template < typename T
> class OHardRefMap
: public connectivity::sdbcx::IObjectCollection
59 typedef ::std::multimap
< ::rtl::OUString
, T
, ::comphelper::UStringMixLess
> ObjectMap
;
60 typedef typename
ObjectMap::iterator ObjectIter
;
61 typedef typename
ObjectMap::value_type ObjectEntry
;
64 // this combination of map and vector is used to have a fast name and index access
65 ::std::vector
< ObjectIter
> m_aElements
; // hold the iterators which point to map
66 ObjectMap m_aNameMap
; // hold the elements and a name
68 OHardRefMap(sal_Bool _bCase
)
69 : m_aNameMap(_bCase
? true : false)
72 virtual ~OHardRefMap()
76 virtual void reserve(size_t nLength
)
78 m_aElements
.reserve(nLength
);
80 // -----------------------------------------------------------------------------
81 virtual bool exists(const ::rtl::OUString
& _sName
)
83 return m_aNameMap
.find(_sName
) != m_aNameMap
.end();
85 // -----------------------------------------------------------------------------
88 return m_aNameMap
.empty();
90 // -----------------------------------------------------------------------------
91 virtual void swapAll()
93 ::std::vector
< ObjectIter
>(m_aElements
).swap(m_aElements
);
94 ObjectMap(m_aNameMap
).swap(m_aNameMap
);
96 // -----------------------------------------------------------------------------
99 ::std::vector
< ObjectIter
>().swap(m_aElements
);
101 OSL_ENSURE( m_aNameMap
.empty(), "swap: what did disposeElements do?" );
102 ObjectMap( m_aNameMap
).swap( m_aNameMap
);
103 // Note that it's /important/ to construct the new ObjectMap from m_aNameMap before
104 // swapping. This way, it's ensured that the compare object held by these maps is preserved
105 // during the swap. If we would not do this, the UStringMixLess instance which is used would be
106 // default constructed (instead of being constructed from the same instance in m_aNameMap), and
107 // it's case-sensitive flag would have an unpredictable value.
109 // -----------------------------------------------------------------------------
115 // -----------------------------------------------------------------------------
116 virtual void insert(const ::rtl::OUString
& _sName
,const ObjectType
& _xObject
)
118 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sName
,_xObject
)));
120 // -----------------------------------------------------------------------------
121 virtual void reFill(const TStringVector
&_rVector
)
123 OSL_ENSURE(!m_aNameMap
.size(),"OCollection::reFill: collection isn't empty");
124 m_aElements
.reserve(_rVector
.size());
126 for(TStringVector::const_iterator i
=_rVector
.begin(); i
!= _rVector
.end();++i
)
127 m_aElements
.push_back(m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(*i
,ObjectType())));
129 // -----------------------------------------------------------------------------
130 virtual bool rename(const ::rtl::OUString _sOldName
,const ::rtl::OUString _sNewName
)
133 ObjectIter aIter
= m_aNameMap
.find(_sOldName
);
134 if ( aIter
!= m_aNameMap
.end() )
136 typename ::std::vector
< ObjectIter
>::iterator aFind
= ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
);
137 if(m_aElements
.end() != aFind
)
139 (*aFind
) = m_aNameMap
.insert(m_aNameMap
.begin(), ObjectEntry(_sNewName
,(*aFind
)->second
));
140 m_aNameMap
.erase(aIter
);
147 // -----------------------------------------------------------------------------
148 virtual sal_Int32
size()
150 return static_cast<sal_Int32
>(m_aNameMap
.size());
152 // -----------------------------------------------------------------------------
153 virtual Sequence
< ::rtl::OUString
> getElementNames()
155 Sequence
< ::rtl::OUString
> aNameList(m_aElements
.size());
157 ::rtl::OUString
* pStringArray
= aNameList
.getArray();
158 typename ::std::vector
< ObjectIter
>::const_iterator aEnd
= m_aElements
.end();
159 for(typename ::std::vector
< ObjectIter
>::const_iterator aIter
= m_aElements
.begin(); aIter
!= aEnd
;++aIter
,++pStringArray
)
160 *pStringArray
= (*aIter
)->first
;
164 // -----------------------------------------------------------------------------
165 virtual ::rtl::OUString
getName(sal_Int32 _nIndex
)
167 return m_aElements
[_nIndex
]->first
;
169 // -----------------------------------------------------------------------------
170 virtual void disposeAndErase(sal_Int32 _nIndex
)
172 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
173 Reference
<XComponent
> xComp(m_aElements
[_nIndex
]->second
.get(),UNO_QUERY
);
174 ::comphelper::disposeComponent(xComp
);
175 m_aElements
[_nIndex
]->second
= T();
177 ::rtl::OUString sName
= m_aElements
[_nIndex
]->first
;
178 m_aElements
.erase(m_aElements
.begin()+_nIndex
);
179 m_aNameMap
.erase(sName
);
181 // -----------------------------------------------------------------------------
182 virtual void disposeElements()
184 for( ObjectIter aIter
= m_aNameMap
.begin(); aIter
!= m_aNameMap
.end(); ++aIter
)
186 Reference
<XComponent
> xComp(aIter
->second
.get(),UNO_QUERY
);
189 ::comphelper::disposeComponent(xComp
);
190 (*aIter
).second
= T();
196 // -----------------------------------------------------------------------------
197 virtual sal_Int32
findColumn( const ::rtl::OUString
& columnName
)
199 ObjectIter aIter
= m_aNameMap
.find(columnName
);
200 OSL_ENSURE(aIter
!= m_aNameMap
.end(),"findColumn:: Illegal name!");
201 return m_aElements
.size() - (m_aElements
.end() - ::std::find(m_aElements
.begin(),m_aElements
.end(),aIter
));
203 // -----------------------------------------------------------------------------
204 virtual ::rtl::OUString
findColumnAtIndex( sal_Int32 _nIndex
)
206 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
207 return m_aElements
[_nIndex
]->first
;
209 // -----------------------------------------------------------------------------
210 virtual ObjectType
getObject(sal_Int32 _nIndex
)
212 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
213 return m_aElements
[_nIndex
]->second
;
215 // -----------------------------------------------------------------------------
216 virtual ObjectType
getObject(const ::rtl::OUString
& columnName
)
218 return m_aNameMap
.find(columnName
)->second
;
220 // -----------------------------------------------------------------------------
221 virtual void setObject(sal_Int32 _nIndex
,const ObjectType
& _xObject
)
223 OSL_ENSURE(_nIndex
>= 0 && _nIndex
< static_cast<sal_Int32
>(m_aElements
.size()),"Illegal argument!");
224 m_aElements
[_nIndex
]->second
= _xObject
;
226 // -----------------------------------------------------------------------------
227 sal_Bool
isCaseSensitive() const
229 return m_aNameMap
.key_comp().isCaseSensitive();
231 // -----------------------------------------------------------------------------
235 IObjectCollection::~IObjectCollection() {}
237 IMPLEMENT_SERVICE_INFO(OCollection
,"com.sun.star.sdbcx.VContainer" , "com.sun.star.sdbcx.Container")
239 OCollection::OCollection(::cppu::OWeakObject
& _rParent
241 , ::osl::Mutex
& _rMutex
242 , const TStringVector
&_rVector
243 , sal_Bool _bUseIndexOnly
244 , sal_Bool _bUseHardRef
)
245 :m_aContainerListeners(_rMutex
)
246 ,m_aRefreshListeners(_rMutex
)
249 ,m_bUseIndexOnly(_bUseIndexOnly
)
253 m_pElements
.reset(new OHardRefMap
< ObjectType
>(_bCase
));
257 m_pElements
.reset(new OHardRefMap
< WeakReference
< XPropertySet
> >(_bCase
));
259 m_pElements
->reFill(_rVector
);
261 // -------------------------------------------------------------------------
262 OCollection::~OCollection()
265 // -----------------------------------------------------------------------------
266 Any SAL_CALL
OCollection::queryInterface( const Type
& rType
) throw (RuntimeException
)
268 if ( m_bUseIndexOnly
&& rType
== ::getCppuType(static_cast< Reference
< XNameAccess
> *> (NULL
)) )
272 return OCollectionBase::queryInterface( rType
);
274 // -----------------------------------------------------------------------------
275 Sequence
< Type
> SAL_CALL
OCollection::getTypes() throw (RuntimeException
)
277 if ( m_bUseIndexOnly
)
279 Sequence
< Type
> aTypes(OCollectionBase::getTypes());
280 Type
* pBegin
= aTypes
.getArray();
281 Type
* pEnd
= pBegin
+ aTypes
.getLength();
283 ::std::vector
<Type
> aOwnTypes
;
284 aOwnTypes
.reserve(aTypes
.getLength());
285 Type aType
= ::getCppuType(static_cast< Reference
<XNameAccess
> *>(NULL
));
286 for(;pBegin
!= pEnd
; ++pBegin
)
288 if ( *pBegin
!= aType
)
289 aOwnTypes
.push_back(*pBegin
);
291 Type
* pTypes
= aOwnTypes
.empty() ? 0 : &aOwnTypes
[0];
292 return Sequence
< Type
>(pTypes
,aOwnTypes
.size());
294 return OCollectionBase::getTypes( );
296 // -------------------------------------------------------------------------
297 void OCollection::clear_NoDispose()
299 ::osl::MutexGuard
aGuard(m_rMutex
);
301 m_pElements
->clear();
302 m_pElements
->swapAll();
305 // -------------------------------------------------------------------------
306 void OCollection::disposing(void)
308 m_aContainerListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
309 m_aRefreshListeners
.disposeAndClear(EventObject(static_cast<XTypeProvider
*>(this)));
311 ::osl::MutexGuard
aGuard(m_rMutex
);
317 // -------------------------------------------------------------------------
318 Any SAL_CALL
OCollection::getByIndex( sal_Int32 Index
) throw(IndexOutOfBoundsException
, WrappedTargetException
, RuntimeException
)
320 ::osl::MutexGuard
aGuard(m_rMutex
);
321 if (Index
< 0 || Index
>= m_pElements
->size() )
322 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(Index
),static_cast<XTypeProvider
*>(this));
324 return makeAny(getObject(Index
));
326 // -------------------------------------------------------------------------
327 Any SAL_CALL
OCollection::getByName( const ::rtl::OUString
& aName
) throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
)
329 ::osl::MutexGuard
aGuard(m_rMutex
);
331 if ( !m_pElements
->exists(aName
) )
333 ::connectivity::SharedResources aResources
;
334 const ::rtl::OUString
sError( aResources
.getResourceStringWithSubstitution(
338 throw NoSuchElementException( sError
, static_cast< XTypeProvider
* >( this ) );
341 return makeAny(getObject(m_pElements
->findColumn(aName
)));
343 // -------------------------------------------------------------------------
344 Sequence
< ::rtl::OUString
> SAL_CALL
OCollection::getElementNames( ) throw(RuntimeException
)
346 ::osl::MutexGuard
aGuard(m_rMutex
);
347 return m_pElements
->getElementNames();
349 // -------------------------------------------------------------------------
350 void SAL_CALL
OCollection::refresh( ) throw(RuntimeException
)
352 ::osl::MutexGuard
aGuard(m_rMutex
);
357 EventObject
aEvt(static_cast<XTypeProvider
*>(this));
358 m_aRefreshListeners
.notifyEach( &XRefreshListener::refreshed
, aEvt
);
360 // -----------------------------------------------------------------------------
361 void OCollection::reFill(const TStringVector
&_rVector
)
363 m_pElements
->reFill(_rVector
);
365 // -------------------------------------------------------------------------
366 // XDataDescriptorFactory
367 Reference
< XPropertySet
> SAL_CALL
OCollection::createDataDescriptor( ) throw(RuntimeException
)
369 ::osl::MutexGuard
aGuard(m_rMutex
);
371 return createDescriptor();
373 // -----------------------------------------------------------------------------
374 ::rtl::OUString
OCollection::getNameForObject(const ObjectType
& _xObject
)
376 OSL_ENSURE(_xObject
.is(),"OCollection::getNameForObject: Object is NULL!");
377 ::rtl::OUString sName
;
378 _xObject
->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
)) >>= sName
;
381 // -------------------------------------------------------------------------
383 void SAL_CALL
OCollection::appendByDescriptor( const Reference
< XPropertySet
>& descriptor
) throw(SQLException
, ElementExistException
, RuntimeException
)
385 ::osl::ClearableMutexGuard
aGuard(m_rMutex
);
387 ::rtl::OUString sName
= getNameForObject( descriptor
);
389 if ( m_pElements
->exists(sName
) )
390 throw ElementExistException(sName
,static_cast<XTypeProvider
*>(this));
392 ObjectType xNewlyCreated
= appendObject( sName
, descriptor
);
393 if ( !xNewlyCreated
.is() )
394 throw RuntimeException();
396 ODescriptor
* pDescriptor
= ODescriptor::getImplementation( xNewlyCreated
);
398 pDescriptor
->setNew( sal_False
);
400 sName
= getNameForObject( xNewlyCreated
);
401 if ( !m_pElements
->exists( sName
) ) // this may happen when the drived class included it itself
402 m_pElements
->insert( sName
, xNewlyCreated
);
404 // notify our container listeners
405 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(sName
), makeAny(xNewlyCreated
), Any());
407 m_aContainerListeners
.notifyEach( &XContainerListener::elementInserted
, aEvent
);
409 // -------------------------------------------------------------------------
411 void SAL_CALL
OCollection::dropByName( const ::rtl::OUString
& elementName
) throw(SQLException
, NoSuchElementException
, RuntimeException
)
413 ::osl::MutexGuard
aGuard(m_rMutex
);
415 if ( !m_pElements
->exists(elementName
) )
416 throw NoSuchElementException(elementName
,static_cast<XTypeProvider
*>(this));
418 dropImpl(m_pElements
->findColumn(elementName
));
420 // -------------------------------------------------------------------------
421 void SAL_CALL
OCollection::dropByIndex( sal_Int32 index
) throw(SQLException
, IndexOutOfBoundsException
, RuntimeException
)
423 ::osl::MutexGuard
aGuard(m_rMutex
);
424 if(index
<0 || index
>= getCount())
425 throw IndexOutOfBoundsException(::rtl::OUString::valueOf(index
),static_cast<XTypeProvider
*>(this));
429 // -----------------------------------------------------------------------------
430 void OCollection::dropImpl(sal_Int32 _nIndex
,sal_Bool _bReallyDrop
)
432 ::rtl::OUString elementName
= m_pElements
->getName(_nIndex
);
435 dropObject(_nIndex
,elementName
);
437 m_pElements
->disposeAndErase(_nIndex
);
439 // notify our container listeners
440 notifyElementRemoved(elementName
);
442 // -----------------------------------------------------------------------------
443 void OCollection::notifyElementRemoved(const ::rtl::OUString
& _sName
)
445 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sName
), Any(), Any());
446 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
447 OInterfaceIteratorHelper
aListenerLoop(m_aContainerListeners
);
448 while (aListenerLoop
.hasMoreElements())
449 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementRemoved(aEvent
);
451 // -------------------------------------------------------------------------
452 sal_Int32 SAL_CALL
OCollection::findColumn( const ::rtl::OUString
& columnName
) throw(SQLException
, RuntimeException
)
454 if ( !m_pElements
->exists(columnName
) )
456 ::connectivity::SharedResources aResources
;
457 const ::rtl::OUString
sError( aResources
.getResourceStringWithSubstitution(
458 STR_UNKNOWN_COLUMN_NAME
,
459 "$columnname$", columnName
461 ::dbtools::throwGenericSQLException(sError
,static_cast< XIndexAccess
*>(this));
464 return m_pElements
->findColumn(columnName
) + 1; // because columns start at one
466 // -------------------------------------------------------------------------
467 Reference
< XEnumeration
> SAL_CALL
OCollection::createEnumeration( ) throw(RuntimeException
)
469 ::osl::MutexGuard
aGuard(m_rMutex
);
470 return new OEnumerationByIndex( static_cast< XIndexAccess
*>(this));
472 // -----------------------------------------------------------------------------
473 void SAL_CALL
OCollection::addContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
)
475 m_aContainerListeners
.addInterface(_rxListener
);
478 //------------------------------------------------------------------------------
479 void SAL_CALL
OCollection::removeContainerListener( const Reference
< XContainerListener
>& _rxListener
) throw(RuntimeException
)
481 m_aContainerListeners
.removeInterface(_rxListener
);
483 // -----------------------------------------------------------------------------
484 void SAL_CALL
OCollection::acquire() throw()
488 // -----------------------------------------------------------------------------
489 void SAL_CALL
OCollection::release() throw()
493 // -----------------------------------------------------------------------------
494 Type SAL_CALL
OCollection::getElementType( ) throw(RuntimeException
)
496 return::getCppuType(static_cast< Reference
< XPropertySet
>*>(NULL
));
498 // -----------------------------------------------------------------------------
499 sal_Bool SAL_CALL
OCollection::hasElements( ) throw(RuntimeException
)
501 ::osl::MutexGuard
aGuard(m_rMutex
);
502 return !m_pElements
->empty();
504 // -----------------------------------------------------------------------------
505 sal_Int32 SAL_CALL
OCollection::getCount( ) throw(RuntimeException
)
507 ::osl::MutexGuard
aGuard(m_rMutex
);
508 return m_pElements
->size();
510 // -----------------------------------------------------------------------------
511 sal_Bool SAL_CALL
OCollection::hasByName( const ::rtl::OUString
& aName
) throw(RuntimeException
)
513 ::osl::MutexGuard
aGuard(m_rMutex
);
514 return m_pElements
->exists(aName
);
516 // -----------------------------------------------------------------------------
517 void SAL_CALL
OCollection::addRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
)
519 m_aRefreshListeners
.addInterface(l
);
521 // -----------------------------------------------------------------------------
522 void SAL_CALL
OCollection::removeRefreshListener( const Reference
< XRefreshListener
>& l
) throw(RuntimeException
)
524 m_aRefreshListeners
.removeInterface(l
);
526 // -----------------------------------------------------------------------------
527 void OCollection::insertElement(const ::rtl::OUString
& _sElementName
,const ObjectType
& _xElement
)
529 OSL_ENSURE(!m_pElements
->exists(_sElementName
),"Element already exists");
530 if ( !m_pElements
->exists(_sElementName
) )
531 m_pElements
->insert(_sElementName
,_xElement
);
533 // -----------------------------------------------------------------------------
534 void OCollection::renameObject(const ::rtl::OUString _sOldName
,const ::rtl::OUString _sNewName
)
536 OSL_ENSURE(m_pElements
->exists(_sOldName
),"Element doesn't exist");
537 OSL_ENSURE(!m_pElements
->exists(_sNewName
),"Element already exists");
538 OSL_ENSURE(!_sNewName
.isEmpty(),"New name must not be empty!");
539 OSL_ENSURE(!_sOldName
.isEmpty(),"Old name must not be empty!");
541 if ( m_pElements
->rename(_sOldName
,_sNewName
) )
543 ContainerEvent
aEvent(static_cast<XContainer
*>(this), makeAny(_sNewName
), makeAny(m_pElements
->getObject(_sNewName
)),makeAny(_sOldName
));
544 // note that xExistent may be empty, in case somebody removed the data source while it is not alive at this moment
545 OInterfaceIteratorHelper
aListenerLoop(m_aContainerListeners
);
546 while (aListenerLoop
.hasMoreElements())
547 static_cast<XContainerListener
*>(aListenerLoop
.next())->elementReplaced(aEvent
);
550 // -----------------------------------------------------------------------------
551 ObjectType
OCollection::getObject(sal_Int32 _nIndex
)
553 ObjectType xName
= m_pElements
->getObject(_nIndex
);
558 xName
= createObject(m_pElements
->getName(_nIndex
));
560 catch(const SQLException
& e
)
564 dropImpl(_nIndex
,sal_False
);
566 catch(const Exception
& )
569 throw WrappedTargetException(e
.Message
,static_cast<XTypeProvider
*>(this),makeAny(e
));
571 m_pElements
->setObject(_nIndex
,xName
);
575 // -----------------------------------------------------------------------------
576 void OCollection::disposeElements()
578 m_pElements
->disposeElements();
580 // -----------------------------------------------------------------------------
581 Reference
< XPropertySet
> OCollection::createDescriptor()
583 OSL_ASSERT(!"Need to be overloaded when used!");
584 throw SQLException();
586 // -----------------------------------------------------------------------------
587 ObjectType
OCollection::cloneDescriptor( const ObjectType
& _descriptor
)
589 ObjectType
xNewDescriptor( createDescriptor() );
590 ::comphelper::copyProperties( _descriptor
, xNewDescriptor
);
591 return xNewDescriptor
;
593 // -----------------------------------------------------------------------------
594 ObjectType
OCollection::appendObject( const ::rtl::OUString
& /*_rForName*/, const Reference
< XPropertySet
>& descriptor
)
596 return cloneDescriptor( descriptor
);
598 // -----------------------------------------------------------------------------
599 void OCollection::dropObject(sal_Int32
/*_nPos*/,const ::rtl::OUString
/*_sElementName*/)
602 // -----------------------------------------------------------------------------
604 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */