work on lazily-loaded string bundles - don't load a bundle until the first string is requested - reduces startup time! only in effect if STRRES_ASYNC environment variable is set

bug 76944 sr=erik, r=valeski
This commit is contained in:
alecf%netscape.com 2001-05-03 20:21:18 +00:00
Родитель d435441ef9
Коммит 80c1259818
2 изменённых файлов: 82 добавлений и 152 удалений

Просмотреть файл

@ -38,15 +38,6 @@
*/ */
#define NS_STRBUNDLE_LOADED_TOPIC (NS_LITERAL_STRING("strbundle-loaded").get()) #define NS_STRBUNDLE_LOADED_TOPIC (NS_LITERAL_STRING("strbundle-loaded").get())
/** callbacks
*
* args:
* bundle handle
* urlSpec
* closure
*/
typedef nsresult (*PR_CALLBACK nsStrBundleLoadedFunc) (void *, const char *, void *);
%} %}
native nsStrBundleLoadedFunc(nsStrBundleLoadedFunc); native nsStrBundleLoadedFunc(nsStrBundleLoadedFunc);
@ -82,10 +73,6 @@ interface nsIStringBundle : nsISupports
*/ */
attribute boolean loaded; attribute boolean loaded;
/* callback */
[noscript] void RegisterCallback(in nsStrBundleLoadedFunc callback,
in voidPtr closure);
}; };
[scriptable, uuid(D85A17C0-AA7C-11d2-9B8C-00805F8A16D9)] [scriptable, uuid(D85A17C0-AA7C-11d2-9B8C-00805F8A16D9)]

Просмотреть файл

@ -78,6 +78,7 @@ public:
nsStringBundle(); nsStringBundle();
nsresult Init(const char* aURLSpec); nsresult Init(const char* aURLSpec);
nsresult InitSyncStream(const char* aURLSpec); nsresult InitSyncStream(const char* aURLSpec);
nsresult LoadProperties();
virtual ~nsStringBundle(); virtual ~nsStringBundle();
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -91,11 +92,11 @@ protected:
// functional decomposition of the funitions repeatively called // functional decomposition of the funitions repeatively called
// //
nsresult GetStringFromID(PRInt32 aID, nsString& aResult); nsresult GetStringFromID(PRInt32 aID, nsString& aResult);
nsresult GetStringFromName(const nsString& aName, nsString& aResult); nsresult GetStringFromName(const nsAReadableString& aName, nsString& aResult);
private: private:
nsStrBundleLoadedFunc _callback; nsCString mPropertiesURL;
void *_closure; PRBool mAttemptedLoad;
PRBool mLoaded; PRBool mLoaded;
public: public:
@ -126,24 +127,13 @@ nsStringBundle::InitSyncStream(const char* aURLSpec)
rv = NS_OpenURI(getter_AddRefs(in), uri); rv = NS_OpenURI(getter_AddRefs(in), uri);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
if (!in) { NS_ASSERTION(NS_SUCCEEDED(rv) && in, "Error in OpenBlockingStream");
#ifdef NS_DEBUG NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && in, NS_ERROR_FAILURE);
if ( NS_OK == rv)
printf("OpenBlockingStream returned success value, but pointer is NULL\n");
#endif
rv = NS_ERROR_UNEXPECTED;
return rv;
}
rv = nsComponentManager::CreateInstance(kPersistentPropertiesCID, NULL, mProps = do_CreateInstance(kPersistentPropertiesCID, &rv);
NS_GET_IID(nsIPersistentProperties), NS_ENSURE_SUCCESS(rv, rv);
getter_AddRefs(mProps));
if (NS_FAILED(rv)) { mAttemptedLoad = mLoaded = PR_TRUE;
#ifdef NS_DEBUG
printf("create nsIPersistentProperties failed\n");
#endif
return rv;
}
return mProps->Load(in); return mProps->Load(in);
} }
@ -151,21 +141,35 @@ nsStringBundle::~nsStringBundle()
{ {
} }
nsStringBundle::nsStringBundle() nsStringBundle::nsStringBundle() :
mAttemptedLoad(PR_FALSE),
mLoaded(PR_FALSE)
{ {
NS_INIT_REFCNT(); NS_INIT_REFCNT();
mLoaded = PR_FALSE;
_callback = nsnull;
_closure = nsnull;
} }
nsresult nsresult
nsStringBundle::Init(const char* aURLSpec) nsStringBundle::Init(const char* aURLSpec)
{ {
#if defined(DEBUG_tao) mPropertiesURL = aURLSpec;
printf("\n-->nsStringBundle::Init: aURLSpec=%s\n", aURLSpec); return NS_OK;
#endif }
nsresult
nsStringBundle::LoadProperties()
{
// this is different than mLoaded, because we only want to attempt
// to load once
// we only want to load once, but if we've tried once and failed,
// continue to throw an error!
if (mAttemptedLoad) {
if (mLoaded)
return NS_OK;
else
return NS_ERROR_UNEXPECTED;
}
mAttemptedLoad = PR_TRUE;
// //
// use eventloop instead // use eventloop instead
@ -180,7 +184,7 @@ nsStringBundle::Init(const char* aURLSpec)
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> uri; nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), aURLSpec); rv = NS_NewURI(getter_AddRefs(uri), mPropertiesURL.get());
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
// create and loader, then wait // create and loader, then wait
@ -191,9 +195,6 @@ nsStringBundle::Init(const char* aURLSpec)
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: NS_NewStreamLoader failed...\n"); NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: NS_NewStreamLoader failed...\n");
// process events until we're finished. // process events until we're finished.
#ifdef DEBUG_tao
printf("\n-->nsStringBundle::Init: LOOP....\n\n");
#endif
PLEvent *event; PLEvent *event;
while (!mLoaded) { while (!mLoaded) {
rv = currentThreadQ->WaitForEvent(&event); rv = currentThreadQ->WaitForEvent(&event);
@ -204,28 +205,12 @@ nsStringBundle::Init(const char* aURLSpec)
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: currentThreadQ->HandleEvent failed...\n"); NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: currentThreadQ->HandleEvent failed...\n");
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
} }
#ifdef DEBUG_tao
printf("\n-->nsStringBundle::Init: out of LOOP....\n");
#endif
rv = service->PopThreadEventQueue(currentThreadQ); rv = service->PopThreadEventQueue(currentThreadQ);
return rv; return rv;
} }
/* [noscript] void RegisterCallback (in nsStrBundleLoadedFunc callback, in voidPtr closure); */
NS_IMETHODIMP
nsStringBundle::RegisterCallback(nsStrBundleLoadedFunc aCallback, void * aClosure)
{
#if defined(DEBUG_tao)
printf("\n-->nsStringBundle::RegisterCallback: aCallback=%x, closure=%x\n",
aCallback, aClosure);
#endif
_callback = aCallback;
_closure = aClosure;
return NS_OK;
}
NS_IMETHODIMP NS_IMETHODIMP
nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader, nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* context, nsISupports* context,
@ -233,13 +218,11 @@ nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
PRUint32 stringLen, PRUint32 stringLen,
const char* string) const char* string)
{ {
#if defined(DEBUG_tao)
printf("\n --> nsStringBundle::OnStreamComplete, aStatus=%d, stringLen=%ld\n", aStatus, stringLen);
#endif
// print a load error on bad status
nsXPIDLCString uriSpec; nsXPIDLCString uriSpec;
if (NS_FAILED(aStatus)) { if (NS_FAILED(aStatus)) {
// print a load error on bad status
#if defined(DEBUG)
if (aLoader) { if (aLoader) {
nsCOMPtr<nsIRequest> request; nsCOMPtr<nsIRequest> request;
aLoader->GetRequest(getter_AddRefs(request)); aLoader->GetRequest(getter_AddRefs(request));
@ -250,13 +233,12 @@ nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
channel->GetURI(getter_AddRefs(uri)); channel->GetURI(getter_AddRefs(uri));
if (uri) { if (uri) {
uri->GetSpec(getter_Copies(uriSpec)); uri->GetSpec(getter_Copies(uriSpec));
#if defined(DEBUG)
printf("\n -->nsStringBundle::OnStreamComplete: Failed to load %s\n", printf("\n -->nsStringBundle::OnStreamComplete: Failed to load %s\n",
uriSpec ? (const char *) uriSpec : ""); uriSpec ? (const char *) uriSpec : "");
#endif
} }
} }
} }
#endif
return aStatus; return aStatus;
} }
@ -268,17 +250,10 @@ nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
nsCOMPtr<nsIInputStream> in = do_QueryInterface(stringStreamSupports, &rv); nsCOMPtr<nsIInputStream> in = do_QueryInterface(stringStreamSupports, &rv);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
rv = nsComponentManager::CreateInstance(kPersistentPropertiesCID, NULL,
NS_GET_IID(nsIPersistentProperties),
getter_AddRefs(mProps));
if (NS_FAILED(rv)) {
#ifdef NS_DEBUG
printf("create nsIPersistentProperties failed\n");
#endif
return rv;
}
mProps = do_CreateInstance(kPersistentPropertiesCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// load the stream // load the stream
rv = mProps->Load(in); rv = mProps->Load(in);
@ -287,11 +262,6 @@ nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
if (NS_SUCCEEDED(rv)) { if (NS_SUCCEEDED(rv)) {
mLoaded = PR_TRUE; mLoaded = PR_TRUE;
// callback
if (_callback) {
_callback(this, uriSpec, _closure);
}
// observer notification // observer notification
nsCOMPtr<nsIObserverService> os = do_GetService(NS_OBSERVERSERVICE_CONTRACTID); nsCOMPtr<nsIObserverService> os = do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (os) if (os)
@ -307,14 +277,11 @@ nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
nsresult nsresult
nsStringBundle::GetStringFromID(PRInt32 aID, nsString& aResult) nsStringBundle::GetStringFromID(PRInt32 aID, nsString& aResult)
{ {
if (!mProps)
return NS_OK;
nsAutoCMonitor(this); nsAutoCMonitor(this);
nsAutoString name; nsAutoString name;
name.AppendInt(aID, 10); name.AppendInt(aID, 10);
nsresult ret = mProps->GetStringProperty(name, aResult); nsresult rv = mProps->GetStringProperty(name, aResult);
#ifdef DEBUG_tao_ #ifdef DEBUG_tao_
char *s = aResult.ToNewCString(); char *s = aResult.ToNewCString();
@ -323,16 +290,16 @@ nsStringBundle::GetStringFromID(PRInt32 aID, nsString& aResult)
delete s; delete s;
#endif /* DEBUG_tao_ */ #endif /* DEBUG_tao_ */
return ret; return rv;
} }
nsresult nsresult
nsStringBundle::GetStringFromName(const nsString& aName, nsString& aResult) nsStringBundle::GetStringFromName(const nsAReadableString& aName,
nsString& aResult)
{ {
if (!mProps) nsresult rv;
return NS_OK;
nsresult ret = mProps->GetStringProperty(aName, aResult); rv = mProps->GetStringProperty(nsAutoString(aName), aResult);
#ifdef DEBUG_tao_ #ifdef DEBUG_tao_
char *s = aResult.ToNewCString(), char *s = aResult.ToNewCString(),
*ss = aName.ToNewCString(); *ss = aName.ToNewCString();
@ -340,7 +307,7 @@ nsStringBundle::GetStringFromName(const nsString& aName, nsString& aResult)
ss?ss:"null", s?s:"null", aResult.Length()); ss?ss:"null", s?s:"null", aResult.Length());
delete s; delete s;
#endif /* DEBUG_tao_ */ #endif /* DEBUG_tao_ */
return ret; return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -363,8 +330,11 @@ nsStringBundle::FormatStringFromName(const PRUnichar *aName,
PRUnichar **aResult) PRUnichar **aResult)
{ {
nsresult rv; nsresult rv;
rv = LoadProperties();
if (NS_FAILED(rv)) return rv;
nsAutoString formatStr; nsAutoString formatStr;
rv = GetStringFromName(nsAutoString(aName), formatStr); rv = GetStringFromName(nsLiteralString(aName), formatStr);
if (NS_FAILED(rv)) return rv; if (NS_FAILED(rv)) return rv;
return FormatString(formatStr.GetUnicode(), aParams, aLength, aResult); return FormatString(formatStr.GetUnicode(), aParams, aLength, aResult);
@ -378,6 +348,10 @@ NS_IMPL_THREADSAFE_ISUPPORTS2(nsStringBundle,
NS_IMETHODIMP NS_IMETHODIMP
nsStringBundle::GetStringFromID(PRInt32 aID, PRUnichar **aResult) nsStringBundle::GetStringFromID(PRInt32 aID, PRUnichar **aResult)
{ {
nsresult rv;
rv = LoadProperties();
if (NS_FAILED(rv)) return rv;
*aResult = nsnull; *aResult = nsnull;
nsAutoString tmpstr; nsAutoString tmpstr;
@ -397,24 +371,25 @@ nsStringBundle::GetStringFromID(PRInt32 aID, PRUnichar **aResult)
NS_IMETHODIMP NS_IMETHODIMP
nsStringBundle::GetStringFromName(const PRUnichar *aName, PRUnichar **aResult) nsStringBundle::GetStringFromName(const PRUnichar *aName, PRUnichar **aResult)
{ {
if (!mProps) nsresult rv;
return NS_OK; rv = LoadProperties();
if (NS_FAILED(rv)) return rv;
nsAutoCMonitor(this); nsAutoCMonitor(this);
*aResult = nsnull; *aResult = nsnull;
nsAutoString tmpstr; nsAutoString tmpstr;
nsAutoString nameStr(aName); nsAutoString nameStr(aName);
nsresult ret = GetStringFromName(nameStr, tmpstr); rv = GetStringFromName(nameStr, tmpstr);
PRInt32 len = tmpstr.Length()+1; PRInt32 len = tmpstr.Length()+1;
if (NS_FAILED(ret) || !len) { if (NS_FAILED(rv) || !len) {
return ret; return rv;
} }
*aResult = (PRUnichar *) PR_Calloc(len, sizeof(PRUnichar)); *aResult = (PRUnichar *) PR_Calloc(len, sizeof(PRUnichar));
*aResult = (PRUnichar *) memcpy(*aResult, tmpstr.GetUnicode(), sizeof(PRUnichar)*len); *aResult = (PRUnichar *) memcpy(*aResult, tmpstr.GetUnicode(), sizeof(PRUnichar)*len);
(*aResult)[len-1] = '\0'; (*aResult)[len-1] = '\0';
return ret; return rv;
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -628,26 +603,21 @@ nsExtensibleStringBundle::~nsExtensibleStringBundle()
NS_IF_RELEASE(mBundle); NS_IF_RELEASE(mBundle);
} }
NS_IMETHODIMP
nsExtensibleStringBundle::RegisterCallback(nsStrBundleLoadedFunc, void *)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsExtensibleStringBundle::GetStringFromID(PRInt32 aID, PRUnichar ** aResult) nsresult nsExtensibleStringBundle::GetStringFromID(PRInt32 aID, PRUnichar ** aResult)
{ {
nsresult res = NS_OK; nsresult rv;
PRUint32 size, i; PRUint32 size, i;
res = mBundle->Count(&size); rv = mBundle->Count(&size);
if (NS_FAILED(res)) return res; if (NS_FAILED(rv)) return rv;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
nsCOMPtr<nsIStringBundle> bundle; nsCOMPtr<nsIStringBundle> bundle;
res = mBundle->QueryElementAt(i, NS_GET_IID(nsIStringBundle), getter_AddRefs(bundle)); rv = mBundle->QueryElementAt(i, NS_GET_IID(nsIStringBundle), getter_AddRefs(bundle));
if (NS_SUCCEEDED(res)) { if (NS_SUCCEEDED(rv)) {
res = bundle->GetStringFromID(aID, aResult); rv = bundle->GetStringFromID(aID, aResult);
if (NS_SUCCEEDED(res)) if (NS_SUCCEEDED(rv))
return NS_OK; return NS_OK;
} }
} }
@ -862,7 +832,6 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
bundleCacheEntry_t* cacheEntry = bundleCacheEntry_t* cacheEntry =
(bundleCacheEntry_t*)mBundleMap.Get(&completeKey); (bundleCacheEntry_t*)mBundleMap.Get(&completeKey);
PRBool addref = PR_FALSE;
if (cacheEntry) { if (cacheEntry) {
// cache hit! // cache hit!
// remove it from the list, it will later be reinserted // remove it from the list, it will later be reinserted
@ -873,24 +842,23 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
// hasn't been cached, so insert it into the hash table // hasn't been cached, so insert it into the hash table
nsStringBundle* bundle = new nsStringBundle(); nsStringBundle* bundle = new nsStringBundle();
if (async) { if (!bundle) return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(bundle); NS_ADDREF(bundle);
addref = PR_TRUE;
if (async)
ret = bundle->Init(aURLSpec); ret = bundle->Init(aURLSpec);
} else
else {
ret = bundle->InitSyncStream(aURLSpec); ret = bundle->InitSyncStream(aURLSpec);
}
if (NS_FAILED(ret)) { if (NS_FAILED(ret)) {
delete bundle; NS_RELEASE(bundle);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
if (!bundle) {
return NS_ERROR_OUT_OF_MEMORY;
}
cacheEntry = insertIntoCache(bundle, &completeKey); cacheEntry = insertIntoCache(bundle, &completeKey);
NS_RELEASE(bundle); // cache should now be holding a ref
// in the cacheEntry
} }
// at this point the cacheEntry should exist in the hashtable, // at this point the cacheEntry should exist in the hashtable,
@ -901,7 +869,6 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
// finally, return the value // finally, return the value
*aResult = cacheEntry->mBundle; *aResult = cacheEntry->mBundle;
if (!addref)
NS_ADDREF(*aResult); NS_ADDREF(*aResult);
return NS_OK; return NS_OK;
@ -956,7 +923,8 @@ nsStringBundleService::recycleEntry(bundleCacheEntry_t *aEntry)
} }
NS_IMETHODIMP NS_IMETHODIMP
nsStringBundleService::CreateBundle(const char* aURLSpec, nsIStringBundle** aResult) nsStringBundleService::CreateBundle(const char* aURLSpec,
nsIStringBundle** aResult)
{ {
#ifdef DEBUG_tao_ #ifdef DEBUG_tao_
printf("\n++ nsStringBundleService::CreateBundle ++\n"); printf("\n++ nsStringBundleService::CreateBundle ++\n");
@ -1114,31 +1082,6 @@ done:
return rv; return rv;
} }
NS_IMETHODIMP
NS_NewStringBundleService(nsISupports* aOuter, const nsIID& aIID,
void** aResult)
{
nsresult rv;
if (!aResult) {
return NS_ERROR_INVALID_POINTER;
}
if (aOuter) {
*aResult = nsnull;
return NS_ERROR_NO_AGGREGATION;
}
nsStringBundleService * inst = new nsStringBundleService();
if (inst == NULL) {
*aResult = nsnull;
return NS_ERROR_OUT_OF_MEMORY;
}
rv = inst->QueryInterface(aIID, aResult);
if (NS_FAILED(rv)) {
delete inst;
*aResult = nsnull;
}
return rv;
}
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStringBundleService, Init) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsStringBundleService, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAcceptLang) NS_GENERIC_FACTORY_CONSTRUCTOR(nsAcceptLang)