Back to index

lightning-sunbird  0.9+nobinonly
nsAbRDFDataSource.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "nsAbRDFDataSource.h"
00040 #include "nsAbBaseCID.h"
00041 #include "nsIAbDirectory.h"
00042 #include "nsIAddrBookSession.h"
00043 #include "nsIAbCard.h"
00044 
00045 #include "rdf.h"
00046 #include "nsIRDFService.h"
00047 #include "nsRDFCID.h"
00048 #include "nsIRDFNode.h"
00049 #include "nsEnumeratorUtils.h"
00050 #include "nsIThread.h"
00051 #include "nsIEventQueueService.h"
00052 #include "nsIProxyObjectManager.h"
00053 
00054 #include "nsString.h"
00055 #include "nsCOMPtr.h"
00056 #include "nsXPIDLString.h"
00057 #include "nsAutoLock.h"
00058 
00059 // this is used for notification of observers using nsVoidArray
00060 typedef struct _nsAbRDFNotification {
00061   nsIRDFDataSource *datasource;
00062   nsIRDFResource *subject;
00063   nsIRDFResource *property;
00064   nsIRDFNode *object;
00065 } nsAbRDFNotification;
00066                                                 
00067 
00068 nsresult nsAbRDFDataSource::createNode(const PRUnichar *str, nsIRDFNode **node)
00069 {
00070        *node = nsnull;
00071        nsresult rv; 
00072     nsCOMPtr<nsIRDFService> rdf(do_GetService("@mozilla.org/rdf/rdf-service;1", &rv)); 
00073        NS_ENSURE_SUCCESS(rv, rv); // always check this before proceeding 
00074        nsCOMPtr<nsIRDFLiteral> value;
00075        rv = rdf->GetLiteral(str, getter_AddRefs(value));
00076        if (NS_SUCCEEDED(rv)) 
00077        {
00078               NS_IF_ADDREF(*node = value);
00079        }
00080        return rv;
00081 }
00082 
00083 nsresult nsAbRDFDataSource::createBlobNode(PRUint8 *value, PRUint32 &length, nsIRDFNode **node, nsIRDFService *rdfService)
00084 {
00085   NS_ENSURE_ARG_POINTER(node);
00086   NS_ENSURE_ARG_POINTER(rdfService);
00087 
00088   *node = nsnull;
00089   nsCOMPtr<nsIRDFBlob> blob;
00090   nsresult rv = rdfService->GetBlobLiteral(value, length, getter_AddRefs(blob));
00091   NS_ENSURE_SUCCESS(rv,rv);
00092   NS_IF_ADDREF(*node = blob);
00093   return rv;
00094 }
00095 
00096 PRBool nsAbRDFDataSource::changeEnumFunc(nsISupports *aElement, void *aData)
00097 {
00098   nsAbRDFNotification* note = (nsAbRDFNotification *)aData;
00099   nsIRDFObserver* observer = (nsIRDFObserver *)aElement;
00100 
00101   observer->OnChange(note->datasource,
00102                      note->subject,
00103                      note->property,
00104                      nsnull, note->object);
00105   return PR_TRUE;
00106 }
00107 
00108 PRBool nsAbRDFDataSource::assertEnumFunc(nsISupports *aElement, void *aData)
00109 {
00110   nsAbRDFNotification *note = (nsAbRDFNotification *)aData;
00111   nsIRDFObserver* observer = (nsIRDFObserver *)aElement;
00112   
00113   observer->OnAssert(note->datasource,
00114                      note->subject,
00115                      note->property,
00116                      note->object);
00117   return PR_TRUE;
00118 }
00119 
00120 PRBool nsAbRDFDataSource::unassertEnumFunc(nsISupports *aElement, void *aData)
00121 {
00122   nsAbRDFNotification* note = (nsAbRDFNotification *)aData;
00123   nsIRDFObserver* observer = (nsIRDFObserver *)aElement;
00124 
00125   observer->OnUnassert(note->datasource,
00126                        note->subject,
00127                        note->property,
00128                        note->object);
00129   return PR_TRUE;
00130 }
00131 
00132 nsresult nsAbRDFDataSource::CreateProxyObserver (nsIRDFObserver* observer,
00133        nsIRDFObserver** proxyObserver)
00134 {
00135        nsresult rv;
00136 
00137        nsCOMPtr<nsIEventQueueService> eventQSvc = do_GetService (NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
00138        NS_ENSURE_SUCCESS(rv, rv);
00139 
00140        // Get the UI event queue
00141        nsCOMPtr<nsIEventQueue> uiQueue;
00142        rv = eventQSvc->GetSpecialEventQueue (
00143                      nsIEventQueueService::UI_THREAD_EVENT_QUEUE,
00144                      getter_AddRefs (uiQueue));
00145        NS_ENSURE_SUCCESS(rv, rv);
00146 
00147        nsCOMPtr<nsIProxyObjectManager> proxyMgr = 
00148               do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
00149        NS_ENSURE_SUCCESS(rv, rv);
00150 
00151        // Proxy the observer on the UI queue
00152        /*
00153         * TODO
00154         * Currenly using PROXY_ASYNC, however
00155         * this can flood the event queue if
00156         * rate of events on the observer is
00157         * greater that the time to process the
00158         * events.
00159         * This causes the UI to pause.
00160         */
00161        rv = proxyMgr->GetProxyForObject (uiQueue,
00162               NS_GET_IID(nsIRDFObserver),
00163               observer,
00164               PROXY_ASYNC | PROXY_ALWAYS,
00165               (void** )proxyObserver);
00166 
00167        return rv;
00168 }
00169 
00170 nsresult nsAbRDFDataSource::CreateProxyObservers ()
00171 {
00172        nsresult rv = NS_OK;
00173 
00174        PRUint32 nObservers;
00175        mObservers->Count (&nObservers);
00176 
00177        if (!mProxyObservers)
00178        {
00179               rv = NS_NewISupportsArray(getter_AddRefs(mProxyObservers));
00180               NS_ENSURE_SUCCESS(rv, rv);
00181        }
00182 
00183        PRUint32 nProxyObservers;
00184        mProxyObservers->Count (&nProxyObservers);
00185 
00186        /*
00187         * For all the outstanding observers that
00188         * have not been proxied
00189         */
00190        for (PRUint32 i = nProxyObservers; i < nObservers; i++)
00191        {
00192               nsCOMPtr<nsISupports> supports;
00193               rv = mObservers->GetElementAt (i, getter_AddRefs (supports));
00194               NS_ENSURE_SUCCESS(rv, rv);
00195 
00196               nsCOMPtr<nsIRDFObserver> observer (do_QueryInterface (supports, &rv));
00197               NS_ENSURE_SUCCESS(rv, rv);
00198               
00199               // Create the proxy
00200               nsCOMPtr<nsIRDFObserver> proxyObserver;
00201               rv = CreateProxyObserver (observer, getter_AddRefs (proxyObserver));
00202               NS_ENSURE_SUCCESS(rv, rv);
00203 
00204               mProxyObservers->AppendElement(proxyObserver);
00205        }
00206 
00207        return rv;
00208 }
00209 
00210 nsresult nsAbRDFDataSource::NotifyObservers(nsIRDFResource *subject,
00211        nsIRDFResource *property,
00212        nsIRDFNode *object,
00213        PRBool assert,
00214        PRBool change)
00215 {
00216        NS_ASSERTION(!(change && assert),
00217                  "Can't change and assert at the same time!\n");
00218 
00219        if(!mLock)
00220        {
00221               NS_ERROR("Error in AutoLock resource in nsAbRDFDataSource::NotifyObservers()");
00222               return NS_ERROR_OUT_OF_MEMORY;
00223        }
00224 
00225        nsresult rv;
00226 
00227        nsAutoLock lockGuard (mLock);
00228 
00229        if (!mObservers)
00230               return NS_OK;
00231 
00232 
00233        // Get the current thread
00234        nsCOMPtr<nsIThread> currentThread;
00235        rv = nsIThread::GetCurrent (getter_AddRefs(currentThread));
00236        NS_ENSURE_SUCCESS (rv, rv);
00237 
00238        // Get the main thread, which is the UI thread
00239        /*
00240         * TODO
00241         * Is the main thread always guaranteed to be
00242         * the UI thread?
00243         *
00244         * Note that this also binds the data source
00245         * to the UI which is supposedly the only
00246         * place where it is used, but what about
00247         * RDF datasources that are not UI specific
00248         * but are used in the UI?
00249         */
00250        nsCOMPtr<nsIThread> uiThread;
00251        rv = nsIThread::GetMainThread (getter_AddRefs(uiThread));
00252        NS_ENSURE_SUCCESS (rv, rv);
00253 
00254        nsCOMPtr<nsISupportsArray> observers;
00255        if (currentThread == uiThread)
00256        {
00257               /*
00258                * Since this is the UI Thread use the
00259                * observers list directly for performance
00260                */
00261               observers = mObservers;
00262        }
00263        else
00264        {
00265               /*
00266                * This is a different thread to the UI
00267                * thread need to use proxies to the
00268                * observers
00269                *
00270                * Create the proxies
00271                */
00272               rv = CreateProxyObservers ();
00273               NS_ENSURE_SUCCESS (rv, rv);
00274 
00275               observers = mProxyObservers;
00276        }
00277 
00278        nsAbRDFNotification note = { this, subject, property, object };
00279        if (change)
00280               observers->EnumerateForwards(changeEnumFunc, &note);
00281        else if (assert)
00282               observers->EnumerateForwards(assertEnumFunc, &note);
00283        else
00284               observers->EnumerateForwards(unassertEnumFunc, &note);
00285 
00286        return NS_OK;
00287 }
00288 
00289 nsresult nsAbRDFDataSource::NotifyPropertyChanged(nsIRDFResource *resource,
00290        nsIRDFResource *propertyResource,
00291        const PRUnichar *oldValue, 
00292        const PRUnichar *newValue)
00293 {
00294        nsCOMPtr<nsIRDFNode> newValueNode;
00295        createNode(newValue, getter_AddRefs(newValueNode));
00296        NotifyObservers(resource, propertyResource, newValueNode, PR_FALSE, PR_TRUE);
00297        return NS_OK;
00298 }
00299 
00300 
00301 nsAbRDFDataSource::nsAbRDFDataSource():
00302   mObservers(nsnull),
00303   mProxyObservers(nsnull),
00304   mLock(nsnull)
00305 {
00306        mLock = PR_NewLock ();
00307 }
00308 
00309 nsAbRDFDataSource::~nsAbRDFDataSource (void)
00310 {
00311        if(mLock)
00312               PR_DestroyLock (mLock);
00313 }
00314 
00315 NS_IMPL_THREADSAFE_ISUPPORTS1(nsAbRDFDataSource, nsIRDFDataSource)
00316 
00317  // nsIRDFDataSource methods
00318 NS_IMETHODIMP nsAbRDFDataSource::GetURI(char* *uri)
00319 {
00320     NS_NOTREACHED("should be implemented by a subclass");
00321     return NS_ERROR_UNEXPECTED;
00322 }
00323 
00324 NS_IMETHODIMP nsAbRDFDataSource::GetSource(nsIRDFResource* property,
00325                                                nsIRDFNode* target,
00326                                                PRBool tv,
00327                                                nsIRDFResource** source /* out */)
00328 {
00329     return NS_RDF_NO_VALUE;
00330 }
00331 
00332 NS_IMETHODIMP nsAbRDFDataSource::GetTarget(nsIRDFResource* source,
00333                                                nsIRDFResource* property,
00334                                                PRBool tv,
00335                                                nsIRDFNode** target)
00336 {
00337     return NS_RDF_NO_VALUE;
00338 }
00339 
00340 
00341 NS_IMETHODIMP nsAbRDFDataSource::GetSources(nsIRDFResource* property,
00342                                                 nsIRDFNode* target,
00343                                                 PRBool tv,
00344                                                 nsISimpleEnumerator** sources)
00345 {
00346     return NS_RDF_NO_VALUE;
00347 }
00348 
00349 NS_IMETHODIMP nsAbRDFDataSource::GetTargets(nsIRDFResource* source,
00350                                                 nsIRDFResource* property,    
00351                                                 PRBool tv,
00352                                                 nsISimpleEnumerator** targets)
00353 {
00354     return NS_RDF_NO_VALUE;
00355 }
00356 
00357 NS_IMETHODIMP nsAbRDFDataSource::Assert(nsIRDFResource* source,
00358                       nsIRDFResource* property, 
00359                       nsIRDFNode* target,
00360                       PRBool tv)
00361 {
00362     return NS_RDF_NO_VALUE;
00363 }
00364 
00365 NS_IMETHODIMP nsAbRDFDataSource::Unassert(nsIRDFResource* source,
00366                         nsIRDFResource* property,
00367                         nsIRDFNode* target)
00368 {
00369     return NS_RDF_NO_VALUE;
00370 }
00371 
00372 NS_IMETHODIMP nsAbRDFDataSource::Change(nsIRDFResource *aSource,
00373                                               nsIRDFResource *aProperty,
00374                                               nsIRDFNode *aOldTarget,
00375                                               nsIRDFNode *aNewTarget)
00376 {
00377     return NS_RDF_NO_VALUE;
00378 }
00379 
00380 NS_IMETHODIMP nsAbRDFDataSource::Move(nsIRDFResource *aOldSource,
00381                                             nsIRDFResource *aNewSource,
00382                                             nsIRDFResource *aProperty,
00383                                             nsIRDFNode *aTarget)
00384 {
00385     return NS_RDF_NO_VALUE;
00386 }
00387 
00388 
00389 NS_IMETHODIMP nsAbRDFDataSource::HasAssertion(nsIRDFResource* source,
00390                             nsIRDFResource* property,
00391                             nsIRDFNode* target,
00392                             PRBool tv,
00393                             PRBool* hasAssertion)
00394 {
00395     *hasAssertion = PR_FALSE;
00396     return NS_OK;
00397 }
00398 
00399 NS_IMETHODIMP nsAbRDFDataSource::AddObserver(nsIRDFObserver* observer)
00400 {
00401        if(!mLock)
00402        {
00403               NS_ERROR("Error in AutoLock resource in nsAbRDFDataSource::AddObservers()");
00404               return NS_ERROR_OUT_OF_MEMORY;
00405        }
00406 
00407        nsresult rv;
00408 
00409        // Lock the whole method
00410        nsAutoLock lockGuard (mLock);
00411 
00412        if (!mObservers)
00413        {
00414               rv = NS_NewISupportsArray(getter_AddRefs(mObservers));
00415               NS_ENSURE_SUCCESS(rv, rv);
00416        }
00417 
00418        // Do not add if already present
00419        PRInt32 i;
00420        mObservers->GetIndexOf (observer, &i);
00421        if (i >= 0)
00422               return NS_OK;
00423 
00424        mObservers->AppendElement(observer);
00425 
00426        /*
00427         * If the proxy observers has been created
00428         * then do the work here to avoid unecessary
00429         * delay when performing the notify from a
00430         * different thread
00431         */
00432        if (mProxyObservers)
00433        {
00434               nsCOMPtr<nsIRDFObserver> proxyObserver;
00435               rv = CreateProxyObserver (observer,
00436                      getter_AddRefs(proxyObserver));
00437               NS_ENSURE_SUCCESS(rv, rv);
00438 
00439               mProxyObservers->AppendElement (proxyObserver);
00440        }
00441 
00442        return NS_OK;
00443 }
00444 
00445 NS_IMETHODIMP nsAbRDFDataSource::RemoveObserver(nsIRDFObserver* observer)
00446 {
00447        if(!mLock)
00448        {
00449               NS_ERROR("Error in AutoLock resource in nsAbRDFDataSource::RemoveObservers()");
00450               return NS_ERROR_OUT_OF_MEMORY;
00451        }
00452 
00453        // Lock the whole method
00454        nsAutoLock lockGuard (mLock);
00455 
00456        if (!mObservers)
00457               return NS_OK;
00458 
00459        PRInt32 i;
00460        mObservers->GetIndexOf (observer, &i);
00461        if (i >= 0)
00462        {
00463               mObservers->RemoveElementAt(i);
00464 
00465               if (mProxyObservers)
00466                      mProxyObservers->RemoveElementAt(i);
00467        }
00468 
00469        return NS_OK;
00470 }
00471 
00472 NS_IMETHODIMP 
00473 nsAbRDFDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, PRBool *result)
00474 {
00475   *result = PR_FALSE;
00476   return NS_OK;
00477 }
00478 
00479 NS_IMETHODIMP 
00480 nsAbRDFDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, PRBool *result)
00481 {
00482   *result = PR_FALSE;
00483   return NS_OK;
00484 }
00485 
00486 NS_IMETHODIMP nsAbRDFDataSource::ArcLabelsIn(nsIRDFNode* node,
00487                                                 nsISimpleEnumerator** labels)
00488 {
00489     return NS_RDF_NO_VALUE;
00490 }
00491 
00492 NS_IMETHODIMP nsAbRDFDataSource::ArcLabelsOut(nsIRDFResource* source,
00493                                                  nsISimpleEnumerator** labels)
00494 {
00495     return NS_RDF_NO_VALUE;
00496 }
00497 
00498 NS_IMETHODIMP nsAbRDFDataSource::GetAllResources(nsISimpleEnumerator** aCursor)
00499 {
00500     return NS_RDF_NO_VALUE;
00501 }
00502 
00503 NS_IMETHODIMP
00504 nsAbRDFDataSource::GetAllCmds(nsIRDFResource* source,
00505                                       nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
00506 {
00507     return NS_RDF_NO_VALUE;
00508 }
00509 
00510 NS_IMETHODIMP
00511 nsAbRDFDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
00512                                         nsIRDFResource*   aCommand,
00513                                         nsISupportsArray/*<nsIRDFResource>*/* aArguments,
00514                                         PRBool* aResult)
00515 {
00516     return NS_RDF_NO_VALUE;
00517 }
00518 
00519 NS_IMETHODIMP nsAbRDFDataSource::DoCommand
00520 (nsISupportsArray * aSources, nsIRDFResource* aCommand, nsISupportsArray * aArguments)
00521 {
00522     return NS_RDF_NO_VALUE;
00523 }
00524 
00525 NS_IMETHODIMP
00526 nsAbRDFDataSource::BeginUpdateBatch()
00527 {
00528     return NS_OK;
00529 }
00530 
00531 NS_IMETHODIMP
00532 nsAbRDFDataSource::EndUpdateBatch()
00533 {
00534     return NS_OK;
00535 }