Where to Put The OSP CodeCache Directory

One of the questions that comes up frequently when installing an OSP-based application on an end-user system is where to put the OSP codeCache. The codeCache is a directory where the OSP framework puts all shared libraries contained in bundles, so that the operating system can find and load them. The OSP framework itself does not care where the codeCache is located, so you’re basically free to put it wherever you’d like. Of course, there are system-specific conventions and restrictions where such things like the codeCache should or can be stored. Also, the location will be different whether your application is a server application that runs in the background, or an interactive desktop application.

For example, on Windows, the codeCache should go into the AppData\Local\ directory within the user’s home directory for a desktop application. If the application runs as a Windows service, another directory might be more appropriate — in this case it might be possible to put the codeCache into the Program Files folder. On a Linux system, for an interactive application, the codeCache should go into a hidden application-specific directory within the user’s home directory, whereas on Mac OS X, ~/Library/Application Support/ is the right place. For a Unix server application (daemon), /var/cache/ is a good choice.

To make configuring the codeCache location in the application’s configuration file easier, it is a good idea to define a configuration property in your application that makes the path to the directory containing the codeCache available.

Following is some sample code that determines an appropriate directory for holding the codeCache on Windows, Mac OS X and other Unix platforms, for desktop applications.

std::string findApplicationDataDir(
    const std::string& vendorName,
    const std::string& applicationName)

{
#if POCO_OS == POCO_OS_WINDOWS_NT
    wchar_t wpath[MAX_PATH];
    HRESULT rc = SHGetFolderPathW(
        NULL,
        CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE,
        NULL, SHGFP_TYPE_CURRENT,
        wpath);
    if (SUCCEEDED(rc))
    {
        std::string localAppData;
        Poco::UnicodeConverter::toUTF8(wpath, localAppData);
        Poco::Path path(localAppData);
        path.makeDirectory();
        path.pushDirectory(vendorName);
        path.pushDirectory(applicationName);
        return path.toString();
    }
    else return config().getString("application.dir");

#elif POCO_OS == POCO_OS_MAC_OS_X
    Poco::Path path(Poco::Path::home());
    path.pushDirectory("Library");
    path.pushDirectory("Application Support");
    path.pushDirectory(vendorName);
    path.pushDirectory(applicationName);
    return path.toString();

#else
    Poco::Path path(Poco::Path::home());
    path.pushDirectory("." + vendorName);
    path.pushDirectory(applicationName);
    return path.toString();
#endif
}

Note that the SHGetFolderPath API function has been deprecated as of Windows Vista, superseded by SHGetKnownFolderPath. However, the latter one is not available on XP, so if you still have to support XP deployments, you've got to use the deprecated SHGetFolderPath function (which now is just a wrapper for SHGetKnownFolderPath).

For the above code to work on Windows, you’ll need to #include <shlobj.h>, as well as #include "Poco/UnicodeConverter.h" and link with shell32.lib.

If you change the BundleServer’s initialize() function to look like below, then you can refer to that directory in your application configuration file.

void initialize(Application& self)
{
    std::string appDataDir(findApplicationDataDir(
        "MyCompany", "MyApplication"));
    config().setString("application.dataDir", appDataDir);
    loadConfiguration();
    Application::initialize(self);
}

This code determines the data directory and stores the path in the application.dataDir configuration property. In the application properties file, you can now specify:

osp.codeCache = ${application.dataDir}codeCache

Note that for a server application, in most cases no extra code is needed to determine the directory — all can be done in the configuration file. For example, on Windows, use the application's installation directory:

osp.codeCache = ${application.dir}codeCache

On UNIX platforms, use /var/cache:

osp.codeCache = /var/cache

And as a final note, on some Unix platforms, depending on the configuration of the dynamic linker, it may be necessary to set up the shared library search path (LD_LIBRARY_PATH) so that it includes the codeCache directory. Otherwise the OSP application will not be able to load the shared libraries from the codeCache. This can be done in the application's startup script.

Tagged