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