1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: MQueryHelper.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_connectivity.hxx"
34 #include "MQueryHelper.hxx"
35 #include "MTypeConverter.hxx"
36 #include "MConnection.hxx"
37 #include "MNSDeclares.hxx"
38 #include "MLdapAttributeMap.hxx"
40 #include <connectivity/dbexception.hxx>
42 #include "resource/mozab_res.hrc"
44 using namespace connectivity::mozab
;
47 NS_IMPL_THREADSAFE_ISUPPORTS1(connectivity::mozab::MQueryHelper
,nsIAbDirectoryQueryResultListener
)
50 // class MQueryHelperResultEntry
54 MQueryHelperResultEntry::MQueryHelperResultEntry()
60 MQueryHelperResultEntry::~MQueryHelperResultEntry()
62 OSL_TRACE("IN MQueryHelperResultEntry::~MQueryHelperResultEntry()\n");
63 OSL_TRACE("OUT MQueryHelperResultEntry::~MQueryHelperResultEntry()\n");
67 MQueryHelperResultEntry::setCard(nsIAbCard
*card
)
72 MQueryHelperResultEntry::getCard()
76 void MQueryHelperResultEntry::insert( const rtl::OString
&key
, rtl::OUString
&value
)
78 m_Fields
[ key
] = value
;
81 rtl::OUString
MQueryHelperResultEntry::getValue( const rtl::OString
&key
) const
83 FieldMap::const_iterator iter
= m_Fields
.find( key
);
84 if ( iter
== m_Fields
.end() )
86 return rtl::OUString();
94 void MQueryHelperResultEntry::setValue( const rtl::OString
&key
, const rtl::OUString
& rValue
)
96 m_Fields
[ key
] = rValue
;
101 MQueryHelper::MQueryHelper()
103 ,m_bHasMore( sal_True
)
104 ,m_bAtEnd( sal_False
)
105 ,m_bErrorCondition( sal_False
)
106 ,m_bQueryComplete( sal_False
)
107 ,mRefCnt( 0 ) // NSISUPPORTS - Initialize RefCnt to 0
110 #if OSL_DEBUG_LEVEL > 0
111 m_oThreadID
= osl_getThreadIdentifier(NULL
);
115 MQueryHelper::~MQueryHelper()
117 OSL_TRACE("IN MQueryHelper::~MQueryHelper()\n");
119 OSL_TRACE("OUT MQueryHelper::~MQueryHelper()\n");
123 MQueryHelper::append(MQueryHelperResultEntry
* resEnt
)
125 if ( resEnt
!= NULL
) {
126 m_aResults
.push_back( resEnt
);
127 m_bAtEnd
= sal_False
;
132 MQueryHelper::clear_results()
134 resultsArray::iterator iter
= m_aResults
.begin();
135 while ( iter
!= m_aResults
.end() ) {
143 MQueryHelper::rewind()
149 MQueryHelper::reset()
152 m_bHasMore
= sal_True
;
153 m_bQueryComplete
= sal_False
;
154 m_bAtEnd
= sal_False
;
155 m_bErrorCondition
= sal_False
;
160 MQueryHelper::clearResultOrComplete()
162 // Don't use a Mutex, it should be called by a method already holding it.
163 OSL_TRACE("In/Out : clearResultOrComplete()");
164 m_aCondition
.reset();
168 MQueryHelper::notifyResultOrComplete()
170 OSL_TRACE("In/Out : notifyResultOrComplete()");
175 MQueryHelper::waitForResultOrComplete( )
177 TimeValue timeValue
= { 1, 0 }; // 20 Seconds 0 NanoSecond timeout
179 osl::Condition::Result rv
= ::osl::Condition::result_ok
;
181 OSL_TRACE("In : waitForResultOrComplete()");
182 // Can't hold mutex or condition would never get set...
183 while( (m_aCondition
.check() == sal_False
|| rv
== ::osl::Condition::result_error
) && times
< 20) {
184 rv
= m_aCondition
.wait( &timeValue
);
187 if (times
>= 20 && rv
== ::osl::Condition::result_timeout
) {
188 OSL_TRACE("waitForResultOrComplete() : Timeout!");
189 m_aError
.setResId( STR_TIMEOUT_WAITING
);
194 OSL_TRACE("waitForResultOrComplete() : Error returned!");
195 m_aError
.setResId( STR_ERR_EXECUTING_QUERY
);
199 OSL_TRACE(" Out : waitForResultOrComplete()");
204 MQueryHelperResultEntry
*
205 MQueryHelper::next( )
207 MQueryHelperResultEntry
* result
;
214 result
= getByIndex( m_nIndex
+ 1) ; // Add 1 as Row is numbered from 1 to N
225 MQueryHelperResultEntry
*
226 MQueryHelper::getByIndex( sal_uInt32 nRow
)
228 // Row numbers are from 1 to N, need to ensure this, and then
235 // Obtain the Mutex - don't use a guard as we want to be able to release
236 // and acquire again...
238 if ( nRow
> m_aResults
.size() )
240 if ( m_bQueryComplete
)
248 clearResultOrComplete();
250 if ( !waitForResultOrComplete( ) )
257 return( m_aResults
[ nRow
-1 ] );
259 } while ( sal_True
);
263 MQueryHelper::hasMore() const
269 MQueryHelper::atEnd() const
275 MQueryHelper::isError() const
277 return m_bErrorCondition
;
281 MQueryHelper::queryComplete() const
283 return m_bQueryComplete
;
287 MQueryHelper::waitForQueryComplete( )
291 OSL_TRACE("In : waitForQueryComplete()");
292 if ( ! m_bQueryComplete
) {
296 clearResultOrComplete();
297 if ( !waitForResultOrComplete( ) )
301 while ( !m_bQueryComplete
);
305 OSL_TRACE("Out : waitForQueryComplete()");
310 MQueryHelper::waitForRow( sal_Int32 rowNum
)
316 clearResultOrComplete();
317 if ( !waitForResultOrComplete() )
321 while ( !m_bQueryComplete
&& m_aResults
.size() < (size_t)rowNum
);
327 // -------------------------------------------------------------------------
330 MQueryHelper::getResultCount() const
332 OSL_TRACE( "IN MQueryHelper::getResultCount()" );
333 if ( !m_bQueryComplete
)
335 OSL_TRACE( "\tOUT MQueryHelper::getResultCount() = -1\n");
340 OSL_TRACE( "\tOUT MQueryHelper::getResultCount() = %d\n", m_aResults
.size() );
341 return static_cast<sal_Int32
>(m_aResults
.size());
345 // -------------------------------------------------------------------------
348 MQueryHelper::getRealCount() const
350 OSL_TRACE( "IN/OUT MQueryHelper::getRealCount() = %d\n", m_aResults
.size() );
351 return static_cast<sal_Int32
>(m_aResults
.size());
354 // -------------------------------------------------------------------------
355 NS_IMETHODIMP
MQueryHelper::OnQueryItem(nsIAbDirectoryQueryResult
*result
)
357 ::osl::MutexGuard
aGuard( m_aMutex
);
358 #if OSL_DEBUG_LEVEL > 0
359 OSL_TRACE( "IN MQueryHelper::OnQueryItem() Caller thread: %4d \n",m_oThreadID
);
364 if ( result
== NULL
) {
365 OSL_TRACE("\tresult ptr is NULL\n");
369 // Get return status of executeQuery() call.
370 rv
= result
-> GetType(&resultType
);
371 NS_ENSURE_SUCCESS(rv
, rv
);
373 // Check for errors of the executeQuery() call.
374 switch ( resultType
) {
375 case nsIAbDirectoryQueryResult::queryResultError
:
376 OSL_TRACE("\tresultType == nsIAbDirectoryQueryResult::queryResultError\n");
377 m_bQueryComplete
= sal_True
;
378 m_bErrorCondition
= sal_True
;
379 notifyResultOrComplete();
381 case nsIAbDirectoryQueryResult::queryResultStopped
:
382 OSL_TRACE("\tresultType == nsIAbDirectoryQueryResult::queryResultStopped\n");
383 m_bQueryComplete
= sal_True
;
384 notifyResultOrComplete();
386 case nsIAbDirectoryQueryResult::queryResultComplete
:
387 OSL_TRACE("\tresultType == nsIAbDirectoryQueryResult::queryResultComplete\n");
388 m_bQueryComplete
= sal_True
;
389 notifyResultOrComplete();
391 case nsIAbDirectoryQueryResult::queryResultMatch
:
392 OSL_TRACE("IN MQueryHelper::OnQueryItem --> queryResultMatch\n");
393 // Don't return, continues onto rest of method.
396 OSL_TRACE("\t******** Unexpected : resultType\n");
397 m_bQueryComplete
= sal_True
;
401 // Initialise an array that holds the resultset of the query.
402 nsCOMPtr
<nsISupportsArray
> properties
;
403 rv
= result
-> GetResult(getter_AddRefs (properties
));
404 NS_ENSURE_SUCCESS(rv
, rv
);
407 nsCOMPtr
<nsISupports
> item
;
408 rv
= properties
-> GetElementAt(0, getter_AddRefs(item
));
409 NS_ENSURE_SUCCESS(rv
, rv
);
411 nsCOMPtr
<nsIAbDirectoryQueryPropertyValue
> property(do_QueryInterface(item
, &rv
));
412 NS_ENSURE_SUCCESS(rv
, rv
);
415 rv
= property
-> GetName(&name
);
416 NS_ENSURE_SUCCESS(rv
, rv
);
417 if ( !strcmp(name
,"card:nsIAbCard") )
419 nsCOMPtr
<nsISupports
> cardSupports
;
420 property
->GetValueISupports (getter_AddRefs (cardSupports
));
421 nsCOMPtr
<nsIAbCard
> card(do_QueryInterface(cardSupports
, &rv
));
422 NS_ENSURE_SUCCESS(rv
, rv
);
426 nsMemory::Free(name
);
428 OSL_TRACE( "\tOUT MQueryHelper::OnQueryItem()\n" );
430 notifyResultOrComplete();
435 // -----------------------------------------------------------------------------
436 void MQueryHelper::notifyQueryError()
438 m_bQueryComplete
= sal_True
;
439 notifyResultOrComplete() ;
442 const char * getAddrURI(const nsIAbDirectory
* directory
)
445 nsCOMPtr
<nsIRDFResource
> rdfResource
= do_QueryInterface((nsISupports
*)directory
, &retCode
) ;
446 if (NS_FAILED(retCode
)) { return NULL
; }
448 retCode
=rdfResource
->GetValueConst(&uri
);
449 if (NS_FAILED(retCode
)) { return NULL
; }
453 #define ENSURE_GETUPDATECARD(x) \
454 if (NS_FAILED(retCode)) \
459 static NS_DEFINE_CID(kRDFServiceCID
, NS_RDFSERVICE_CID
);
461 //Some address book does not support query uri on card
462 //In this case, we can't resync the cards, we just return the old cards
463 nsIAbCard
* getUpdatedCard( nsIAbCard
* card
)
465 OSL_ENSURE(card
!= NULL
, "getUpdatedCard for NULL");
467 nsCOMPtr
<nsIRDFResource
> rdfResource
= do_QueryInterface((nsISupports
*)card
, &retCode
) ;
468 ENSURE_GETUPDATECARD( "IN getUpdatedCard: Card does not support nsIRDFResource\n" );
471 retCode
=rdfResource
->GetValueConst(&uri
);
472 ENSURE_GETUPDATECARD( "IN getUpdatedCard: Card does not has a uri\n" );
474 nsCOMPtr
<nsIRDFService
> rdfService (do_GetService(kRDFServiceCID
, &retCode
)) ;
475 ENSURE_GETUPDATECARD( "IN getUpdatedCard: Card does not has a uri\n" );
477 nsCOMPtr
<nsIRDFResource
> rdfCard
;
479 retCode
= rdfService
->GetResource(nsDependentCString(uri
), getter_AddRefs(rdfCard
)) ;
480 ENSURE_GETUPDATECARD( "IN getUpdatedCard: Can not get the updated card\n" );
482 nsCOMPtr
<nsIAbCard
> aNewCard
=do_QueryInterface((nsISupports
*)rdfCard
, &retCode
);
483 ENSURE_GETUPDATECARD( "IN getUpdatedCard: Error in get new card\n" );
488 #define ENSURE_MOZAB_PROFILE_NOT_LOOKED(directory) \
489 if (getDirectoryType(directory) == SDBCAddress::Mozilla && isProfileLocked(NULL)) \
491 m_aError.setResId( STR_MOZILLA_IS_RUNNIG_NO_CHANGES ); \
495 sal_Int32
MQueryHelper::commitCard(const sal_Int32 rowIndex
,nsIAbDirectory
* directory
)
497 ENSURE_MOZAB_PROFILE_NOT_LOOKED(directory
);
499 MQueryHelperResultEntry
*resEntry
= getByIndex(rowIndex
);
504 nsIAbCard
*card
=resEntry
->getCard();
511 rv
= directory
->HasCard(card
,&hasCard
);
512 if (setCardValues(rowIndex
) != sal_True
)
515 if (!NS_FAILED(rv
) && hasCard
)
517 rv
= card
->EditCardToDatabase(getAddrURI(directory
));
521 nsIAbCard
*addedCard
=NULL
;
522 rv
= directory
->AddCard(card
,&addedCard
);
524 resEntry
->setCard(addedCard
);
526 //We return NS_ERROR_FILE_ACCESS_DENIED in the case the mozillaAB has been changed out side of our process
527 if (rv
== NS_ERROR_FILE_ACCESS_DENIED
)
528 m_aError
.setResId( STR_FOREIGN_PROCESS_CHANGED_AB
);
530 return !(NS_FAILED(rv
));
533 sal_Int32
MQueryHelper::deleteCard(const sal_Int32 rowIndex
,nsIAbDirectory
* directory
)
535 ENSURE_MOZAB_PROFILE_NOT_LOOKED(directory
);
536 MQueryHelperResultEntry
*resEntry
= getByIndex(rowIndex
);
541 nsIAbCard
*card
=resEntry
->getCard();
548 if (resEntry
->getRowStates() == RowStates_Inserted
)
554 rv
= directory
->HasCard(card
,&hasCard
);
556 if (!NS_FAILED(rv
) && hasCard
)
558 nsCOMPtr
<nsISupportsArray
> cardsToDelete
;
559 rv
= NS_NewISupportsArray(getter_AddRefs(cardsToDelete
));
560 if (NS_SUCCEEDED(rv
))
562 nsCOMPtr
<nsISupports
> supports
= do_QueryInterface(card
, &rv
);
563 if (NS_SUCCEEDED(rv
))
565 rv
= cardsToDelete
->AppendElement(supports
);
566 if (NS_SUCCEEDED(rv
))
567 rv
= directory
->DeleteCards(cardsToDelete
);
572 if (NS_SUCCEEDED(rv
))
573 resEntry
->setRowStates(RowStates_Deleted
);
574 //We return NS_ERROR_FILE_ACCESS_DENIED in the case the mozillaAB has been changed out side of our process
575 if (rv
== NS_ERROR_FILE_ACCESS_DENIED
)
576 m_aError
.setResId( STR_FOREIGN_PROCESS_CHANGED_AB
);
577 return !(NS_FAILED(rv
));
580 sal_Bool
MQueryHelper::setCardValues(const sal_Int32 rowIndex
)
582 MQueryHelperResultEntry
*resEntry
= getByIndex(rowIndex
);
585 m_aError
.setResId( STR_CANT_FIND_ROW
);
588 nsIAbCard
*card
=resEntry
->getCard();
591 m_aError
.setResId( STR_CANT_FIND_CARD_FOR_ROW
);
595 MLdapAttributeMap::fillCardFromResult( *card
, *resEntry
);
599 void MQueryHelper::getCardValues(nsIAbCard
*card
,sal_Int32 rowIndex
)
601 MQueryHelperResultEntry
*resEntry
;
604 resEntry
= getByIndex(rowIndex
);
607 resEntry
= new MQueryHelperResultEntry();
609 MLdapAttributeMap::fillResultFromCard( *resEntry
, *card
);
610 resEntry
->setCard(card
);
614 sal_Bool
MQueryHelper::resyncRow(sal_Int32 rowIndex
)
617 MQueryHelperResultEntry
*resEntry
= getByIndex(rowIndex
);
620 m_aError
.setResId( STR_CANT_FIND_ROW
);
623 nsIAbCard
*card
=resEntry
->getCard();
624 card
= getUpdatedCard(card
);
625 getCardValues(card
,rowIndex
);
628 // -------------------------------------------------------------------------
629 sal_Int32
MQueryHelper::createNewCard()
631 ::osl::MutexGuard
aGuard( m_aMutex
);
633 nsCOMPtr
<nsIAbCard
> card
= do_CreateInstance(NS_ABCARDPROPERTY_CONTRACTID
, &rv
);
636 return static_cast<sal_Int32
>(m_aResults
.size());