Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <vector>
21 : #include <sortdynres.hxx>
22 : #include <cppuhelper/interfacecontainer.hxx>
23 : #include <cppuhelper/supportsservice.hxx>
24 : #include <com/sun/star/ucb/ContentResultSetCapability.hpp>
25 : #include <com/sun/star/ucb/ListActionType.hpp>
26 : #include <com/sun/star/ucb/WelcomeDynamicResultSetStruct.hpp>
27 : #include <com/sun/star/ucb/CachedDynamicResultSetStubFactory.hpp>
28 : #include <com/sun/star/ucb/XSourceInitialization.hpp>
29 : #include <ucbhelper/getcomponentcontext.hxx>
30 :
31 : using namespace com::sun::star::beans;
32 : using namespace com::sun::star::lang;
33 : using namespace com::sun::star::sdbc;
34 : using namespace com::sun::star::ucb;
35 : using namespace com::sun::star::uno;
36 : using namespace cppu;
37 :
38 :
39 : // The mutex to synchronize access to containers.
40 0 : static osl::Mutex& getContainerMutex()
41 : {
42 : static osl::Mutex* pMutex = NULL;
43 0 : if( !pMutex )
44 : {
45 0 : osl::Guard< osl::Mutex > aGuard( osl::Mutex::getGlobalMutex() );
46 0 : if( !pMutex )
47 : {
48 0 : static osl::Mutex aMutex;
49 0 : pMutex = &aMutex;
50 0 : }
51 : }
52 :
53 0 : return *pMutex;
54 : }
55 :
56 :
57 : // SortedDynamicResultSet
58 :
59 70 : SortedDynamicResultSet::SortedDynamicResultSet(
60 : const Reference < XDynamicResultSet > &xOriginal,
61 : const Sequence < NumberedSortingInfo > &aOptions,
62 : const Reference < XAnyCompareFactory > &xCompFac,
63 70 : const Reference < XComponentContext > &rxContext )
64 : {
65 70 : mpDisposeEventListeners = NULL;
66 70 : mpOwnListener = new SortedDynamicResultSetListener( this );
67 :
68 70 : mxOwnListener = Reference< XDynamicResultSetListener >( mpOwnListener );
69 :
70 70 : mxOriginal = xOriginal;
71 70 : maOptions = aOptions;
72 70 : mxCompFac = xCompFac;
73 70 : m_xContext = rxContext;
74 :
75 70 : mpOne = NULL;
76 70 : mpTwo = NULL;
77 :
78 70 : mbGotWelcome = false;
79 70 : mbUseOne = true;
80 70 : mbStatic = false;
81 70 : }
82 :
83 :
84 210 : SortedDynamicResultSet::~SortedDynamicResultSet()
85 : {
86 70 : mpOwnListener->impl_OwnerDies();
87 70 : mxOwnListener.clear();
88 :
89 70 : delete mpDisposeEventListeners;
90 :
91 70 : mxOne.clear();
92 70 : mxTwo.clear();
93 70 : mxOriginal.clear();
94 :
95 70 : mpOne = NULL;
96 70 : mpTwo = NULL;
97 140 : }
98 :
99 : // XServiceInfo methods.
100 :
101 0 : OUString SAL_CALL SortedDynamicResultSet::getImplementationName()
102 : throw( css::uno::RuntimeException, std::exception )
103 : {
104 0 : return getImplementationName_Static();
105 : }
106 :
107 0 : OUString SortedDynamicResultSet::getImplementationName_Static()
108 : {
109 0 : return OUString( "com.sun.star.comp.ucb.SortedDynamicResultSet" );
110 : }
111 :
112 0 : sal_Bool SAL_CALL SortedDynamicResultSet::supportsService( const OUString& ServiceName )
113 : throw( css::uno::RuntimeException, std::exception )
114 : {
115 0 : return cppu::supportsService( this, ServiceName );
116 : }
117 :
118 0 : css::uno::Sequence< OUString > SAL_CALL SortedDynamicResultSet::getSupportedServiceNames()
119 : throw( css::uno::RuntimeException, std::exception )
120 : {
121 0 : return getSupportedServiceNames_Static();
122 : }
123 :
124 0 : css::uno::Sequence< OUString > SortedDynamicResultSet::getSupportedServiceNames_Static()
125 : {
126 0 : css::uno::Sequence< OUString > aSNS( 1 );
127 0 : aSNS.getArray()[ 0 ] = DYNAMIC_RESULTSET_SERVICE_NAME;
128 0 : return aSNS;
129 : }
130 :
131 : // XComponent methods.
132 :
133 0 : void SAL_CALL SortedDynamicResultSet::dispose()
134 : throw( RuntimeException, std::exception )
135 : {
136 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
137 :
138 0 : if ( mpDisposeEventListeners && mpDisposeEventListeners->getLength() )
139 : {
140 0 : EventObject aEvt;
141 0 : aEvt.Source = static_cast< XComponent * >( this );
142 0 : mpDisposeEventListeners->disposeAndClear( aEvt );
143 : }
144 :
145 0 : mxOne.clear();
146 0 : mxTwo.clear();
147 0 : mxOriginal.clear();
148 :
149 0 : mpOne = NULL;
150 0 : mpTwo = NULL;
151 0 : mbUseOne = true;
152 0 : }
153 :
154 0 : void SAL_CALL SortedDynamicResultSet::addEventListener(
155 : const Reference< XEventListener >& Listener )
156 : throw( RuntimeException, std::exception )
157 : {
158 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
159 :
160 0 : if ( !mpDisposeEventListeners )
161 : mpDisposeEventListeners =
162 0 : new OInterfaceContainerHelper( getContainerMutex() );
163 :
164 0 : mpDisposeEventListeners->addInterface( Listener );
165 0 : }
166 :
167 0 : void SAL_CALL SortedDynamicResultSet::removeEventListener(
168 : const Reference< XEventListener >& Listener )
169 : throw( RuntimeException, std::exception )
170 : {
171 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
172 :
173 0 : if ( mpDisposeEventListeners )
174 0 : mpDisposeEventListeners->removeInterface( Listener );
175 0 : }
176 :
177 :
178 : // XDynamicResultSet methods.
179 :
180 : Reference< XResultSet > SAL_CALL
181 70 : SortedDynamicResultSet::getStaticResultSet()
182 : throw( ListenerAlreadySetException, RuntimeException, std::exception )
183 : {
184 70 : osl::Guard< osl::Mutex > aGuard( maMutex );
185 :
186 70 : if ( mxListener.is() )
187 0 : throw ListenerAlreadySetException();
188 :
189 70 : mbStatic = true;
190 :
191 70 : if ( mxOriginal.is() )
192 : {
193 70 : mpOne = new SortedResultSet( mxOriginal->getStaticResultSet() );
194 70 : mxOne = mpOne;
195 70 : mpOne->Initialize( maOptions, mxCompFac );
196 : }
197 :
198 70 : return mxOne;
199 : }
200 :
201 :
202 : void SAL_CALL
203 0 : SortedDynamicResultSet::setListener( const Reference< XDynamicResultSetListener >& Listener )
204 : throw( ListenerAlreadySetException, RuntimeException, std::exception )
205 : {
206 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
207 :
208 0 : if ( mxListener.is() )
209 0 : throw ListenerAlreadySetException();
210 :
211 0 : addEventListener( Reference< XEventListener >::query( Listener ) );
212 :
213 0 : mxListener = Listener;
214 :
215 0 : if ( mxOriginal.is() )
216 0 : mxOriginal->setListener( mxOwnListener );
217 0 : }
218 :
219 :
220 : void SAL_CALL
221 0 : SortedDynamicResultSet::connectToCache( const Reference< XDynamicResultSet > & xCache )
222 : throw( ListenerAlreadySetException,
223 : AlreadyInitializedException,
224 : ServiceNotFoundException,
225 : RuntimeException, std::exception )
226 : {
227 0 : if( mxListener.is() )
228 0 : throw ListenerAlreadySetException();
229 :
230 0 : if( mbStatic )
231 0 : throw ListenerAlreadySetException();
232 :
233 0 : Reference< XSourceInitialization > xTarget( xCache, UNO_QUERY );
234 0 : if( xTarget.is() && m_xContext.is() )
235 : {
236 0 : Reference< XCachedDynamicResultSetStubFactory > xStubFactory;
237 : try
238 : {
239 0 : xStubFactory = CachedDynamicResultSetStubFactory::create( m_xContext );
240 : }
241 0 : catch ( Exception const & )
242 : {
243 : }
244 :
245 0 : if( xStubFactory.is() )
246 : {
247 0 : xStubFactory->connectToCache(
248 0 : this, xCache, Sequence< NumberedSortingInfo > (), NULL );
249 0 : return;
250 0 : }
251 : }
252 0 : throw ServiceNotFoundException();
253 : }
254 :
255 :
256 0 : sal_Int16 SAL_CALL SortedDynamicResultSet::getCapabilities()
257 : throw( RuntimeException, std::exception )
258 : {
259 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
260 :
261 0 : sal_Int16 nCaps = 0;
262 :
263 0 : if ( mxOriginal.is() )
264 0 : nCaps = mxOriginal->getCapabilities();
265 :
266 0 : nCaps |= ContentResultSetCapability::SORTED;
267 :
268 0 : return nCaps;
269 : }
270 :
271 :
272 : // XDynamicResultSetListener methods.
273 :
274 :
275 : /** In the first notify-call the listener gets the two
276 : <type>XResultSet</type>s and has to hold them. The <type>XResultSet</type>s
277 : are implementations of the service <type>ContentResultSet</type>.
278 :
279 : <p>The notified new <type>XResultSet</type> will stay valid after returning
280 : notification. The old one will become invalid after returning notification.
281 :
282 : <p>While in notify-call the listener is allowed to read old and new version,
283 : except in the first call, where only the new Resultset is valid.
284 :
285 : <p>The Listener is allowed to blockade this call, until he really want to go
286 : to the new version. The only situation, where the listener has to return the
287 : update call at once is, while he disposes his broadcaster or while he is
288 : removing himsef as listener (otherwise you deadlock)!!!
289 : */
290 0 : void SortedDynamicResultSet::impl_notify( const ListEvent& Changes )
291 : throw( RuntimeException )
292 : {
293 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
294 :
295 0 : bool bHasNew = false;
296 0 : bool bHasModified = false;
297 :
298 0 : SortedResultSet *pCurSet = NULL;
299 :
300 : // exchange mxNew and mxOld and immediately afterwards copy the tables
301 : // from Old to New
302 0 : if ( mbGotWelcome )
303 : {
304 0 : if ( mbUseOne )
305 : {
306 0 : mbUseOne = false;
307 0 : mpTwo->CopyData( mpOne );
308 0 : pCurSet = mpTwo;
309 : }
310 : else
311 : {
312 0 : mbUseOne = true;
313 0 : mpOne->CopyData( mpTwo );
314 0 : pCurSet = mpOne;
315 : }
316 : }
317 :
318 0 : if (!pCurSet)
319 0 : return;
320 :
321 0 : Any aRet;
322 :
323 : try {
324 0 : aRet = pCurSet->getPropertyValue("IsRowCountFinal");
325 : }
326 0 : catch (const UnknownPropertyException&) {}
327 0 : catch (const WrappedTargetException&) {}
328 :
329 0 : long nOldCount = pCurSet->GetCount();
330 0 : bool bWasFinal = false;
331 :
332 0 : aRet >>= bWasFinal;
333 :
334 : // handle the actions in the list
335 0 : for ( long i=0; i<Changes.Changes.getLength(); i++ )
336 : {
337 0 : const ListAction aAction = Changes.Changes[i];
338 0 : switch ( aAction.ListActionType )
339 : {
340 : case ListActionType::WELCOME:
341 : {
342 0 : WelcomeDynamicResultSetStruct aWelcome;
343 0 : if ( aAction.ActionInfo >>= aWelcome )
344 : {
345 0 : mpTwo = new SortedResultSet( aWelcome.Old );
346 0 : mxTwo = mpTwo;
347 0 : mpOne = new SortedResultSet( aWelcome.New );
348 0 : mxOne = mpOne;
349 0 : mpOne->Initialize( maOptions, mxCompFac );
350 0 : mbGotWelcome = true;
351 0 : mbUseOne = true;
352 0 : pCurSet = mpOne;
353 :
354 0 : aWelcome.Old = mxTwo;
355 0 : aWelcome.New = mxOne;
356 :
357 0 : ListAction *pWelcomeAction = new ListAction;
358 0 : pWelcomeAction->ActionInfo <<= aWelcome;
359 0 : pWelcomeAction->Position = 0;
360 0 : pWelcomeAction->Count = 0;
361 0 : pWelcomeAction->ListActionType = ListActionType::WELCOME;
362 :
363 0 : maActions.Insert( pWelcomeAction );
364 : }
365 : else
366 : {
367 : // throw RuntimeException();
368 : }
369 0 : break;
370 : }
371 : case ListActionType::INSERTED:
372 : {
373 0 : pCurSet->InsertNew( aAction.Position, aAction.Count );
374 0 : bHasNew = true;
375 0 : break;
376 : }
377 : case ListActionType::REMOVED:
378 : {
379 : pCurSet->Remove( aAction.Position,
380 : aAction.Count,
381 0 : &maActions );
382 0 : break;
383 : }
384 : case ListActionType::MOVED:
385 : {
386 0 : long nOffset = 0;
387 0 : if ( aAction.ActionInfo >>= nOffset )
388 : {
389 : pCurSet->Move( aAction.Position,
390 : aAction.Count,
391 0 : nOffset );
392 : }
393 0 : break;
394 : }
395 : case ListActionType::PROPERTIES_CHANGED:
396 : {
397 0 : pCurSet->SetChanged( aAction.Position, aAction.Count );
398 0 : bHasModified = true;
399 0 : break;
400 : }
401 0 : default: break;
402 : }
403 0 : }
404 :
405 0 : if ( bHasModified )
406 0 : pCurSet->ResortModified( &maActions );
407 :
408 0 : if ( bHasNew )
409 0 : pCurSet->ResortNew( &maActions );
410 :
411 : // send the new actions with a notify to the listeners
412 0 : SendNotify();
413 :
414 : // check for propertyChangeEvents
415 0 : pCurSet->CheckProperties( nOldCount, bWasFinal );
416 : }
417 :
418 : // XEventListener
419 :
420 0 : void SortedDynamicResultSet::impl_disposing( const EventObject& )
421 : throw( RuntimeException )
422 : {
423 0 : mxListener.clear();
424 0 : mxOriginal.clear();
425 0 : }
426 :
427 : // private methods
428 :
429 0 : void SortedDynamicResultSet::SendNotify()
430 : {
431 0 : long nCount = maActions.Count();
432 :
433 0 : if ( nCount && mxListener.is() )
434 : {
435 0 : Sequence< ListAction > aActionList( maActions.Count() );
436 0 : ListAction *pActionList = aActionList.getArray();
437 :
438 0 : for ( long i=0; i<nCount; i++ )
439 : {
440 0 : pActionList[ i ] = *(maActions.GetAction( i ));
441 : }
442 :
443 0 : ListEvent aNewEvent;
444 0 : aNewEvent.Changes = aActionList;
445 :
446 0 : mxListener->notify( aNewEvent );
447 : }
448 :
449 : // clean up
450 0 : maActions.Clear();
451 0 : }
452 :
453 : // SortedDynamicResultSetFactory
454 :
455 10 : SortedDynamicResultSetFactory::SortedDynamicResultSetFactory(
456 10 : const Reference< XComponentContext > & rxContext )
457 : {
458 10 : m_xContext = rxContext;
459 10 : }
460 :
461 :
462 20 : SortedDynamicResultSetFactory::~SortedDynamicResultSetFactory()
463 : {
464 20 : }
465 :
466 :
467 : // XServiceInfo methods.
468 :
469 1 : OUString SAL_CALL SortedDynamicResultSetFactory::getImplementationName()
470 : throw( css::uno::RuntimeException, std::exception )
471 : {
472 1 : return getImplementationName_Static();
473 : }
474 :
475 21 : OUString SortedDynamicResultSetFactory::getImplementationName_Static()
476 : {
477 21 : return OUString( "com.sun.star.comp.ucb.SortedDynamicResultSetFactory" );
478 : }
479 :
480 0 : sal_Bool SAL_CALL SortedDynamicResultSetFactory::supportsService( const OUString& ServiceName )
481 : throw( css::uno::RuntimeException, std::exception )
482 : {
483 0 : return cppu::supportsService( this, ServiceName );
484 : }
485 :
486 1 : css::uno::Sequence< OUString > SAL_CALL SortedDynamicResultSetFactory::getSupportedServiceNames()
487 : throw( css::uno::RuntimeException, std::exception )
488 : {
489 1 : return getSupportedServiceNames_Static();
490 : }
491 :
492 : static css::uno::Reference< css::uno::XInterface > SAL_CALL
493 10 : SortedDynamicResultSetFactory_CreateInstance( const css::uno::Reference<
494 : css::lang::XMultiServiceFactory> & rSMgr )
495 : throw( css::uno::Exception )
496 : {
497 : css::lang::XServiceInfo* pX = static_cast<css::lang::XServiceInfo*>(
498 10 : new SortedDynamicResultSetFactory( ucbhelper::getComponentContext(rSMgr) ));
499 10 : return css::uno::Reference< css::uno::XInterface >::query( pX );
500 : }
501 :
502 11 : css::uno::Sequence< OUString > SortedDynamicResultSetFactory::getSupportedServiceNames_Static()
503 : {
504 11 : com::sun::star::uno::Sequence< OUString > aSNS( 1 );
505 11 : aSNS.getArray()[ 0 ] = DYNAMIC_RESULTSET_FACTORY_NAME;
506 11 : return aSNS;
507 : }
508 :
509 :
510 : // Service factory implementation.
511 : css::uno::Reference< css::lang::XSingleServiceFactory >
512 10 : SortedDynamicResultSetFactory::createServiceFactory( const css::uno::Reference< css::lang::XMultiServiceFactory >& rxServiceMgr )
513 : {
514 : return css::uno::Reference< css::lang::XSingleServiceFactory >(
515 : cppu::createOneInstanceFactory(
516 : rxServiceMgr,
517 : SortedDynamicResultSetFactory::getImplementationName_Static(),
518 : SortedDynamicResultSetFactory_CreateInstance,
519 10 : SortedDynamicResultSetFactory::getSupportedServiceNames_Static() ) );
520 : }
521 :
522 : // SortedDynamicResultSetFactory methods.
523 :
524 : Reference< XDynamicResultSet > SAL_CALL
525 70 : SortedDynamicResultSetFactory::createSortedDynamicResultSet(
526 : const Reference< XDynamicResultSet > & Source,
527 : const Sequence< NumberedSortingInfo > & Info,
528 : const Reference< XAnyCompareFactory > & CompareFactory )
529 : throw( RuntimeException, std::exception )
530 : {
531 70 : Reference< XDynamicResultSet > xRet;
532 70 : xRet = new SortedDynamicResultSet( Source, Info, CompareFactory, m_xContext );
533 70 : return xRet;
534 : }
535 :
536 : // EventList
537 :
538 70 : void EventList::Clear()
539 : {
540 140 : for ( std::deque< ListAction* >::size_type i = 0;
541 70 : i < maData.size(); ++i )
542 : {
543 0 : delete maData[i];
544 : }
545 :
546 70 : maData.clear();
547 70 : }
548 :
549 0 : void EventList::AddEvent( sal_IntPtr nType, sal_IntPtr nPos, sal_IntPtr nCount )
550 : {
551 0 : ListAction *pAction = new ListAction;
552 0 : pAction->Position = nPos;
553 0 : pAction->Count = nCount;
554 0 : pAction->ListActionType = nType;
555 :
556 0 : Insert( pAction );
557 0 : }
558 :
559 : // SortedDynamicResultSetListener
560 :
561 70 : SortedDynamicResultSetListener::SortedDynamicResultSetListener(
562 70 : SortedDynamicResultSet *mOwner )
563 : {
564 70 : mpOwner = mOwner;
565 70 : }
566 :
567 :
568 140 : SortedDynamicResultSetListener::~SortedDynamicResultSetListener()
569 : {
570 140 : }
571 :
572 : // XEventListener ( base of XDynamicResultSetListener )
573 :
574 : void SAL_CALL
575 0 : SortedDynamicResultSetListener::disposing( const EventObject& Source )
576 : throw( RuntimeException, std::exception )
577 : {
578 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
579 :
580 0 : if ( mpOwner )
581 0 : mpOwner->impl_disposing( Source );
582 0 : }
583 :
584 :
585 : // XDynamicResultSetListener
586 :
587 : void SAL_CALL
588 0 : SortedDynamicResultSetListener::notify( const ListEvent& Changes )
589 : throw( RuntimeException, std::exception )
590 : {
591 0 : osl::Guard< osl::Mutex > aGuard( maMutex );
592 :
593 0 : if ( mpOwner )
594 0 : mpOwner->impl_notify( Changes );
595 0 : }
596 :
597 : // own methods:
598 :
599 : void SAL_CALL
600 70 : SortedDynamicResultSetListener::impl_OwnerDies()
601 : {
602 70 : osl::Guard< osl::Mutex > aGuard( maMutex );
603 70 : mpOwner = NULL;
604 70 : }
605 :
606 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|