/* 
 * $Id: XDTPModuleLoader.cpp,v 1.11 2006/06/30 05:09:11 ozawa Exp $
 *
 * Copyright 2005- ONGS Inc. All rights reserved.
 * 
 * author: Masanori OZAWA (ozawa@ongs.co.jp)
 * version: $Revision: 1.11 $
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY ONGS INC ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL ONGS INC OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the ONGS Inc.
 * 
 */

#include "xdtp.h"
#include "modules/XDTPModuleLoader.h"

#include <dlfcn.h>

#define BUILDMODULE_SYM         "buildXDTPModule"
#define BUILDCHECKER_SYM        "buildXDTPChecker"
#define FREEMODULE_SYM          "freeXDTPModule"
#define FREECHECKER_SYM         "freeXDTPChecker"
#define GETMODULE_VERSION_SYM   "getXDTPModuleVersion"

using namespace XDTP;

XDTPModuleLoader::XDTPModuleLoader()
{
}

XDTPModuleLoader::~XDTPModuleLoader()
{
}

/**
 * XDTPModuleを内包するライブラリをロードします。
 * 
 * @param aPath XDTPModuleを内包するダイナミックリンクライブラリへのパス
 * @return XDTPModuleを内包するライブラリ。
 *         不要になった段階で、unloadModuleLibraryする必要があります。
 */
XDTPModuleLibrary* XDTPModuleLoader::loadModuleLibrary(const Glib::ustring& aPath)
{
    void* handle = dlopen(aPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
    
    if (!handle) {
        fprintf(stderr, "%s: %s" LINE_SEP, APP_NAME, dlerror());
        return NULL;
    }
    
    XDTPModuleLibrary* lib = new XDTPModuleLibrary;
    
    if (!lib) {
        dlclose(handle);
    }
    
    lib->handle = handle;
    lib->buildModule    = (XDTPModule*(*)())dlsym(handle, BUILDMODULE_SYM);
    lib->buildChecker   = (XDTPChecker*(*)())dlsym(handle, BUILDCHECKER_SYM);
    lib->freeModule     = (void(*)(XDTPModule*))dlsym(handle, FREEMODULE_SYM);
    lib->freeChecker    = (void(*)(XDTPChecker*))dlsym(handle, FREECHECKER_SYM);
    lib->getModuleVersion   = (u_int32_t(*)())dlsym(handle, GETMODULE_VERSION_SYM);
    
#ifdef DEBUG
    fprintf(stdout, "%s: module load result:" LINE_SEP, APP_NAME);
    fprintf(stdout, "\t handle: %p" LINE_SEP, lib->handle);
    fprintf(stdout, "\t buildModule: %p" LINE_SEP, lib->buildModule);
    fprintf(stdout, "\t buildChecker: %p" LINE_SEP, lib->buildChecker);
    fprintf(stdout, "\t freeModule: %p" LINE_SEP, lib->freeModule);
    fprintf(stdout, "\t freeChecker: %p" LINE_SEP, lib->freeChecker);
    fprintf(stdout, "\t getModuleVersion: %p (%x)" LINE_SEP,
            lib->getModuleVersion, (lib->getModuleVersion ? lib->getModuleVersion() : 0));
#endif

    if (!lib->getModuleVersion ||
        (!lib->buildModule || !lib->freeModule) ||
        (lib->buildChecker && !lib->freeChecker))
    {
        dlclose(handle);
        delete lib;
        lib = NULL;
    }
    
    return lib;
}

/**
 * XDTPModuleを内包するライブラリを解放します。
 * 未解放のXDTPModule と XDTPCheckerが存在する場合は、これを解放します。
 * 
 * @param aLibrary XDTPModuleを内包するライブラリ。
 */
void XDTPModuleLoader::unloadModuleLibrary(XDTPModuleLibrary* aLibrary)
{
    if (!aLibrary) {
        THROW("bad argument.");
    }
    
    {
        std::list<XDTPModule*>::iterator iter = (aLibrary->module).begin();
        std::list<XDTPModule*>::iterator end = (aLibrary->module).end();
        
        for (; iter != end; iter++) {
            aLibrary->freeModule(*iter);
        }
    }

    {
        std::list<XDTPChecker*>::iterator iter = (aLibrary->checker).begin();
        std::list<XDTPChecker*>::iterator end = (aLibrary->checker).end();
        
        for (; iter != end; iter++) {
            aLibrary->freeChecker(*iter);
        }
    }
    
    dlclose(aLibrary->handle);
    delete aLibrary;
}

/**
 * XDTPModuleを構築します。
 * 
 * @param aLibrary XDTPModuleを内包するライブラリ。
 * @return XDTPModuleを戻します。不要になった段階で freeModule する必要があります。
 */
XDTPModule* XDTPModuleLoader::buildModule(XDTPModuleLibrary* aLibrary)
{
    u_int32_t version;

    if (!aLibrary) {
        THROW("bad argument.");
    }
    
    version = aLibrary->getModuleVersion();
    if (XDTP_MODULE_VERSION != version) {
#ifdef DEBUG
        fprintf(stderr, "%s: error: XDTPModule is old. (version=%x)" LINE_SEP, APP_NAME, version);
#endif
        return NULL;
    }
    
    XDTPModule* result = (XDTPModule*)aLibrary->buildModule();
    
    if (result) {
        (aLibrary->module).push_back(result);
    }
    
    return result;
}

/**
 * XDTPCheckerを構築します。
 * 
 * @param aLibrary XDTPCheckerを内包するライブラリ。
 * @return XDTPCheckerを戻します。不要になった段階で freeChecker する必要があります。
 */
XDTPChecker* XDTPModuleLoader::buildChecker(XDTPModuleLibrary* aLibrary)
{
    u_int32_t version;

    if (!aLibrary) {
        THROW("bad argument.");
    }
    
    version = aLibrary->getModuleVersion();
    if (XDTP_MODULE_VERSION != version) {
#ifdef DEBUG
        fprintf(stderr, "%s: error: XDTPModule is old. (version=%x)" LINE_SEP, APP_NAME, version);
#endif
        return NULL;
    }

    if (!aLibrary->buildChecker) {
        return NULL;
    }

    XDTPChecker* result = (XDTPChecker*)aLibrary->buildChecker();
    
    if (result) {
        (aLibrary->checker).push_back(result);
    }
    
    return result;
}

/**
 * XDTPModuleを解放します。
 * 
 * @param aLibrary XDTPModuleを内包するライブラリ。
 * @param aModule 構築したXDTPModule
 */
void XDTPModuleLoader::freeModule(XDTPModuleLibrary* aLibrary, XDTPModule* aModule)
{
    if (!aLibrary || !aModule) {
        THROW("bad argument.");
    }
    
    aLibrary->freeModule(aModule);
    (aLibrary->module).remove(aModule);
}

/**
 * XDTPCheckerを解放します。
 * 
 * @param aLibrary XDTPCheckerを内包するライブラリ。
 * @param aModule 構築したXDTPChecker
 */
void XDTPModuleLoader::freeChecker(XDTPModuleLibrary* aLibrary, XDTPChecker* aChecker)
{
    if (!aLibrary || !aChecker) {
        THROW("bad argument.");
    }
    
    aLibrary->freeChecker(aChecker);
    (aLibrary->checker).remove(aChecker);
}


syntax highlighted by Code2HTML, v. 0.9.1