blob: 9aa00cef020fe06059c1dc1aa47f584624044c11 [file] [log] [blame]
/** \file dllfile.hpp .
-----------------------------------------------------------------------------
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
-----------------------------------------------------------------------------
\brief the class DllProcLoaderFile is used to maintain dynamic link libraries
-------------------------------------------------------------------------- */
#ifndef __UIMA_DLLFILE_HPP
#define __UIMA_DLLFILE_HPP
/* ----------------------------------------------------------------------- */
/* Interface dependencies */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Implementation dependencies */
/* ----------------------------------------------------------------------- */
#include "apr_pools.h"
#include "apr_dso.h"
#include "uima/filename.hpp"
#include "uima/exceptions.hpp"
#include "uima/msg.h"
#include "uima/envvar.hpp"
/* ----------------------------------------------------------------------- */
/* Constants */
/* ----------------------------------------------------------------------- */
#define DSOBUFLEN 256
/* ----------------------------------------------------------------------- */
/* Types */
/* ----------------------------------------------------------------------- */
namespace uima {
typedef apr_dso_handle_sym_t TyProcedure;
}
/* ----------------------------------------------------------------------- */
/* Classes */
/* ----------------------------------------------------------------------- */
namespace uima {
namespace util {
/**
* The class <tt> DllProcLoaderFile</tt> is used to load specific procedures
* from a DLL (shared library) by their name.
* \code
typedef void (*MYPROC)(const char *);
foo(const uima::util::Filename & crclFilename)
{
uima::util::DllProcLoaderFile clDll(crclFilename);
if(clDll.isValid())
{
MYPROC utProc = (MYPROC) clDll.getProcedure("myFunction");
if(utProc)
(utProc)("My message"); // call my procedure in DLL
else
// error handling
}
}
\endcode
* The loaded functions may be called as long as the DLL is loaded. Calling
* a loaded function after the destructor of <tt> DllProcLoaderFile</tt> has
* unloaded the DLL will cause unexpected results. (An application crash
* is very likely to happen.)
*
* <b> NOTE: dropped the Cos Special Requirements for AIX 4.2 and below </b>
*
*/
class DllProcLoaderFile {
public:
/** @name Constructors */
/*@{*/
/** instantiate a DLL object and load the specified DLL */
DllProcLoaderFile(const Filename & crclFilename);
/*@}*/
~DllProcLoaderFile(void);
/** @name Properties */
/*@{*/
/** return TRUE if the DLL was loaded successfully */
bool isValid(void) const {
return isLoaded;
}
/** return a pointer to the specified DLL function or NULL if the specified
function cannot be found in this DLL */
TyProcedure getProcedure(const char * cpszProcName);
/** map APR error code (status) of last call to a UIMACPP error code. */
TyErrorId getErrorId(void) const;
/** map APR error code to a UIMACPP message id */
TyMessageId getErrorMsgId(void) const;
/** return a pointer to the error msg (if any) */
const char * getErrorMsg(void) const;
/** return the file's filename */
const Filename & getFilename(void) const {
return(iv_clFilename);
}
/** determine whether a file exists for filename on file system */
bool isExistent(void) const {
return iv_clFilename.isExistent();
}
/*@}*/
protected:
/* --- functions --- */
private:
apr_dso_handle_t * dsoHandle;
apr_pool_t * dsoPool;
bool isLoaded;
apr_status_t aprError;
Filename iv_clFilename;
char * dsoBuffer;
#ifdef WIN32
apr_status_t aprError2;
#endif
/* --- functions --- */
/* BASE CONSTRUCTOR NOT SUPPORTED */
DllProcLoaderFile(void); //lint !e1704
/* COPY CONSTRUCTOR NOT SUPPORTED */
DllProcLoaderFile(const DllProcLoaderFile & ); //lint !e1704
/* ASSIGNMENT OPERATOR NOT SUPPORTED */
DllProcLoaderFile & operator=(const DllProcLoaderFile & crclObject);
}
; /* DllProcLoaderFile */
/* ----------------------------------------------------------------------- */
/* Globals */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Function declarations */
/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* Macro definitions */
/* ----------------------------------------------------------------------- */
#ifdef _MSC_VER
# define DSO_EXTN ".dll"
#else
# ifdef __APPLE__
# define DSO_EXTN ".dylib"
# else
# define DSO_EXTN ".so"
# endif
#endif
/* ----------------------------------------------------------------------- */
/* Implementation */
/* ----------------------------------------------------------------------- */
inline DllProcLoaderFile::DllProcLoaderFile(const Filename & crclFilename)
: iv_clFilename(crclFilename)
/* ----------------------------------------------------------------------- */
{
isLoaded = FALSE;
dsoHandle = NULL;
dsoPool = NULL;
aprError = apr_pool_create(&dsoPool, NULL);
if ( aprError == APR_SUCCESS ) {
// Always allocate error buffer as if done in getErrorMsg it loses it's const
// and that is expected back in ResourceManager::requestAnnotatorFile
dsoBuffer = (char*) apr_palloc ( dsoPool, DSOBUFLEN );
#ifdef _DEBUG
#ifdef _WINDOWS
// Add "D" to library name
char libName[128];
strcpy(libName, iv_clFilename.getName());
strcat(libName, "D");
iv_clFilename.setNewName(libName);
#endif
#endif
// Add the appropriate extension if missing
if (! iv_clFilename.isAbsolute() && *iv_clFilename.getExtension() == '\0' )
iv_clFilename.setNewExtension(DSO_EXTN);
aprError = apr_dso_load(&dsoHandle, iv_clFilename.getAsCString(), dsoPool);
isLoaded = ( aprError == APR_SUCCESS );
#ifdef WIN32
// WIN32: LoadLibraryEx falsely reports ERROR_MOD_NOT_FOUND when the dll cannot be loaded.
// APR should use DONT_RESOLVE_DLL_REFERENCES to check if ERROR_INVALID_DLL is a better rc.
// Can check for missing case but not for damaged vs. missing library.
aprError2 = APR_SUCCESS;
if ( !isLoaded ) {
if ( APR_TO_OS_ERROR(aprError) == ERROR_MOD_NOT_FOUND ) {
if ( ! iv_clFilename.isExistent() ) { // Not in cur dir
util::EnvironmentVariableQueryOnly clEnvVarSearchPaths("PATH");
if ( !iv_clFilename.determinePath( clEnvVarSearchPaths.getValue() ) ) {
return; // Definitely missing
}
}
// Exists, so must be damaged ... change error code
aprError = APR_FROM_OS_ERROR(ERROR_INVALID_DLL);
aprError2 = aprError;
}
}
#endif
} else {
UIMA_EXC_THROW_NEW(ExcOutOfMemory,
UIMA_ERR_ENGINE_OUT_OF_MEMORY,
UIMA_MSG_ID_EXC_OUT_OF_MEMORY,
ErrorMessage(UIMA_MSG_ID_EXCON_CREATING_POOL_FOR_CLASS,
"uima::util::DllProcLoaderFile"),
ErrorInfo::unrecoverable);
}
}
inline DllProcLoaderFile::~DllProcLoaderFile(void)
/* ----------------------------------------------------------------------- */
{
if ( dsoHandle != NULL ) {
apr_dso_unload ( dsoHandle );
dsoHandle = NULL;
}
if ( dsoPool != NULL )
apr_pool_destroy ( dsoPool );
isLoaded = FALSE;
}
inline TyProcedure DllProcLoaderFile::getProcedure(const char * cpszProcName)
/* ----------------------------------------------------------------------- */
{
apr_dso_handle_sym_t procAddr = NULL;
if (isLoaded) {
aprError = apr_dso_sym(&procAddr, dsoHandle, cpszProcName);
if (aprError == APR_SUCCESS)
return (TyProcedure) procAddr;
}
return NULL;
}
inline const char * DllProcLoaderFile::getErrorMsg(void) const
/* ----------------------------------------------------------------------- */
{
if ( dsoHandle == NULL )
return NULL;
else {
#ifdef WIN32
if ( aprError == aprError2 )
return apr_strerror ( aprError2, dsoBuffer, DSOBUFLEN );
#endif
return apr_dso_error ( dsoHandle, dsoBuffer, DSOBUFLEN );
}
}
inline TyErrorId DllProcLoaderFile::getErrorId(void) const
/* ----------------------------------------------------------------------- */
{
if (aprError == APR_SUCCESS) {
return UIMA_ERR_NONE;
}
#ifdef WIN32
if (APR_TO_OS_ERROR(aprError) == ERROR_MOD_NOT_FOUND) {
return UIMA_ERR_ANNOTATOR_COULD_NOT_FIND;
}
#else
if (APR_TO_OS_ERROR(aprError) == ENOENT) {
return UIMA_ERR_ANNOTATOR_COULD_NOT_FIND;
}
#endif
return UIMA_ERR_ANNOTATOR_COULD_NOT_LOAD;
}
inline TyMessageId DllProcLoaderFile::getErrorMsgId(void) const
/* ----------------------------------------------------------------------- */
{
if (aprError == APR_SUCCESS) {
return UIMA_ERR_NONE;
}
#ifdef WIN32
if (APR_TO_OS_ERROR(aprError) == ERROR_MOD_NOT_FOUND) {
return UIMA_MSG_ID_ANNOTATOR_COULD_NOT_FIND;
}
#endif
return UIMA_MSG_ID_ANNOTATOR_COULD_NOT_LOAD;
}
} // namespace util
} // namespace uima
#endif /* __UIMA_DLLFILE_HPP */
/* <EOF> */