The New Cache System
This is a quick overview of how the new cache system works, and which messages (along with which parameters) it requires.
The new cache system handles both RAM and disk cache files, and does not allow direct access to the pointers of the file handlers. This is to make sure that no part of the application can do anything sneaky, such as writing to a cache file while some other part is also trying to write to it.
So, without further ado, here it is.
The best way to access the cache system is to use the pointer to the plug-in manager "PlugMan" in your add-on's PlugClass child class. Be sure to include the header file "plugman.h" in your source or header file so that you can properly reference this object without getting an error. You will also need to include "cacheplug.h" in your source or header, and add a CachePlug pointer somewhere. (Preferably in your class declaration so that it's available throughout your class.) For example:
#include "plugclass.h"
#include "plugman.h"
#include "cacheplug.h"
class MyPlugin: public PlugClass { public: MyPlugin(BMessage *info=NULL); ~MyPlugin(); CachePlug *CacheSystem;//pointer to the cache plug-in object. uint32 CacheUserToken; status_t ReceiveBroadcast(BMessage *msg); ... };
In your class constructor as well as in ReceiveBroadcast() you will want to try to find the cache object. Because it is nearly impossible to tell whether the cache plug-in will load before or after your plug-in, you need to cover your bases. Whenever the plug-in manager loads a plug-in, it sends a broadcast to all plug-ins notifying them of the plug-in most recently loaded; so we can utilize that feature if the cache plug-in is not already loaded when your plug-in is loaded.
In your constructor, you will want to see if the cache plug-in has been loaded and if so, initialize your pointer to the appropriate address:
MyPlugin::MyPlugin(BMessage *info):PlugClass(info){ CacheSys=(CachePlug*)PlugMan->FindPlugin(CachePlugin); CacheUserToken=0; ... }
If CacheSys is still NULL after your constructor completes, then you can safely assume that the cache plug-in has not yet been loaded. Note that you must include commondefs.h in order to use the "CachePlugin" value for FindPlugin. Otherwise you may simply use 'cash'.
In your ReceiveBroadcast function, you will want to have similar behavior. When your plug-in receives a COMMAND_INFO broadcast with PlugInLoaded as the "what" value of the BMessage, you will want to check the newly loaded plug-in's Type to see if it matches the cache system's type:
status_t MyPlugin::ReceiveBroadcast(BMessage *msg) { uint32 command=0; command=msg->FindInt32("command"); switch(command) { case COMMAND_INFO: { switch(msg->what) { case PlugInLoaded: { PlugClass *pobj=NULL; msg->FindPointer("plugin",(void**)&pobj); if (pobj!=NULL) { if ((pobj->Type()&TARGET_CACHE)!=0) { CacheSys=(CachePlug*)pobj; } } }break; case PlugInUnloaded: { uint32 type=0; type=msg->FindInt32("type"); if ((type&TARGET_CACHE)!=0) { CacheSys=NULL; } }break; case B_QUIT_REQUESTED: { ... }break; } }break; ... } }
As illustrated above, you may easily set and unset the pointer to the cache system, or update any variable necessary, so that you may properly access (or refrain from accessing) the cache in your plug-in.
While it is possible to use the Themis broadcast system to access the cache, it is best accessed via pointer, as the broadcast system method requires that the cache user is also a plug-in. In addition, the broadcast system method requires the use of the BroadcastReply function in your plug-in. As in the http protocol plug-in, you may have to use semaphores or some other method to make sure that a response from the cache system is received if the cache system is loaded, and that it can handle a situation where no response is forthcoming if the cache system isn't loaded. This can be a major headache, so it's best to just use the pointer method. In addition, virtually none of the cache system's functionality is available [yet] via the Themis broadcast system.
Once you have a valid pointer to the cache system, you will want to make a call to the Register function. If you do not register your plug-in, you will not be able to use much of the cache's functionality. The register function takes two parameters, though the second is optional. The first parameter should be your plug-in's type or target value as given to the broadcast system. This will be used so that you may receive updates of various sorts with regards to any URL's your plug-in might be interested in. The second parameter is a text description of your choice. At this point, it is not utilized at all, so it is completely optional. In the future, this description may be used for logging purposes if enabled.
Continuing on our example above, you might register like this:
...
CacheUserToken=CacheSys->Register(Type(),"My Plug-in");
...
Be sure to keep the return value from the registration call. This value, called the cache user token, is used to manipulate the cache objects. It is used when reading and writing data and attributes to the cache object, as well as for simply finding a cached URL.
The cache system handles two types of cache files: disk and RAM(memory). While it is most likely that disk cache files will be used, it sometimes happens that a memory cache file is used instead. For the most part, the type of cache file being handled is completely transparent to the user of the cache. (And the cache system itself for that matter.) The only control you as a user of the cache system have over whether the file to be cached is a memory or disk file, is when creating a cache object. Cache objects are created with the CreateObject function call as follows:
For a memory cache object:
CacheSys->CreateObject( CacheUserToken, "http://www.themisbrowser.org/", TYPE_RAM);
For a disk cache object:
CacheSys->CreateObject(CacheUserToken, "http://www.themisbrowser.org/", TYPE_DISK);
or
CacheSys->CreateObject(CacheUserToken, "http://www.themisbrowser.org/");
Notice that by default, disk cache files are created. Although it isn't illustrated in the example above, you will need to keep track of the int32 value returned by the function. This value is the cache object token (or simply object token). Also be aware that when you create a cache object, you are by default the "write lock owner." In order to write to any cache object, you must first acquire the write lock with the AcquireWriteLock call, which takes your cache user token and the object token as parameters. If you obtained the cache object token by searching for an URL, then you will need to acquire the write lock before you try to write to the file. The AcquireWriteLock function returns true if successfully acquired and false if not.
The FindObject function is called relatively simply, and returns either B_ENTRY_NOT_FOUND or an int32 value for the cache object. The function call works as follows:
int32 cacheobject=CacheSys->FindObject(CacheUserToken,"http://themis.sourceforge.net/");
Again, if you will be using the cache object for more than a moment, you'll probably want to cache the value, and/or associate it with the URL you're dealing with.
The remaining functions that you will most likely utilize are as follows:
BMessage *GetInfo(uint32 usertoken, int32 objecttoken);
ssize_t Write(uint32 usertoken, int32 objecttoken, void *data, size_t size);
ssize_t Read(uint32 usertoken, int32 objecttoken, void *data, size_t size);
ssize_t GetObjectSize(uint32 usertoken, int32 objecttoken);
void ReleaseWriteLock(uint32 usertoken, int32 objecttoken);
Most of these should be fairly obvious. The ReleaseWriteLock function release the write lock, so that some other part of the application may write to the cache file. GetInfo returns a BMessage with any and all attribute information that has been set on the cache object.
GetObjectSize, Write, and Read all do as their names imply.
As for the messages the cache system handles currently:
Command | "what" Value | Field and type | Purpose |
COMMAND_STORE | CreateCacheObject | int32 cache_type | TYPE_DISK or TYPE_RAM to determine whether the file is stored in RAM or on DISK. |
char* url | The url to be stored. | ||
uint32 cache_user_token | Your plug-in's cache user token. | ||
PlugClass* ReplyToPointer | Pointer to your plug-in's PlugClass derived object. | ||
COMMAND_INFO_REQUEST | FindCachedObject | cache_user_token | Your plug-in's cache user token. |
char* url | The url being requested. |
The messages it responds with are:
Command | "what" Value | Field and type | Purpose |
COMMAND_INFO | CachedObject | int32 cache_object_token | The object token of the URL requested. |
COMMAND_INFO | CacheObjectNotFound | The file wasn't found. | |