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