26291: StringBundle should not call OpenInputStream(). (r,sr)=(alecf,erik).

Add new api , CreateAsyncBundle() to load stream asynchronously. setenv
STRRES_ASYNC to flip CreateBundle() to CreateAsyncBundle().
This commit is contained in:
tao%netscape.com 2001-01-12 03:02:22 +00:00
Родитель bce469e2f2
Коммит b1a210d7da
2 изменённых файлов: 292 добавлений и 83 удалений

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

@ -35,8 +35,25 @@
{ 0x9b, 0x8c, 0x0, 0x80, 0x5f, 0x8a, 0x16, 0xd9 } }
#define NS_STRINGBUNDLE_CONTRACTID "@mozilla.org/intl/stringbundle;1"
/**
* observer needs to check if the bundle handle matches
*/
#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);
[scriptable, uuid(D85A17C2-AA7C-11d2-9B8C-00805F8A16D9)]
interface nsIStringBundle : nsISupports
{
@ -63,6 +80,15 @@ interface nsIStringBundle : nsISupports
Implements nsISimpleEnumerator, replaces nsIEnumerator
*/
nsISimpleEnumerator getSimpleEnumeration();
/* stream loaded
*/
attribute boolean loaded;
/* callback */
[noscript] void RegisterCallback(in nsStrBundleLoadedFunc callback,
in voidPtr closure);
};
[scriptable, uuid(D85A17C0-AA7C-11d2-9B8C-00805F8A16D9)]
@ -70,6 +96,7 @@ interface nsIStringBundleService : nsISupports
{
nsIStringBundle CreateBundle([const] in string aURLSpec,
in nsILocale aLocale);
nsIStringBundle CreateAsyncBundle([const] in string aURLSpec);
nsIStringBundle CreateExtensibleBundle([const] in string aRegistryKey,
in nsILocale aLocale);
@ -91,6 +118,7 @@ interface nsIStringBundleService : nsISupports
* at some point, we might want to make this flush all the bundles,
* because any bundles that are floating around when the locale changes
* will suddenly contain bad data
*
*/
void flushBundles();
};

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

@ -56,23 +56,37 @@
#include "nsAcceptLang.h" // for nsIAcceptLang
// for async loading
#include "nsIBinaryInputStream.h"
#include "nsIStringStream.h"
// eventQ
#include "nsIEventQueueService.h"
#include "prenv.h"
static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
static NS_DEFINE_CID(kStandardUrlCID, NS_STANDARDURL_CID);
static NS_DEFINE_CID(kErrorServiceCID, NS_ERRORSERVICE_CID);
// XXX investigate need for proper locking in this module
//static PRInt32 gLockCount = 0;
NS_DEFINE_IID(kStringBundleServiceCID, NS_STRINGBUNDLESERVICE_CID);
class nsStringBundle : public nsIStringBundle
class nsStringBundle : public nsIStringBundle,
public nsIStreamLoaderObserver
{
public:
nsStringBundle(const char* aURLSpec, nsILocale* aLocale, nsresult* aResult);
// init version
nsStringBundle();
nsresult Init(const char* aURLSpec);
nsresult InitSyncStream(const char* aURLSpec);
virtual ~nsStringBundle();
NS_DECL_ISUPPORTS
NS_DECL_NSISTRINGBUNDLE
NS_DECL_NSISTREAMLOADEROBSERVER
nsIPersistentProperties* mProps;
@ -85,6 +99,12 @@ protected:
nsresult GetInputStream(const char* aURLSpec, nsILocale* aLocale, nsIInputStream*& in);
nsresult OpenInputStream(nsString& aURLStr, nsIInputStream*& in);
private:
nsStrBundleLoadedFunc _callback;
void *_closure;
PRBool mLoaded;
public:
static nsresult GetLangCountry(nsILocale* aLocale, nsString& lang, nsString& country);
@ -93,33 +113,35 @@ public:
PRUnichar **aResult);
};
nsStringBundle::nsStringBundle(const char* aURLSpec, nsILocale* aLocale, nsresult* aResult)
{ NS_INIT_REFCNT();
mProps = nsnull;
nsresult
nsStringBundle::InitSyncStream(const char* aURLSpec)
{
nsIInputStream *in = nsnull;
*aResult = GetInputStream(aURLSpec,aLocale, in);
nsresult rv = GetInputStream(aURLSpec, nsnull, in);
if (!in) {
#ifdef NS_DEBUG
if ( NS_OK == *aResult)
if ( NS_OK == rv)
printf("OpenBlockingStream returned success value, but pointer is NULL\n");
#endif
*aResult = NS_ERROR_UNEXPECTED;
return;
rv = NS_ERROR_UNEXPECTED;
return rv;
}
*aResult = nsComponentManager::CreateInstance(kPersistentPropertiesCID, NULL,
NS_GET_IID(nsIPersistentProperties), (void**) &mProps);
if (NS_FAILED(*aResult)) {
rv = nsComponentManager::CreateInstance(kPersistentPropertiesCID, NULL,
NS_GET_IID(nsIPersistentProperties),
(void**) &mProps);
if (NS_FAILED(rv)) {
#ifdef NS_DEBUG
printf("create nsIPersistentProperties failed\n");
#endif
return;
return rv;
}
*aResult = mProps->Load(in);
rv = mProps->Load(in);
NS_RELEASE(in);
return rv;
}
nsStringBundle::~nsStringBundle()
@ -127,12 +149,168 @@ nsStringBundle::~nsStringBundle()
NS_IF_RELEASE(mProps);
}
nsStringBundle::nsStringBundle()
{
NS_INIT_REFCNT();
mProps = nsnull;
mLoaded = PR_FALSE;
_callback = nsnull;
_closure = nsnull;
}
nsresult
nsStringBundle::Init(const char* aURLSpec)
{
#if defined(DEBUG_tao)
printf("\n-->nsStringBundle::Init: aURLSpec=%s\n", aURLSpec);
#endif
//
// use eventloop instead
//
// create an event queue for this thread.
nsresult rv;
nsCOMPtr<nsIEventQueueService> service = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIEventQueue> currentThreadQ;
rv = service->PushThreadEventQueue(getter_AddRefs(currentThreadQ));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), aURLSpec);
if (NS_FAILED(rv)) return rv;
// create and loader, then wait
nsCOMPtr<nsIStreamLoader> loader;
rv = NS_NewStreamLoader(getter_AddRefs(loader),
uri,
this /*the load observer*/);
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: NS_NewStreamLoader failed...\n");
// process events until we're finished.
#ifdef DEBUG_tao
printf("\n-->nsStringBundle::Init: LOOP....\n\n");
#endif
PLEvent *event;
while (!mLoaded) {
rv = currentThreadQ->WaitForEvent(&event);
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: currentThreadQ->WaitForEvent failed...\n");
if (NS_FAILED(rv)) return rv;
rv = currentThreadQ->HandleEvent(event);
NS_ASSERTION(NS_SUCCEEDED(rv), "\n-->nsStringBundle::Init: currentThreadQ->HandleEvent failed...\n");
if (NS_FAILED(rv)) return rv;
}
#ifdef DEBUG_tao
printf("\n-->nsStringBundle::Init: out of LOOP....\n");
#endif
rv = service->PopThreadEventQueue(currentThreadQ);
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
nsStringBundle::OnStreamComplete(nsIStreamLoader* aLoader,
nsISupports* context,
nsresult aStatus,
PRUint32 stringLen,
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;
if (NS_FAILED(aStatus)) {
if (aLoader) {
nsCOMPtr<nsIChannel> channel;
aLoader->GetChannel(getter_AddRefs(channel));
if (channel) {
nsCOMPtr<nsIURI> uri;
channel->GetURI(getter_AddRefs(uri));
if (uri) {
uri->GetSpec(getter_Copies(uriSpec));
#if defined(DEBUG)
printf("\n -->nsStringBundle::OnStreamComplete: Failed to load %s\n",
uriSpec ? (const char *) uriSpec : "");
#endif
}
}
}
return aStatus;
}
nsresult rv;
nsCOMPtr<nsISupports> stringStreamSupports;
rv = NS_NewByteInputStream(getter_AddRefs(stringStreamSupports),
string, stringLen);
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsIInputStream> in = do_QueryInterface(stringStreamSupports);
nsCOMPtr<nsIBinaryInputStream> binaryStream;
rv = NS_NewBinaryInputStream(getter_AddRefs(binaryStream), in);
if (NS_FAILED(rv)) return rv;
aStatus = nsComponentManager::CreateInstance(kPersistentPropertiesCID, NULL,
NS_GET_IID(nsIPersistentProperties),
(void**) &mProps);
if (NS_FAILED(aStatus)) {
#ifdef NS_DEBUG
printf("create nsIPersistentProperties failed\n");
#endif
return aStatus;
}
// load the stream
aStatus = mProps->Load(in);
//
// notify
if (NS_SUCCEEDED(aStatus)) {
mLoaded = PR_TRUE;
// callback
if (_callback) {
_callback(this, uriSpec, _closure);
}
// observer notification
nsCOMPtr<nsIObserverService> os = do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
if (os)
os->Notify((nsIStringBundle *) this,
NS_STRBUNDLE_LOADED_TOPIC, nsnull);
#if defined(DEBUG_tao)
printf("\n --> nsStringBundle::OnStreamComplete: end sending NOTIFICATIONS!!\n");
#endif
}
return aStatus;
}
nsresult
nsStringBundle::GetStringFromID(PRInt32 aID, nsString& aResult)
{
if (!mProps)
return NS_OK;
NS_ENSURE_TRUE(mProps, NS_ERROR_UNEXPECTED);
nsAutoCMonitor(this);
nsAutoString name;
name.AppendInt(aID, 10);
@ -153,6 +331,7 @@ nsStringBundle::GetStringFromName(const nsString& aName, nsString& aResult)
{
if (!mProps)
return NS_OK;
NS_ENSURE_TRUE(mProps, NS_ERROR_FAILURE);
nsresult ret = mProps->GetStringProperty(aName, aResult);
#ifdef DEBUG_tao_
@ -193,7 +372,8 @@ nsStringBundle::FormatStringFromName(const PRUnichar *aName,
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsStringBundle, nsIStringBundle)
NS_IMPL_THREADSAFE_ISUPPORTS2(nsStringBundle,
nsIStringBundle, nsIStreamLoaderObserver)
/* void GetStringFromID (in long aID, out wstring aResult); */
NS_IMETHODIMP
@ -218,6 +398,9 @@ nsStringBundle::GetStringFromID(PRInt32 aID, PRUnichar **aResult)
NS_IMETHODIMP
nsStringBundle::GetStringFromName(const PRUnichar *aName, PRUnichar **aResult)
{
if (!mProps)
return NS_OK;
nsAutoCMonitor(this);
*aResult = nsnull;
nsAutoString tmpstr;
@ -238,6 +421,9 @@ nsStringBundle::GetStringFromName(const PRUnichar *aName, PRUnichar **aResult)
NS_IMETHODIMP
nsStringBundle::GetEnumeration(nsIBidirectionalEnumerator** elements)
{
if (!mProps)
return NS_OK;
nsAutoCMonitor(this);
if (!elements)
return NS_ERROR_INVALID_POINTER;
@ -258,6 +444,18 @@ nsStringBundle::GetSimpleEnumeration(nsISimpleEnumerator** elements)
return ret;
}
/* attribute boolean loaded; */
NS_IMETHODIMP nsStringBundle::GetLoaded(PRBool *aLoaded)
{
*aLoaded = mLoaded;
return NS_OK;
}
NS_IMETHODIMP nsStringBundle::SetLoaded(PRBool aLoaded)
{
mLoaded = aLoaded;
return NS_OK;
}
nsresult
nsStringBundle::GetInputStream(const char* aURLSpec, nsILocale* aLocale, nsIInputStream*& in)
@ -269,65 +467,10 @@ nsStringBundle::GetInputStream(const char* aURLSpec, nsILocale* aLocale, nsIInpu
/* locale binding */
nsAutoString strFile2;
#if 1
/* plan A: don't fallback; use aURLSpec: xxx.pro -> xxx.pro
*/
strFile2.AssignWithConversion(aURLSpec);
ret = OpenInputStream(strFile2, in);
#else
nsAutoString lc_lang;
nsAutoString lc_country;
if (NS_OK == (ret = GetLangCountry(aLocale, lc_lang, lc_country))) {
/* find the place to concatenate locale name
*/
PRInt32 count = 0;
nsAutoString strFile(aURLSpec);
PRInt32 mylen = strFile.Length();
nsAutoString fileLeft;
/* assume the name always ends with this
*/
PRInt32 dot = strFile.RFindChar('.');
count = strFile.Left(fileLeft, (dot>0)?dot:mylen);
strFile2 += fileLeft;
/* insert lang-country code
*/
strFile2 += "_";
strFile2 += lc_lang;
if (lc_country.Length() > 0) {
strFile2 += "_";
strFile2 += lc_country;;
}
/* insert it
*/
nsAutoString fileRight;
if (dot > 0) {
count = strFile.Right(fileRight, mylen-dot);
strFile2 += fileRight;
}
ret = OpenInputStream(strFile2, in);
if ((NS_FAILED(ret) || !in) && lc_country.Length() && lc_lang.Length()) {
/* plan A: fallback to lang only
*/
strFile2 = fileLeft;
strFile2 += "_";
strFile2 += lc_lang;
strFile2 += fileRight;
ret = OpenInputStream(strFile2, in);
}/* plan A */
}/* locale */
if (NS_FAILED(ret) || !in) {
/* plan B: fallback to aURLSpec
*/
strFile2 = aURLSpec;
ret = OpenInputStream(strFile2, in);
}
#endif
return ret;
}
@ -424,6 +567,7 @@ class nsExtensibleStringBundle : public nsIStringBundle
private:
nsISupportsArray * mBundle;
PRBool mLoaded;
public:
@ -445,6 +589,8 @@ nsExtensibleStringBundle::nsExtensibleStringBundle(const char * aRegistryKey,
{
NS_INIT_REFCNT();
mLoaded = PR_FALSE;
nsresult res = NS_OK;
nsIEnumerator * components = NULL;
nsIRegistry * registry = NULL;
@ -502,7 +648,7 @@ nsExtensibleStringBundle::nsExtensibleStringBundle(const char * aRegistryKey,
res = registry->GetStringUTF8(key, "name", &name);
if (NS_FAILED(res)) goto done1;
res = sbServ->CreateBundle(name, aLocale, &bundle);
res = sbServ->CreateBundle(name, nsnull, &bundle);
if (NS_FAILED(res)) goto done1;
res = mBundle->AppendElement(bundle);
@ -539,6 +685,12 @@ nsExtensibleStringBundle::~nsExtensibleStringBundle()
NS_IF_RELEASE(mBundle);
}
NS_IMETHODIMP
nsExtensibleStringBundle::RegisterCallback(nsStrBundleLoadedFunc, void *)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult nsExtensibleStringBundle::GetStringFromID(PRInt32 aID, PRUnichar ** aResult)
{
nsresult res = NS_OK;
@ -619,6 +771,19 @@ nsresult nsExtensibleStringBundle::GetSimpleEnumeration(nsISimpleEnumerator ** a
return NS_ERROR_NOT_IMPLEMENTED;
}
/* attribute boolean loaded; */
NS_IMETHODIMP nsExtensibleStringBundle::GetLoaded(PRBool *aLoaded)
{
*aLoaded = mLoaded;
return NS_OK;
}
NS_IMETHODIMP nsExtensibleStringBundle::SetLoaded(PRBool aLoaded)
{
mLoaded = aLoaded;
return NS_OK;
}
/////////////////////////////////////////////////////////////////////////////////////////
#define MAX_CACHED_BUNDLES 10
@ -645,8 +810,7 @@ public:
NS_DECL_NSIOBSERVER
private:
nsresult getStringBundle(const char *aUrl, nsILocale* aLocale,
nsIStringBundle** aResult);
nsresult getStringBundle(const char *aUrl, PRBool async, nsIStringBundle** aResult);
nsresult FormatWithBundle(nsIStringBundle* bundle, nsresult aStatus,
PRUint32 argCount, PRUnichar** argArray,
PRUnichar* *result);
@ -665,6 +829,8 @@ private:
// reuse the same uri structure over and over
nsCOMPtr<nsIURI> mScratchUri;
nsCOMPtr<nsIErrorService> mErrorService;
const char *mAsync; // temporary; remove after we settle w/ sync/async
};
nsStringBundleService::nsStringBundleService() :
@ -684,6 +850,8 @@ nsStringBundleService::nsStringBundleService() :
NS_ASSERTION(mScratchUri, "Couldn't create scratch URI");
mErrorService = do_GetService(kErrorServiceCID);
NS_ASSERTION(mErrorService, "Couldn't get error service");
mAsync = PR_GetEnv("STRRES_ASYNC");
}
NS_IMPL_THREADSAFE_ISUPPORTS3(nsStringBundleService,
@ -746,18 +914,16 @@ nsStringBundleService::FlushBundles()
nsresult
nsStringBundleService::getStringBundle(const char *aURLSpec,
nsILocale* aLocale,
PRBool async,
nsIStringBundle **aResult)
{
nsresult ret;
nsXPIDLCString newSpec;
nsCStringKey completeKey(aURLSpec);
bundleCacheEntry_t* cacheEntry =
(bundleCacheEntry_t*)mBundleMap.Get(&completeKey);
PRBool addref = PR_FALSE;
if (cacheEntry) {
// cache hit!
// remove it from the list, it will later be reinserted
@ -767,7 +933,16 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
} else {
// hasn't been cached, so insert it into the hash table
nsStringBundle* bundle = new nsStringBundle(aURLSpec, nsnull, &ret);
nsStringBundle* bundle = new nsStringBundle();
if (async) {
NS_ADDREF(bundle);
addref = PR_TRUE;
ret = bundle->Init(aURLSpec);
}
else {
ret = bundle->InitSyncStream(aURLSpec);
}
if (NS_FAILED(ret)) {
delete bundle;
return NS_ERROR_FAILURE;
@ -787,6 +962,7 @@ nsStringBundleService::getStringBundle(const char *aURLSpec,
// finally, return the value
*aResult = cacheEntry->mBundle;
if (!addref)
NS_ADDREF(*aResult);
return NS_OK;
@ -854,8 +1030,13 @@ nsStringBundleService::CreateBundle(const char* aURLSpec, nsILocale* aLocale,
}
#endif
return getStringBundle(aURLSpec, mAsync?PR_TRUE:PR_FALSE, aResult);
}
return getStringBundle(aURLSpec, aLocale, aResult);
NS_IMETHODIMP
nsStringBundleService::CreateAsyncBundle(const char* aURLSpec, nsIStringBundle** aResult)
{
return getStringBundle(aURLSpec, PR_TRUE, aResult);
}
NS_IMETHODIMP
@ -973,13 +1154,13 @@ nsStringBundleService::FormatStatusMessage(nsresult aStatus,
rv = mErrorService->GetErrorStringBundle(NS_ERROR_GET_MODULE(aStatus),
getter_Copies(stringBundleURL));
if (NS_SUCCEEDED(rv)) {
rv = getStringBundle(stringBundleURL, nsnull, getter_AddRefs(bundle));
rv = getStringBundle(stringBundleURL, mAsync?PR_TRUE:PR_FALSE, getter_AddRefs(bundle));
if (NS_SUCCEEDED(rv)) {
rv = FormatWithBundle(bundle, aStatus, argCount, argArray, result);
}
}
if (NS_FAILED(rv)) {
rv = getStringBundle(GLOBAL_PROPERTIES, nsnull, getter_AddRefs(bundle));
rv = getStringBundle(GLOBAL_PROPERTIES, mAsync?PR_TRUE:PR_FALSE, getter_AddRefs(bundle));
if (NS_SUCCEEDED(rv)) {
rv = FormatWithBundle(bundle, aStatus, argCount, argArray, result);
}