sbLibraryManager.cpp
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2009 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
29 #include "sbLibraryManager.h"
30 #include "sbLibraryCID.h"
31 
32 #include <nsIAppStartupNotifier.h>
33 #include <nsICategoryManager.h>
34 #include <nsIGenericFactory.h>
35 #include <nsILocalFile.h>
36 #include <nsIObserver.h>
37 #include <nsIObserverService.h>
38 #include <nsIPrefBranch.h>
39 #include <nsIPrefService.h>
40 #include <nsIRDFDataSource.h>
41 #include <nsISimpleEnumerator.h>
42 #include <nsISupportsPrimitives.h>
43 #include <sbILibraryFactory.h>
44 #include <sbILibraryManagerListener.h>
45 
46 #include <nsArrayEnumerator.h>
47 #include <nsAutoLock.h>
48 #include <nsCOMArray.h>
49 #include <nsComponentManagerUtils.h>
50 #include <nsEnumeratorUtils.h>
51 #include <nsServiceManagerUtils.h>
52 #include <prlog.h>
53 #include <rdf.h>
54 #include <sbLibraryUtils.h>
55 #include <sbDebugUtils.h>
56 #include <sbThreadUtils.h>
58 
59 /* for sbILibraryUtils::GetCanonicalPath */
60 #if XP_WIN
61 #include <windows.h>
62 #endif
63 
69 #define NS_PROFILE_STARTUP_OBSERVER_ID "profile-after-change"
70 #define NS_PROFILE_TEARDOWN_OBSERVER_ID "profile-change-teardown"
71 
76 
77 static nsString sString;
78 
80 : mLoaderCache(SB_LIBRARY_LOADER_CATEGORY),
81  mLock(nsnull)
82 {
83  MOZ_COUNT_CTOR(sbLibraryManager);
84  NS_ASSERTION(SB_IsMainThread(), "Wrong thread!");
85 
87 
88  TRACE("sbLibraryManager[0x%x] - Created", this);
89 }
90 
91 sbLibraryManager::~sbLibraryManager()
92 {
93  NS_ASSERTION(SB_IsMainThread(mThreadManager), "Wrong thread!");
94 
95  if(mLock) {
96  nsAutoLock::DestroyLock(mLock);
97  }
98 
99  TRACE("LibraryManager[0x%x] - Destroyed", this);
100  MOZ_COUNT_DTOR(sbLibraryManager);
101 }
102 
103 /* static */ NS_METHOD
104 sbLibraryManager::RegisterSelf(nsIComponentManager* aCompMgr,
105  nsIFile* aPath,
106  const char* aLoaderStr,
107  const char* aType,
108  const nsModuleComponentInfo *aInfo)
109 {
110  nsresult rv;
111  nsCOMPtr<nsICategoryManager> categoryManager =
112  do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
113  NS_ENSURE_SUCCESS(rv, rv);
114 
115  rv = categoryManager->AddCategoryEntry(APPSTARTUP_CATEGORY,
117  "service,"
119  PR_TRUE, PR_TRUE, nsnull);
120  NS_ENSURE_SUCCESS(rv, rv);
121 
122  return rv;
123 }
124 
128 nsresult
130 {
131  TRACE("sbLibraryManager[0x%x] - Init", this);
132  NS_ASSERTION(SB_IsMainThread(), "Wrong thread!");
133 
134  nsresult rv;
135 
136  PRBool success = mLibraryTable.Init();
137  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
138 
139  success = mListeners.Init();
140  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
141 
142  mLock = nsAutoLock::NewLock("sbLibraryManager::mLock");
143  NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY);
144 
145  // Get the thread manager. This is used so that main thread checks work
146  // during XPCOM shutdown.
147  mThreadManager = do_GetService("@mozilla.org/thread-manager;1", &rv);
148  NS_ENSURE_SUCCESS(rv, rv);
149 
150  nsCOMPtr<nsIObserverService> observerService =
151  do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
152  NS_ENSURE_SUCCESS(rv, rv);
153 
154  rv = observerService->AddObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID,
155  PR_TRUE);
156  NS_ENSURE_SUCCESS(rv, rv);
157 
158  rv = observerService->AddObserver(this, NS_PROFILE_TEARDOWN_OBSERVER_ID,
159  PR_TRUE);
160  NS_ENSURE_SUCCESS(rv, rv);
161 
162  return NS_OK;
163 }
164 
175 /* static */ PLDHashOperator PR_CALLBACK
176 sbLibraryManager::AddLibrariesToCOMArrayCallback(nsStringHashKey::KeyType aKey,
177  sbLibraryInfo* aEntry,
178  void* aUserData)
179 {
180  NS_ASSERTION(aEntry, "Null entry in hashtable!");
181  NS_ASSERTION(aEntry->library, "Null library in hashtable!");
182 
183  nsCOMArray<sbILibrary>* array =
184  static_cast<nsCOMArray<sbILibrary>*>(aUserData);
185 
186  PRBool success = array->AppendObject(aEntry->library);
187  NS_ENSURE_TRUE(success, PL_DHASH_STOP);
188 
189  return PL_DHASH_NEXT;
190 }
191 
202 /* static */ PLDHashOperator PR_CALLBACK
203 sbLibraryManager::AddStartupLibrariesToCOMArrayCallback(nsStringHashKey::KeyType aKey,
204  sbLibraryInfo* aEntry,
205  void* aUserData)
206 {
207  NS_ASSERTION(aEntry, "Null entry in hashtable!");
208  NS_ASSERTION(aEntry->library, "Null library in hashtable!");
209 
210  nsCOMArray<sbILibrary>* array =
211  static_cast<nsCOMArray<sbILibrary>*>(aUserData);
212 
213  if (aEntry->loader && aEntry->loadAtStartup) {
214  PRBool success = array->AppendObject(aEntry->library);
215  NS_ENSURE_TRUE(success, PL_DHASH_STOP);
216  }
217 
218  return PL_DHASH_NEXT;
219 }
220 
231 /* static */ PLDHashOperator PR_CALLBACK
232 sbLibraryManager::AddListenersToCOMArrayCallback(nsISupportsHashKey::KeyType aKey,
234  void* aUserData)
235 {
236  NS_ASSERTION(aKey, "Null key in hashtable!");
237  NS_ASSERTION(aEntry, "Null entry in hashtable!");
238 
239  nsCOMArray<sbILibraryManagerListener>* array =
240  static_cast<nsCOMArray<sbILibraryManagerListener>*>(aUserData);
241 
242  PRBool success = array->AppendObject(aEntry);
243  NS_ENSURE_TRUE(success, PL_DHASH_STOP);
244 
245  return PL_DHASH_NEXT;
246 }
247 
259 /* static */ PLDHashOperator PR_CALLBACK
260 sbLibraryManager::AssertAllLibrariesCallback(nsStringHashKey::KeyType aKey,
261  sbLibraryInfo* aEntry,
262  void* aUserData)
263 {
264  NS_ASSERTION(aEntry, "Null entry in hashtable!");
265  NS_ASSERTION(aEntry->library, "Null library in hashtable!");
266 
267  nsCOMPtr<nsIRDFDataSource> ds = static_cast<nsIRDFDataSource*>(aUserData);
268  NS_ENSURE_TRUE(ds, PL_DHASH_STOP);
269 
270  nsresult rv = AssertLibrary(ds, aEntry->library);
271  NS_ENSURE_SUCCESS(rv, PL_DHASH_STOP);
272 
273  return PL_DHASH_NEXT;
274 }
275 
284 /* static */ nsresult
285 sbLibraryManager::AssertLibrary(nsIRDFDataSource* aDataSource,
286  sbILibrary* aLibrary)
287 {
288  NS_NOTYETIMPLEMENTED("sbLibraryManager::AssertLibrary");
289  return NS_ERROR_NOT_IMPLEMENTED;
290 }
291 
300 /* static */ nsresult
301 sbLibraryManager::UnassertLibrary(nsIRDFDataSource* aDataSource,
302  sbILibrary* aLibrary)
303 {
304  NS_NOTYETIMPLEMENTED("sbLibraryManager::UnassertLibrary");
305  return NS_ERROR_NOT_IMPLEMENTED;
306 }
307 
314 nsresult
315 sbLibraryManager::GenerateDataSource()
316 {
317  NS_ASSERTION(!mDataSource, "GenerateDataSource called twice!");
318 
319  nsresult rv;
320  mDataSource = do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX
321  "in-memory-datasource", &rv);
322  NS_ENSURE_SUCCESS(rv, rv);
323 
324  PRUint32 libraryCount = mLibraryTable.Count();
325  if (!libraryCount) {
326  return NS_OK;
327  }
328 
329  PRUint32 enumCount =
330  mLibraryTable.EnumerateRead(AssertAllLibrariesCallback, mDataSource);
331  NS_ENSURE_TRUE(enumCount == libraryCount, NS_ERROR_FAILURE);
332 
333  return NS_OK;
334 }
335 
344 void
345 sbLibraryManager::NotifyListenersLibraryRegistered(sbILibrary* aLibrary)
346 {
347  TRACE("sbLibraryManager[0x%x] - NotifyListenersLibraryRegistered", this);
348 
349  nsCOMArray<sbILibraryManagerListener> listeners;
350  {
351  nsAutoLock lock(mLock);
352  mListeners.EnumerateRead(AddListenersToCOMArrayCallback, &listeners);
353  }
354 
355  PRInt32 count = listeners.Count();
356  for (PRInt32 index = 0; index < count; index++) {
357  nsCOMPtr<sbILibraryManagerListener> listener =
358  listeners.ObjectAt(index);
359  NS_ASSERTION(listener, "Null listener!");
360 
361  listener->OnLibraryRegistered(aLibrary);
362  }
363 }
364 
373 void
374 sbLibraryManager::NotifyListenersLibraryUnregistered(sbILibrary* aLibrary)
375 {
376  TRACE("sbLibraryManager[0x%x] - NotifyListenersLibraryUnregistered", this);
377 
378  nsCOMArray<sbILibraryManagerListener> listeners;
379  {
380  nsAutoLock lock(mLock);
381  mListeners.EnumerateRead(AddListenersToCOMArrayCallback, &listeners);
382  }
383 
384  PRInt32 count = listeners.Count();
385  for (PRInt32 index = 0; index < count; index++) {
386  nsCOMPtr<sbILibraryManagerListener> listener =
387  listeners.ObjectAt(index);
388  NS_ASSERTION(listener, "Null listener!");
389 
390  listener->OnLibraryUnregistered(aLibrary);
391  }
392 }
393 
394 void
395 sbLibraryManager::InvokeLoaders()
396 {
397  TRACE("sbLibraryManager[0x%x] - InvokeLoaders", this);
398  NS_ASSERTION(SB_IsMainThread(mThreadManager), "Wrong thread!");
399 
400  nsCOMArray<sbILibraryLoader> loaders = mLoaderCache.GetEntries();
401  PRInt32 count = loaders.Count();
402  for (PRInt32 index = 0; index < count; index++) {
403  mCurrentLoader = loaders.ObjectAt(index);
404  NS_ASSERTION(mCurrentLoader, "Null pointer!");
405 
406  nsresult SB_UNUSED_IN_RELEASE(rv) =
407  mCurrentLoader->OnRegisterStartupLibraries(this);
408  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "OnRegisterStartupLibraries failed!");
409  }
410  mCurrentLoader = nsnull;
411 }
412 
420 nsresult
421 sbLibraryManager::SetLibraryLoadsAtStartupInternal(sbILibrary* aLibrary,
422  PRBool aLoadAtStartup,
423  sbLibraryInfo** aInfo)
424 {
425  TRACE("sbLibraryManager[0x%x] - SetLibraryLoadsAtStartupInternal", this);
426 
427  nsresult rv = NS_ERROR_NOT_AVAILABLE;
428 
429  nsAutoPtr<sbLibraryInfo> libraryInfo(*aInfo ? *aInfo : new sbLibraryInfo());
430  NS_ENSURE_TRUE(libraryInfo, NS_ERROR_OUT_OF_MEMORY);
431 
432  if (!*aInfo) {
433  // First see if this library is in our hash table.
434  nsAutoString libraryGUID;
435  rv = aLibrary->GetGuid(libraryGUID);
436  NS_ENSURE_SUCCESS(rv, rv);
437 
438  nsAutoLock lock(mLock);
439 
440  sbLibraryInfo* tableLibraryInfo;
441  if (!mLibraryTable.Get(libraryGUID, &tableLibraryInfo)) {
442  NS_WARNING("Can't modify the startup of an unregistered library!");
443  return NS_ERROR_INVALID_ARG;
444  }
445 
446  // Copy these values to our new sbLibraryInfo object.
447  libraryInfo->loader = tableLibraryInfo->loader;
448  libraryInfo->library = tableLibraryInfo->library;
449  libraryInfo->loadAtStartup = tableLibraryInfo->loadAtStartup;
450  }
451 
452  if (libraryInfo->loader) {
453  rv = libraryInfo->loader->OnLibraryStartupModified(aLibrary,
454  aLoadAtStartup);
455  NS_ENSURE_SUCCESS(rv, rv);
456 
457  libraryInfo->loadAtStartup = aLoadAtStartup;
458  }
459  else {
460  // See if we can find a loader for this library.
461  PRInt32 loaderCount;
462  nsCOMArray<sbILibraryLoader> loaders;
463  {
464  nsAutoLock lock(mLock);
465  nsCOMArray<sbILibraryLoader> cachedLoaders = mLoaderCache.GetEntries();
466 
467  loaderCount = cachedLoaders.Count();
468  loaders.SetCapacity(loaderCount);
469  loaders.AppendObjects(cachedLoaders);
470  }
471 
472  NS_ENSURE_TRUE(loaderCount > 0, NS_ERROR_NOT_AVAILABLE);
473 
474  for (PRInt32 index = 0; index < loaderCount; index++) {
475  nsCOMPtr<sbILibraryLoader> cachedLoader = loaders.ObjectAt(index);
476  NS_ASSERTION(cachedLoader, "Null pointer!");
477 
478  rv = cachedLoader->OnLibraryStartupModified(aLibrary, aLoadAtStartup);
479  if (NS_SUCCEEDED(rv)) {
480  libraryInfo->loader = cachedLoader;
481  libraryInfo->loadAtStartup = aLoadAtStartup;
482  }
483  }
484  }
485 
486  if (NS_FAILED(rv)) {
487  // Fail if none of the registered loaders could accomodate the request.
488  return NS_ERROR_NOT_AVAILABLE;
489  }
490 
491  *aInfo = libraryInfo.forget();
492  return NS_OK;
493 }
494 
498 NS_IMETHODIMP
500 {
501  nsresult rv;
502  nsCOMPtr<nsIPrefBranch> prefService =
503  do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
504  NS_ENSURE_SUCCESS(rv, rv);
505 
506  nsCOMPtr<nsISupportsString> supportsString;
507  rv = prefService->GetComplexValue(SB_PREF_MAIN_LIBRARY,
508  NS_GET_IID(nsISupportsString),
509  getter_AddRefs(supportsString));
510  NS_ENSURE_SUCCESS(rv, rv);
511 
512  nsAutoString mainLibraryGUID;
513  rv = supportsString->GetData(mainLibraryGUID);
514  NS_ENSURE_SUCCESS(rv, rv);
515 
516  rv = GetLibrary(mainLibraryGUID, _retval);
517  NS_ENSURE_SUCCESS(rv, rv);
518 
519  return NS_OK;
520 }
521 
525 NS_IMETHODIMP
526 sbLibraryManager::GetDataSource(nsIRDFDataSource** aDataSource)
527 {
528  TRACE("sbLibraryManager[0x%x] - GetDataSource", this);
529  NS_ENSURE_ARG_POINTER(aDataSource);
530 
531  nsAutoLock lock(mLock);
532 
533  if (!mDataSource) {
534  nsresult rv = GenerateDataSource();
535  NS_ENSURE_SUCCESS(rv, rv);
536  }
537 
538  NS_ADDREF(*aDataSource = mDataSource);
539  return NS_OK;
540 }
541 
545 NS_IMETHODIMP
546 sbLibraryManager::GetLibrary(const nsAString& aGuid,
547  sbILibrary** _retval)
548 {
549  TRACE("sbLibraryManager[0x%x] - GetLibrary", this);
550  NS_ENSURE_ARG_POINTER(_retval);
551 
552  nsCOMPtr<sbILibrary> library;
553 
554  {
555  nsAutoLock lock(mLock);
556 
557  sbLibraryInfo* libraryInfo;
558  PRBool exists = mLibraryTable.Get(aGuid, &libraryInfo);
559  NS_ENSURE_TRUE(exists, NS_ERROR_NOT_AVAILABLE);
560 
561  NS_ASSERTION(libraryInfo->library, "Null library in hash table!");
562  library = libraryInfo->library;
563  }
564 
565  NS_ADDREF(*_retval = library);
566  return NS_OK;
567 }
568 
572 NS_IMETHODIMP
573 sbLibraryManager::GetLibraries(nsISimpleEnumerator** _retval)
574 {
575  TRACE("sbLibraryManager[0x%x] - GetLibraries", this);
576  NS_ENSURE_ARG_POINTER(_retval);
577 
578  nsCOMArray<sbILibrary> libraryArray;
579 
580  {
581  nsAutoLock lock(mLock);
582 
583  PRUint32 libraryCount = mLibraryTable.Count();
584  if (!libraryCount) {
585  return NS_NewEmptyEnumerator(_retval);
586  }
587 
588  libraryArray.SetCapacity(libraryCount);
589 
590  PRUint32 enumCount =
591  mLibraryTable.EnumerateRead(AddLibrariesToCOMArrayCallback,
592  &libraryArray);
593  NS_ENSURE_TRUE(enumCount == libraryCount, NS_ERROR_FAILURE);
594  }
595 
596  return NS_NewArrayEnumerator(_retval, libraryArray);
597 }
598 
602 NS_IMETHODIMP
603 sbLibraryManager::GetStartupLibraries(nsISimpleEnumerator** _retval)
604 {
605  TRACE("sbLibraryManager[0x%x] - GetStartupLibraries", this);
606  NS_ENSURE_ARG_POINTER(_retval);
607 
608  nsCOMArray<sbILibrary> libraryArray;
609 
610  {
611  nsAutoLock lock(mLock);
612 
613  PRUint32 libraryCount = mLibraryTable.Count();
614  if (!libraryCount) {
615  return NS_NewEmptyEnumerator(_retval);
616  }
617 
618  libraryArray.SetCapacity(libraryCount);
619 
620  PRUint32 enumCount =
621  mLibraryTable.EnumerateRead(AddStartupLibrariesToCOMArrayCallback,
622  &libraryArray);
623  NS_ENSURE_TRUE(enumCount == libraryCount, NS_ERROR_FAILURE);
624  }
625 
626  return NS_NewArrayEnumerator(_retval, libraryArray);
627 }
628 
632 NS_IMETHODIMP
633 sbLibraryManager::RegisterLibrary(sbILibrary* aLibrary,
634  PRBool aLoadAtStartup)
635 {
636  TRACE("sbLibraryManager[0x%x] - RegisterLibrary", this);
637  NS_ENSURE_ARG_POINTER(aLibrary);
638 
639  nsAutoString libraryGUID;
640  nsresult rv = aLibrary->GetGuid(libraryGUID);
641  NS_ENSURE_SUCCESS(rv, rv);
642 
643  {
644  nsAutoLock lock(mLock);
645 
646  if (mLibraryTable.Get(libraryGUID, nsnull)) {
647  NS_WARNING("Registering a library that has already been registered!");
648  return NS_OK;
649  }
650  }
651 
652  nsAutoPtr<sbLibraryInfo> newLibraryInfo(new sbLibraryInfo());
653  NS_ENSURE_TRUE(newLibraryInfo, NS_ERROR_OUT_OF_MEMORY);
654 
655  newLibraryInfo->library = aLibrary;
656  newLibraryInfo->loader = mCurrentLoader;
657 
658  if (aLoadAtStartup) {
659  if (mCurrentLoader) {
660  newLibraryInfo->loadAtStartup = PR_TRUE;
661  }
662  else {
663  sbLibraryInfo* libraryInfo = newLibraryInfo;
664  rv = SetLibraryLoadsAtStartupInternal(aLibrary, aLoadAtStartup,
665  &libraryInfo);
666  if (NS_FAILED(rv)) {
667  NS_WARNING("No loader can add this library to its startup group.");
668  newLibraryInfo->loadAtStartup = PR_FALSE;
669  }
670  }
671  }
672 
673  {
674  nsAutoLock lock(mLock);
675 
676  PRBool success = mLibraryTable.Put(libraryGUID, newLibraryInfo);
677  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
678 
679  newLibraryInfo.forget();
680  }
681 
682 
683  if (mDataSource) {
684  rv = AssertLibrary(mDataSource, aLibrary);
685  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to update dataSource!");
686  }
687 
688  // Don't notify while within InvokeLoaders.
689  if (!mCurrentLoader) {
690  NotifyListenersLibraryRegistered(aLibrary);
691  }
692 
693  return NS_OK;
694 }
695 
699 NS_IMETHODIMP
700 sbLibraryManager::UnregisterLibrary(sbILibrary* aLibrary)
701 {
702  TRACE("sbLibraryManager[0x%x] - UnregisterLibrary", this);
703  NS_ENSURE_ARG_POINTER(aLibrary);
704 
705  NS_ASSERTION(!mCurrentLoader, "Shouldn't call this within InvokeLoaders!");
706 
707  nsAutoString libraryGUID;
708  nsresult rv = aLibrary->GetGuid(libraryGUID);
709  NS_ENSURE_SUCCESS(rv, rv);
710 
711  {
712  nsAutoLock lock (mLock);
713 
714  sbLibraryInfo* libInfo;
715  if (!mLibraryTable.Get(libraryGUID, &libInfo)) {
716  NS_WARNING("Unregistering a library that was never registered!");
717  return NS_OK;
718  }
719 
720  mLibraryTable.Remove(libraryGUID);
721  }
722 
723  // Don't notify while within InvokeLoaders.
724  if (!mCurrentLoader) {
725  NotifyListenersLibraryUnregistered(aLibrary);
726  }
727 
728  if (mDataSource) {
729  rv = UnassertLibrary(mDataSource, aLibrary);
730  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to update dataSource!");
731  }
732 
733  return NS_OK;
734 }
735 
739 NS_IMETHODIMP
740 sbLibraryManager::SetLibraryLoadsAtStartup(sbILibrary* aLibrary,
741  PRBool aLoadAtStartup)
742 {
743  TRACE("sbLibraryManager[0x%x] - SetLibraryLoadsAtStartup", this);
744  NS_ENSURE_ARG_POINTER(aLibrary);
745 
746  sbLibraryInfo* outLibInfo = nsnull;
747  nsresult rv = SetLibraryLoadsAtStartupInternal(aLibrary, aLoadAtStartup,
748  &outLibInfo);
749  NS_ENSURE_SUCCESS(rv, rv);
750 
751  // Protect from leaks.
752  nsAutoPtr<sbLibraryInfo> libraryInfo(outLibInfo);
753 
754 #ifdef DEBUG
755  // Prevent anyone from using this pointer as they should use libraryInfo.
756  // It will dangle in release mode, but who cares.
757  outLibInfo = nsnull;
758 #endif
759 
760  // There's a possibility that another thread came through and unregistered
761  // the library while we were messing around above... That would suck, but we
762  // can't hang on to our lock while calling OnLibraryStartupModified. If that
763  // ever happens then we're just going to return failure and let the caller
764  // deal with it.
765 
766  nsAutoString libraryGUID;
767  rv = aLibrary->GetGuid(libraryGUID);
768  NS_ENSURE_SUCCESS(rv, rv);
769 
770  nsAutoLock lock(mLock);
771 
772  if (!mLibraryTable.Get(libraryGUID, nsnull)) {
773  NS_WARNING("Another thread unregistered the library you're trying to modify!");
774  return NS_ERROR_UNEXPECTED;
775  }
776 
777  PRBool success = mLibraryTable.Put(libraryGUID, libraryInfo);
778  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
779 
780  libraryInfo.forget();
781  return NS_OK;
782 }
783 
787 NS_IMETHODIMP
788 sbLibraryManager::GetLibraryLoadsAtStartup(sbILibrary* aLibrary,
789  PRBool* _retval)
790 {
791  TRACE("sbLibraryManager[0x%x] - GetLibraryLoadsAtStartup", this);
792  NS_ENSURE_ARG_POINTER(aLibrary);
793  NS_ENSURE_ARG_POINTER(_retval);
794 
795  nsAutoString libraryGUID;
796  nsresult rv = aLibrary->GetGuid(libraryGUID);
797  NS_ENSURE_SUCCESS(rv, rv);
798 
799  nsAutoLock lock(mLock);
800 
801  sbLibraryInfo* libraryInfo;
802  if (!mLibraryTable.Get(libraryGUID, &libraryInfo)) {
803  NS_WARNING("Can't check the startup of an unregistered library!");
804  return NS_ERROR_INVALID_ARG;
805  }
806 
807  *_retval = libraryInfo->loader && libraryInfo->loadAtStartup;
808  return NS_OK;
809 }
810 
814 NS_IMETHODIMP
815 sbLibraryManager::HasLibrary(sbILibrary* aLibrary,
816  PRBool* _retval)
817 {
818  TRACE("sbLibraryManager[0x%x] - HasLibrary", this);
819  NS_ENSURE_ARG_POINTER(aLibrary);
820  NS_ENSURE_ARG_POINTER(_retval);
821 
822  nsString libraryGUID;
823  nsresult rv = aLibrary->GetGuid(libraryGUID);
824  NS_ENSURE_SUCCESS(rv, rv);
825 
826  nsAutoLock lock(mLock);
827  *_retval = mLibraryTable.Get(libraryGUID, nsnull);
828  return NS_OK;
829 }
830 
834 NS_IMETHODIMP
835 sbLibraryManager::AddListener(sbILibraryManagerListener* aListener)
836 {
837  TRACE("sbLibraryManager[0x%x] - AddListener", this);
838  NS_ENSURE_ARG_POINTER(aListener);
839 
840  {
841  nsAutoLock lock(mLock);
842 
843  if (mListeners.Get(aListener, nsnull)) {
844  NS_WARNING("Trying to add a listener twice!");
845  return NS_OK;
846  }
847  }
848 
849  // Make a proxy for the listener that will always send callbacks to the
850  // current thread.
851  nsCOMPtr<sbILibraryManagerListener> proxy;
852  nsresult rv = do_GetProxyForObject(NS_PROXY_TO_CURRENT_THREAD,
853  NS_GET_IID(sbILibraryManagerListener),
854  aListener,
855  NS_PROXY_SYNC | NS_PROXY_ALWAYS,
856  getter_AddRefs(proxy));
857  NS_ENSURE_SUCCESS(rv, rv);
858 
859  nsAutoLock lock(mLock);
860 
861  // Add the proxy to the hash table, using the listener as the key.
862  PRBool success = mListeners.Put(aListener, proxy);
863  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
864 
865  return NS_OK;
866 }
867 
871 NS_IMETHODIMP
872 sbLibraryManager::RemoveListener(sbILibraryManagerListener* aListener)
873 {
874  TRACE("sbLibraryManager[0x%x] - RemoveListener", this);
875  NS_ENSURE_ARG_POINTER(aListener);
876 
877  nsAutoLock lock(mLock);
878 
879 #ifdef DEBUG
880  if (!mListeners.Get(aListener, nsnull)) {
881  NS_WARNING("Trying to remove a listener that was never added!");
882  }
883 #endif
884  mListeners.Remove(aListener);
885 
886  return NS_OK;
887 }
888 
892 NS_IMETHODIMP
893 sbLibraryManager::GetContentURI(nsIURI* aURI,
894  nsIURI** _retval)
895 {
896  TRACE("sbLibraryManager[0x%x] - GetContentURI", this);
897  NS_ENSURE_ARG_POINTER(aURI);
898  NS_ENSURE_ARG_POINTER(_retval);
899 
900  return sbLibraryUtils::GetContentURI(aURI, _retval);
901 }
902 
906 NS_IMETHODIMP
907 sbLibraryManager::GetFileContentURI(nsIFile* aFile,
908  nsIURI** _retval)
909 {
910  TRACE("sbLibraryManager[0x%x] - GetFileContentURI", this);
911  NS_ENSURE_ARG_POINTER(aFile);
912  NS_ENSURE_ARG_POINTER(_retval);
913 
914  return sbLibraryUtils::GetFileContentURI(aFile, _retval);
915 }
916 
920 /* nsIFile getCanonicalPath (in nsIFile aFile); */
921 NS_IMETHODIMP
922 sbLibraryManager::GetCanonicalPath(nsIFile *aFile, nsIFile **_retval)
923 {
924  nsresult rv;
925  nsCOMPtr<nsIFile> outFile;
926  NS_ENSURE_ARG_POINTER(aFile);
927  NS_ENSURE_ARG_POINTER(_retval);
928 
929  #if XP_WIN
930  nsString originalPath, canonicalizedLeafName;
931  rv = aFile->GetPath(originalPath);
932  NS_ENSURE_SUCCESS(rv, rv);
933 
934  WIN32_FIND_DATA findData = {0};
935  HANDLE findResult = ::FindFirstFileEx(originalPath.BeginReading(),
936  FindExInfoStandard,
937  &findData,
938  FindExSearchNameMatch,
939  NULL,
940  0);
941  NS_ENSURE_FALSE(findResult == INVALID_HANDLE_VALUE, NS_ERROR_FAILURE);
942  canonicalizedLeafName.Assign(findData.cFileName);
943  ::FindClose(findResult);
944  rv = aFile->Clone(getter_AddRefs(outFile));
945  NS_ENSURE_SUCCESS(rv, rv);
946  rv = outFile->SetLeafName(canonicalizedLeafName);
947  NS_ENSURE_SUCCESS(rv, rv);
948  #else
949  /* default implementation, assume case-sensitive filesystem */
950  rv = aFile->Clone(getter_AddRefs(outFile));
951  NS_ENSURE_SUCCESS(rv, rv);
952  #endif
953 
954  outFile.forget(_retval);
955  return NS_OK;
956 }
957 
961 NS_IMETHODIMP
962 sbLibraryManager::Observe(nsISupports* aSubject,
963  const char* aTopic,
964  const PRUnichar* aData)
965 {
966  TRACE("sbLibraryManager[0x%x] - Observe: %s", this, aTopic);
967 
968  nsresult rv;
969  nsCOMPtr<nsIObserverService> observerService =
970  do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
971 
972  if (strcmp(aTopic, APPSTARTUP_TOPIC) == 0) {
973  return NS_OK;
974  }
975  else if (strcmp(aTopic, NS_PROFILE_STARTUP_OBSERVER_ID) == 0) {
976  // Remove ourselves from the observer service.
977  if (NS_SUCCEEDED(rv)) {
978  observerService->RemoveObserver(this, NS_PROFILE_STARTUP_OBSERVER_ID);
979  }
980 
981  // Ask all the library loader components to register their libraries.
982  InvokeLoaders();
983 
984  // And notify any observers that we're ready to go.
985  rv = observerService->NotifyObservers(NS_ISUPPORTS_CAST(sbILibraryManager*, this),
987  nsnull);
988  NS_ENSURE_SUCCESS(rv, rv);
989 
990  return NS_OK;
991  }
992  else if (strcmp(aTopic, NS_PROFILE_TEARDOWN_OBSERVER_ID) == 0) {
993 
994  // Remove ourselves from the observer service.
995  if (NS_SUCCEEDED(rv)) {
996  observerService->RemoveObserver(this, NS_PROFILE_TEARDOWN_OBSERVER_ID);
997  }
998 
999  // Notify observers that we're about to release all libraries.
1000  rv = observerService->NotifyObservers(NS_ISUPPORTS_CAST(sbILibraryManager*, this),
1002  nsnull);
1003  NS_ENSURE_SUCCESS(rv, rv);
1004 
1005  // Notify observers to actually shut down the libraries and anything library related
1006  rv = observerService->NotifyObservers(NS_ISUPPORTS_CAST(sbILibraryManager*, this),
1008  nsnull);
1009  NS_ENSURE_SUCCESS(rv, rv);
1010 
1011  mLibraryTable.Clear();
1012 
1013  // Notify observers that we're totally shutdown.
1014  rv = observerService->NotifyObservers(NS_ISUPPORTS_CAST(sbILibraryManager*, this),
1016  nsnull);
1017  NS_ENSURE_SUCCESS(rv, rv);
1018 
1019  return NS_OK;
1020  }
1021 
1022  NS_NOTREACHED("Observing a topic that wasn't handled!");
1023  return NS_OK;
1024 }
Manages the lifecycle of libraries in the system.
#define SB_PRLOG_SETUP(x)
Definition: sbDebugUtils.h:115
return NS_OK
_updateCookies aPath
const SB_LIBRARY_MANAGER_READY_TOPIC
static nsCOMPtr< nsIObserverService > observerService
Definition: UnityProxy.cpp:6
#define SB_LIBRARY_MANAGER_SHUTDOWN_TOPIC
inArray array
const NS_PREFSERVICE_CONTRACTID
static nsresult GetFileContentURI(nsIFile *aFile, nsIURI **_retval)
Return a library content URI for the file specified by aFile. Special processing is required to conve...
Songbird Library Manager Definition.
nsresult do_GetProxyForObject(nsIEventTarget *aTarget, REFNSIID aIID, nsISupports *aObj, PRInt32 aProxyType, void **aProxyObject)
static nsresult GetContentURI(nsIURI *aURI, nsIURI **_retval, nsIIOService *aIOService=nsnull)
Return a library content URI for the URI specified by aURI. A library content URI is a specially form...
#define SB_LIBRARY_MANAGER_AFTER_SHUTDOWN_TOPIC
nsresult Init()
Register with the Observer Service.
Manages the lifecycle of libraries in the system.
#define SB_LIBRARY_LOADER_CATEGORY
PRBool SB_IsMainThread(nsIThreadManager *aThreadManager)
var count
Definition: test_bug7406.js:32
#define NS_PROFILE_TEARDOWN_OBSERVER_ID
function TRACE(s)
Songbird Thread Utilities Definitions.
Media library abstraction.
Definition: sbILibrary.idl:82
#define SB_PREF_MAIN_LIBRARY
static NS_METHOD RegisterSelf(nsIComponentManager *aCompMgr, nsIFile *aPath, const char *aLoaderStr, const char *aType, const nsModuleComponentInfo *aInfo)
nsresult GetMainLibrary(sbILibrary **aMainLibrary)
NS_IMPL_THREADSAFE_ISUPPORTS4(sbLibraryManager, nsIObserver, nsISupportsWeakReference, sbILibraryManager, sbILibraryUtils) static nsString sString
const nsISupportsString
#define NS_PROFILE_STARTUP_OBSERVER_ID
#define SONGBIRD_LIBRARYMANAGER_DESCRIPTION
Definition: sbLibraryCID.h:26
#define SONGBIRD_LIBRARYMANAGER_CONTRACTID
Definition: sbLibraryCID.h:28
Set of library utilities.
#define SB_UNUSED_IN_RELEASE(decl)
Definition: sbDebugUtils.h:55
const SB_LIBRARY_MANAGER_BEFORE_SHUTDOWN_TOPIC
_updateTextAndScrollDataForFrame aData