(*
* Unit owner: D10.天地弦
* blog: http://www.cnblogs.com/dksoft
*
* 2014-11-14 13:59:05
* 添加GetBeanInfos
*
* v0.1.2 (2014-09-06 10:50:44)
* 为了满足各种加载需求, 去掉自动加载方式,
* 需要在工程开始的地方调用applicationContextInitialize进行初始化
*
* v0.1.1 (2014-09-03 23:46:16)
* 添加 IApplicationContextEx01接口
* 可以实现手动加载DLL和配置文件
*
*
* v0.1.0(2014-08-29 13:00)
* 修改加载方式(beanMananger.dll-改造)
*
* v0.0.1(2014-05-17)
* + first release
*
*
*)
unit mybean.console;
{$I 'MyBean.inc'}
interface
{$WARN UNIT_PLATFORM OFF}
{$WARN SYMBOL_PLATFORM OFF}
uses
Classes, SysUtils, Windows, ShLwApi,
mybean.core.intf,
mybean.console.loader,
mybean.console.loader.dll,
mybean.strConsts,
uKeyInterface, IniFiles,
{$IFDEF CONSOLE}
{$ELSE}
// 引用Forms单元,避免在Application和Screen对象释放之后清理该单元
{$if CompilerVersion < 23}
Forms,
{$else}
Vcl.Forms,
{$ifend}
{$ENDIF}
safeLogger;
type
TApplicationContext = class(TInterfacedObject
, IApplicationContext
, IApplicationContextEx01
, IApplicationContextEx2
, IApplicationContextEx3
, IbeanFactoryRegister
)
private
FINIFile:TIniFile;
FTraceLoadFile: Boolean;
///
/// 保存FactoryObject列表,LibFile -> FactoryObject
///
FFactoryObjectList: TStrings;
///
/// 保存beanID和FactoryObject的对应关系
///
FBeanMapList: TStrings;
procedure DoRegisterPluginIDS(pvPluginIDS: String; pvFactoryObject:
TBaseFactoryObject);
procedure DoRegisterPlugins(pvPlugins: TStrings; pvFactoryObject:
TBaseFactoryObject);
procedure checkCreateINIFile;
function checkInitializeFactoryObject(pvFactoryObject:TBaseFactoryObject;
pvRaiseException:Boolean): Boolean;
procedure removeRegistedBeans(pvLibFile:string);
protected
///
/// 卸载掉指定的插件宿主文件(dll)
/// 在卸载之前应该释放掉由所创建的对象实例,和分配的内存空间,
/// 否则会在退出EXE的时候,出现内存访问违规错误
/// 卸载如果出现问题,请查看日志文件
/// *(谨慎使用)
///
function unLoadLibraryFile(pvLibFile: PAnsiChar; pvRaiseException: Boolean =
true): Boolean; stdcall;
///
/// 判断BeanID是否存在
///
function checkBeanExists(pvBeanID:PAnsiChar):Boolean; stdcall;
///
/// 获取所有Bean信息
/// result: 返回读取到的数据长度
/// pvLength: 尝试读取的长度,传入的pvBeanInfo必须分配有足够的内存
/// pvBeanInfo: 返回读取到的数据
/// utf8 AnsiString
/// [
/// {"id":"beanid", "lib":"libfile"}
/// ...
/// ]
///
function GetBeanInfos(pvBeanInfo:PAnsiChar; pvLength:Integer): Integer; stdcall;
protected
///
/// 加载库文件
///
///
/// 加载成功返回true, 失败返回false, 可以用raiseLastOsError获取异常
///
/// (PAnsiChar)
function checkLoadLibraryFile(pvLibFile:PAnsiChar): Boolean; stdcall;
///
/// 加载配置文件
///
///
/// 加载失败返回false<文件可能不存在>
///
/// (PAnsiChar)
function checkLoadBeanConfigFile(pvConfigFile:PAnsiChar): Boolean; stdcall;
protected
///
/// 直接从DLL和BPL文件中加载插件,在没有配置文件的情况下执行
/// plug-ins\*.DLL, plug-ins\*.BPL, *.DLL
///
procedure executeLoadLibrary; stdcall;
///
/// 加载一个库文件, 获取其中插件,并进行注册
///
procedure checkLoadALibFile(pvFile:string);
///
/// 根据提供的Lib文件得到TLibFactoryObject对象,如果不列表中不存在则新增一个对象
///
function checkCreateLibObject(pvFileName:string): TLibFactoryObject;
///
/// 从FLibFactory中移除,加载失败时进行移除
///
///
/// 如果移除返回true
///
/// 要移除的文件名(全路径)
function checkRemoveLibObjectFromList(pvFileName:String): Boolean;
private
///
/// Copy的目的文件
///
FCopyDestPath: String;
///
/// 应用程序根目录
///
FRootPath:String;
///
/// 从单个配置文件中配置插件, 返回成功处理的Bean配置数量
/// 会整理配置中Bean对应libFile库对象(TLibFactoryObject)
///
function executeLoadFromConfigFile(pvFileName: String): Integer;
///
/// 从多个配置文件中读取配置插件, 返回成功处理的Bean配置数量
///
function executeLoadFromConfigFiles(pvFiles: TStrings): Integer;
///
/// 准备工作,读取配置文件
///
procedure checkReady;
///
/// 关联Bean和Lib对象(往FBeanMapList中注册关系)
///
function checkRegisterBean(pvBeanID: string; pvFactoryObject:
TBaseFactoryObject): Boolean;
///
/// 从配置文件中加载, 返回成功处理的Bean配置数量
///
function checkInitializeFromConfigFiles(pvConfigFiles: string): Integer;
///
/// 初始化工厂对象
///
procedure checkInitializeFactoryObjects;
public
constructor Create;
procedure BeforeDestruction; override;
destructor Destroy; override;
///
/// 执行反初始化
///
procedure checkFinalize; stdcall;
///
/// 执行初始化
///
procedure checkInitialize; stdcall;
///
/// 获取根据BeanID获取一个对象
///
function getBean(pvBeanID: PAnsiChar): IInterface; stdcall;
///
/// 获取beanID对应的工厂接口
///
function getBeanFactory(pvBeanID:PAnsiChar): IInterface; stdcall;
protected
///
/// 直接注册Bean工厂插件
///
function registerBeanFactory(const pvFactory: IBeanFactory; const pvNameSapce:PAnsiChar):Integer;stdcall;
public
//1 根据基础路径和相对路径获取绝对路径(杨茂丰)
class function getAbsolutePath(BasePath, RelativePath: string): string;
class function getFileNameList(vFileList: TStrings; const aSearchPath: string):
integer;
class function instance: TApplicationContext;
class function pathWithBackslash(const Path: string): String;
class function pathWithoutBackslash(const Path: string): string;
end;
TKeyMapImpl = class(TInterfacedObject, IKeyMap)
private
FKeyIntface:TKeyInterface;
protected
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
protected
///
/// 判断是否存在接口
///
function existsObject(const pvKey:PAnsiChar):Boolean; stdcall;
///
/// 根据key值获取接口
///
function getObject(const pvKey:PAnsiChar):IInterface; stdcall;
///
/// 赋值接口
///
procedure setObject(const pvKey:PAnsiChar; const pvIntf: IInterface); stdcall;
///
/// 移除接口
///
procedure removeObject(const pvKey:PAnsiChar); stdcall;
///
/// 清理对象
///
procedure cleanupObjects; stdcall;
public
procedure AfterConstruction; override;
destructor Destroy; override;
end;
///
/// 获取全局的appliationContext
///
function appPluginContext: IApplicationContext; stdcall;
///
/// 应用程序清理
///
procedure appContextCleanup; stdcall;
///
/// 注册beanFactory
///
function registerFactoryObject(const pvBeanFactory:IBeanFactory; const
pvNameSapce:PAnsiChar): Integer; stdcall;
procedure executeKeyMapCleanup;
///
/// 获取全局的KeyMap接口
///
function applicationKeyMap: IKeyMap; stdcall;
///
/// 加载文件
/// executeLoadLibFiles('plugin\*.dll');
///
procedure executeLoadLibFiles(const pvLibFiles: string);
///
/// 执行初始化,如果已经初始化过,则会跳过
/// 根据 ini的配置进行初始化,
/// 如果没有配置文件,直接加载 *.dll和plug-ins\*.dll
///
procedure applicationContextInitialize;
///
/// 应用程序退出时可以手动调用该方法,
/// 可以清理全局对象,卸载DLL
///
procedure applicationContextFinalize;
procedure logDebugInfo;
///
/// 产生一个Hash值
/// QDAC群-Hash函数
///
function hashOf(const p:Pointer;l:Integer): Integer; overload;
///
/// 产生一个Hash值
///
function hashOf(const vStrData:String): Integer; overload;
implementation
uses
superobject, uSOTools, Dialogs;
var
__instanceAppContext:TApplicationContext;
__instanceAppContextAppContextIntf:IInterface;
__instanceKeyMap:TKeyMapImpl;
__instanceKeyMapKeyIntf:IInterface;
__beanLogger:TSafeLogger;
function appPluginContext: IApplicationContext;
begin
Result := TApplicationContext.instance;
end;
procedure appContextCleanup; stdcall;
begin
//清理KeyMap对象
executeKeyMapCleanup;
if __instanceAppContextAppContextIntf = nil then exit;
try
try
__instanceAppContext.checkFinalize;
except
end;
except
end;
end;
function applicationKeyMap: IKeyMap;
begin
Result := __instanceKeyMap;
end;
procedure executeKeyMapCleanup;
begin
if __instanceKeyMapKeyIntf = nil then exit;
try
__instanceKeyMap.cleanupObjects;
except
end;
end;
function registerFactoryObject(const pvBeanFactory:IBeanFactory; const
pvNameSapce:PAnsiChar): Integer;
begin
try
Result := TApplicationContext.instance.registerBeanFactory(pvBeanFactory, pvNameSapce);
except
Result := -1;
end;
end;
procedure logDebugInfo;
begin
if __instanceKeyMapKeyIntf = nil then exit;
try
if __instanceKeyMap.RefCount > 1 then
begin
__beanLogger.logMessage(sDebug_applicationKeyMapUnload,
[__instanceKeyMap.RefCount-1], 'DEBUG_');
end;
except
end;
if __instanceAppContextAppContextIntf = nil then exit;
try
if __instanceAppContext.RefCount > 1 then
begin
__beanLogger.logMessage(sDebug_applicationContextUnload,
[__instanceAppContext.RefCount-1], 'DEBUG_');
end;
except
end;
end;
function hashOf(const p:Pointer;l:Integer): Integer;
var
ps:PInteger;
lr:Integer;
begin
Result:=0;
if l>0 then
begin
ps:=p;
lr:=(l and $03);//检查长度是否为4的整数倍
l:=(l and $FFFFFFFC);//整数长度
while l>0 do
begin
Result:=((Result shl 5) or (Result shr 27)) xor ps^;
Inc(ps);
Dec(l,4);
end;
if lr<>0 then
begin
l:=0;
Move(ps^,l,lr);
Result:=((Result shl 5) or (Result shr 27)) xor l;
end;
end;
end;
function hashOf(const vStrData:String): Integer;
var
lvStr:AnsiString;
begin
lvStr := AnsiString(vStrData);
Result := hashOf(PAnsiChar(lvStr), Length(lvStr));
end;
procedure executeLoadLibFiles(const pvLibFiles: string);
begin
TApplicationContext.instance.checkLoadLibraryFile(PAnsiChar(AnsiString(pvLibFiles)));
end;
procedure applicationContextInitialize;
begin
appPluginContext.checkInitialize;
end;
procedure applicationContextFinalize;
begin
mybean.core.intf.appPluginContext := nil;
mybean.core.intf.applicationKeyMap := nil;
executeKeyMapCleanup;
appContextCleanup;
end;
procedure TApplicationContext.checkInitialize;
var
lvConfigFiles:String;
begin
if FFactoryObjectList.Count = 0 then
begin
// 先读取配置文件
lvConfigFiles := FINIFile.ReadString('main', 'beanConfigFiles', '');
if lvConfigFiles <> '' then
begin
if FTraceLoadFile then
__beanLogger.logMessage(sDebug_loadFromConfigFile, 'LOAD_TRACE_');
if checkInitializeFromConfigFiles(lvConfigFiles) > 0 then
begin
if FINIFile.ReadBool('main', 'loadOnStartup', False) then
begin
//加载DLL文件, 把DLL载入
checkInitializeFactoryObjects;
end;
end else
begin
if FTraceLoadFile then
__beanLogger.logMessage(sDebug_NoneConfigFile, 'LOAD_TRACE_');
end;
end else
begin
if FTraceLoadFile then
__beanLogger.logMessage(sDebug_directlyLoadLibFile, 'LOAD_TRACE_');
executeLoadLibrary;
end;
end;
end;
procedure TApplicationContext.checkReady;
var
lvTempPath:String;
l:Integer;
begin
lvTempPath := FINIFile.ReadString('main', 'copyDest', 'plug-ins\');
FTraceLoadFile := FINIFile.ReadBool('main','traceLoadLib', FTraceLoadFile);
__beanLogger.Enable := FTraceLoadFile;
FCopyDestPath := GetAbsolutePath(FRootPath, lvTempPath);
l := Length(FCopyDestPath);
if l = 0 then
begin
FCopyDestPath := FRootPath + 'plug-ins\';
end else
begin
FCopyDestPath := PathWithBackslash(FCopyDestPath);
end;
// try
// ForceDirectories(FCopyDestPath);
// except
// on E:Exception do
// begin
// __beanLogger.logMessage(
// '创建Copy目标文件夹[%s]出现异常:%s', [FCopyDestPath, e.Message],
// 'LOAD_ERROR_');
// end;
// end;
end;
function TApplicationContext.checkRegisterBean(pvBeanID: string;
pvFactoryObject: TBaseFactoryObject): Boolean;
var
j:Integer;
lvID:String;
lvLibObject:TBaseFactoryObject;
begin
Result := false;
lvID := trim(pvBeanID);
if (lvID <> '') then
begin
j := FBeanMapList.IndexOf(lvID);
if j <> -1 then
begin
lvLibObject := TBaseFactoryObject(FBeanMapList.Objects[j]);
{$IFDEF LOG_ON}
__beanLogger.logMessage(Format(sLoadTrace_BeanID_Repeat,
[lvID,lvLibObject.namespace]), 'LOAD_TRACE_');
{$ENDIF}
end else
begin
FBeanMapList.AddObject(lvID, pvFactoryObject);
Result := true;
end;
end;
end;
procedure TApplicationContext.BeforeDestruction;
begin
inherited;
end;
procedure TApplicationContext.checkFinalize;
var
lvLibObject:TBaseFactoryObject;
i:Integer;
begin
///清理掉applicationKeyMap中的全局资源
applicationKeyMap.cleanupObjects;
///全部执行一次Finalize;
for i := 0 to FFactoryObjectList.Count -1 do
begin
lvLibObject := TBaseFactoryObject(FFactoryObjectList.Objects[i]);
lvLibObject.checkFinalize;
end;
///卸载DLL
for i := 0 to FFactoryObjectList.Count -1 do
begin
try
lvLibObject := TBaseFactoryObject(FFactoryObjectList.Objects[i]);
lvLibObject.cleanup;
lvLibObject.Free;
except
on E: Exception do
ShowMessage(E.Message);
end;
end;
FFactoryObjectList.Clear;
FBeanMapList.Clear;
end;
constructor TApplicationContext.Create;
begin
inherited Create;
FFactoryObjectList := TStringList.Create();
FBeanMapList := TStringList.Create;
FRootPath := ExtractFilePath(ParamStr(0));
checkCreateINIFile;
checkReady;
end;
destructor TApplicationContext.Destroy;
begin
FINIFile.Free;
checkFinalize;
FBeanMapList.Free;
FFactoryObjectList.Free;
inherited Destroy;
end;
function TApplicationContext.checkBeanExists(pvBeanID: PAnsiChar): Boolean;
var
lvBeanID:String;
begin
lvBeanID := String(AnsiString(pvBeanID));
Result := FBeanMapList.IndexOf(lvBeanID)<> -1;
end;
procedure TApplicationContext.checkCreateINIFile;
var
lvFile:String;
begin
lvFile := ExtractFilePath(ParamStr(0)) + 'appConfig.ini';
// 不存在配置文件
if not FileExists(lvFile) then
begin
{$IFDEF LOG_ON}
FTraceLoadFile := true;
{$ELSE}
FTraceLoadFile := False;
{$ENDIF}
__beanLogger.Enable := FTraceLoadFile;
end;
FINIFile := TIniFile.Create(lvFile);
end;
function TApplicationContext.checkRemoveLibObjectFromList(pvFileName:String):
Boolean;
var
lvNameSpace:String;
i:Integer;
begin
Result := False;
lvNameSpace :=ExtractFileName(pvFileName) + '_' + IntToStr(hashOf(pvFileName));
if Length(lvNameSpace) = 0 then Exit;
i := FFactoryObjectList.IndexOf(lvNameSpace);
if i <> -1 then
begin
Result := true;
FFactoryObjectList.Delete(i);
end;
end;
function TApplicationContext.checkCreateLibObject(pvFileName:string):
TLibFactoryObject;
var
lvNameSpace:String;
i:Integer;
begin
Result := nil;
lvNameSpace :=ExtractFileName(pvFileName) + '_' + IntToStr(hashOf(pvFileName));
if Length(lvNameSpace) = 0 then Exit;
i := FFactoryObjectList.IndexOf(lvNameSpace);
if i = -1 then
begin
Result := TLibFactoryObject.Create;
Result.LibFileName := pvFileName;
FFactoryObjectList.AddObject(lvNameSpace, Result);
end else
begin
Result := TLibFactoryObject(FFactoryObjectList.Objects[i]);
end;
end;
function TApplicationContext.checkInitializeFactoryObject(
pvFactoryObject:TBaseFactoryObject; pvRaiseException:Boolean): Boolean;
begin
try
if pvFactoryObject.beanFactory = nil then
begin
if FTraceLoadFile then
begin
__beanLogger.logMessage(
sLoadTrace_Lib_Initalize, [String(pvFactoryObject.namespace)], 'LOAD_TRACE_');
end;
if pvRaiseException then
begin // 抛出异常的情况下, 直接进行初始化
pvFactoryObject.checkInitialize;
end else
begin //
if pvFactoryObject.checkIsValidLib(False) then
begin
pvFactoryObject.checkInitialize;
end else
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(
Format(sLoadTrace_Lib_Invalidate, [String(pvFactoryObject.namespace)]),
'LOAD_TRACE_');
{$ENDIF}
end;
end;
end;
Result := pvFactoryObject.beanFactory <> nil;
except
on E:Exception do
begin
Result := false;
{$IFDEF LOG_ON}
__beanLogger.logMessage(
sLoadTrace_Lib_Error,
[String(pvFactoryObject.namespace), e.Message],
'LOAD_TRACE_');
{$ENDIF}
if pvRaiseException then
raise;
end;
end;
end;
function TApplicationContext.getBean(pvBeanID: PAnsiChar): IInterface;
var
j:Integer;
lvLibObject:TBaseFactoryObject;
lvBeanID:String;
begin
Result := nil;
lvBeanID := string(AnsiString(pvBeanID));
j := FBeanMapList.IndexOf(lvBeanID);
if j <> -1 then
begin
lvLibObject := TBaseFactoryObject(FBeanMapList.Objects[j]);
Result := lvLibObject.getBean(lvBeanID);
end;
end;
procedure TApplicationContext.DoRegisterPluginIDS(pvPluginIDS: String;
pvFactoryObject: TBaseFactoryObject);
var
lvStrings:TStrings;
begin
lvStrings := TStringList.Create;
try
lvStrings.Text := pvPluginIDS;
DoRegisterPlugins(lvStrings, pvFactoryObject);
finally
lvStrings.Free;
end;
end;
procedure TApplicationContext.DoRegisterPlugins(pvPlugins: TStrings;
pvFactoryObject: TBaseFactoryObject);
var
i, j:Integer;
lvID:String;
lvLibObject:TBaseFactoryObject;
begin
for i := 0 to pvPlugins.Count - 1 do
begin
lvID := trim(pvPlugins[i]);
if (lvID <> '') then
begin
j := FBeanMapList.IndexOf(lvID);
if j <> -1 then
begin
lvLibObject := TBaseFactoryObject(FBeanMapList.Objects[j]);
{$IFDEF LOG_ON}
__beanLogger.logMessage(Format(sLoadTrace_BeanID_Repeat,
[lvID,lvLibObject.namespace]));
{$ENDIF}
end else
begin
FBeanMapList.AddObject(lvID, pvFactoryObject);
end;
end;
end;
end;
procedure TApplicationContext.checkInitializeFactoryObjects;
var
i: Integer;
lvFactoryObject:TBaseFactoryObject;
begin
for i := 0 to FFactoryObjectList.Count -1 do
begin
lvFactoryObject := TBaseFactoryObject(FFactoryObjectList.Objects[i]);
try
if FTraceLoadFile then
__beanLogger.logMessage(sLoadTrace_Factory_Initalize, [string(lvFactoryObject.namespace)],
'LOAD_TRACE_');
lvFactoryObject.checkInitialize;
except
on E:Exception do
begin
__beanLogger.logMessage(
sLoadTrace_Lib_Error, [lvFactoryObject.namespace,e.Message],
'LOAD_TRACE_');
end;
end;
end;
end;
function TApplicationContext.checkInitializeFromConfigFiles(pvConfigFiles:
string): Integer;
var
lvFilesList, lvStrings: TStrings;
i: Integer;
lvStr, lvFileName, lvPath:String;
begin
Result := 0;
lvStrings := TStringList.Create;
lvFilesList := TStringList.Create;
try
lvFilesList.Text := StringReplace(pvConfigFiles, ',', sLineBreak, [rfReplaceAll]);
for i := 0 to lvFilesList.Count - 1 do
begin
lvStr := lvFilesList[i];
lvFileName := ExtractFileName(lvStr);
lvPath := ExtractFilePath(lvStr);
lvPath := GetAbsolutePath(FRootPath, lvPath);
lvFileName := lvPath + lvFileName;
lvStrings.Clear;
getFileNameList(lvStrings, lvFileName);
Result := Result + executeLoadFromConfigFiles(lvStrings);
end;
finally
lvFilesList.Free;
lvStrings.Free;
end;
end;
procedure TApplicationContext.checkLoadALibFile(pvFile: string);
var
lvFile: string;
lvLib:TLibFactoryObject;
lvIsOK:Boolean;
lvBeanIDs:array[1..4096] of AnsiChar;
begin
if pvFile = '' then exit;
lvFile := pvFile;
lvLib := checkCreateLibObject(lvFile);
lvIsOK := false;
try
if lvLib.Tag = 1 then
begin //已经加载
lvIsOK := true;
end else
begin
if checkInitializeFactoryObject(TBaseFactoryObject(lvLib), False) then
begin
try
ZeroMemory(@lvBeanIDs[1], 4096);
lvLib.beanFactory.getBeanList(@lvBeanIDs[1], 4096);
DoRegisterPluginIDS(String(AnsiString(PAnsiChar(@lvBeanIDs[1]))), TBaseFactoryObject(lvLib));
lvIsOK := true;
lvLib.Tag := 1;
except
on E:Exception do
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(sLoadTrace_Lib_Error, [lvLib.LibFileName, e.Message],
'LOAD_TRACE_');
{$ENDIF}
end;
end;
end;
end;
finally
if not lvIsOK then
begin
try
checkRemoveLibObjectFromList(lvFile);
lvLib.DoFreeLibrary;
lvLib.Free;
except
end;
end;
end;
end;
function TApplicationContext.checkLoadBeanConfigFile(
pvConfigFile: PAnsiChar): Boolean;
begin
Result := checkInitializeFromConfigFiles(String(AnsiString(pvConfigFile))) > 0;
end;
function TApplicationContext.checkLoadLibraryFile(
pvLibFile: PAnsiChar): Boolean;
var
lvFilesList, lvStrings: TStrings;
i, j: Integer;
lvStr, lvFileName, lvPath:String;
begin
lvStrings := TStringList.Create;
lvFilesList := TStringList.Create;
try
lvStr :=String(AnsiString(pvLibFile));
{$IFDEF LOG_ON}
__beanLogger.logMessage('加载插件宿主文件[%s]', [lvStr], 'LOAD_TRACE_');
{$ENDIF}
lvFilesList.Text := StringReplace(lvStr, ',', sLineBreak, [rfReplaceAll]);
for i := 0 to lvFilesList.Count - 1 do
begin
lvStr := lvFilesList[i];
lvFileName := ExtractFileName(lvStr);
lvPath := ExtractFilePath(lvStr);
lvPath := GetAbsolutePath(FRootPath, lvPath);
lvFileName := lvPath + lvFileName;
lvStrings.Clear;
getFileNameList(lvStrings, lvFileName);
for j := 0 to lvStrings.Count -1 do
begin
checkLoadALibFile(trim(lvStrings[j]));
end;
end;
Result := true;
finally
lvFilesList.Free;
lvStrings.Free;
end;
end;
function TApplicationContext.executeLoadFromConfigFile(pvFileName: String):
Integer;
var
lvConfig, lvPluginList, lvItem:ISuperObject;
I: Integer;
lvLibFile, lvID:String;
lvLibObj:TBaseFactoryObject;
begin
Result := 0;
lvConfig := TSOTools.JsnParseFromFile(pvFileName);
if lvConfig = nil then Exit;
if lvConfig.IsType(stArray) then lvPluginList := lvConfig
else if lvConfig.O['list'] <> nil then lvPluginList := lvConfig.O['list']
else if lvConfig.O['plugins'] <> nil then lvPluginList := lvConfig.O['plugins'];
if (lvPluginList = nil) or (not lvPluginList.IsType(stArray)) then
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(Format('配置文件[%s]非法', [pvFileName]), 'LOAD_TRACE_');
{$ENDIF}
Exit;
end;
for I := 0 to lvPluginList.AsArray.Length - 1 do
begin
lvItem := lvPluginList.AsArray.O[i];
lvLibFile := FRootPath + lvItem.S['lib'];
if not FileExists(lvLibFile) then
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(Format('未找到配置文件[%s]中的Lib文件[%s]', [pvFileName, lvLibFile]),
'LOAD_TRACE_');
{$ENDIF}
end else
begin
lvLibObj := TBaseFactoryObject(checkCreateLibObject(lvLibFile));
if lvLibObj = nil then
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(Format('未找到Lib文件[%s]', [lvLibFile]), 'LOAD_TRACE_');
{$ENDIF}
end else
begin
try
lvID := lvItem.S['id'];
if lvID = '' then
begin
raise Exception.Create('非法的插件配置,没有指定beanID:' + sLineBreak + lvItem.AsJSon(true, false));
end;
if checkRegisterBean(lvID, lvLibObj) then
begin
//将配置放到对应的节点管理中
lvLibObj.addBeanConfig(lvItem);
end;
Inc(result);
except
on E:Exception do
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(
sLoadTrace_Lib_Error,
[String(lvLibObj.namespace), e.Message],
'LOAD_TRACE_');
{$ENDIF}
end;
end;
end;
end;
end;
end;
function TApplicationContext.executeLoadFromConfigFiles(pvFiles: TStrings):
Integer;
var
i:Integer;
lvFile:String;
begin
Result := 0;
for i := 0 to pvFiles.Count - 1 do
begin
lvFile := pvFiles[i];
Result := Result + executeLoadFromConfigFile(lvFile);
end;
end;
procedure TApplicationContext.executeLoadLibrary;
var
lvStrings: TStrings;
i: Integer;
lvFile: string;
begin
lvStrings := TStringList.Create;
try
getFileNameList(lvStrings, ExtractFilePath(ParamStr(0)) + 'plug-ins\*.dll');
getFileNameList(lvStrings, ExtractFilePath(ParamStr(0)) + 'plug-ins\*.bpl');
getFileNameList(lvStrings, ExtractFilePath(ParamStr(0)) + '*.dll');
for i := 0 to lvStrings.Count - 1 do
begin
lvFile := lvStrings[i];
checkLoadALibFile(lvFile);
end;
finally
lvStrings.Free;
end;
end;
function TApplicationContext.getBeanFactory(pvBeanID:PAnsiChar): IInterface;
var
j:Integer;
lvLibObject:TBaseFactoryObject;
lvBeanID:AnsiString;
begin
Result := nil;
lvBeanID := pvBeanID;
try
j := FBeanMapList.IndexOf(String(lvBeanID));
if j <> -1 then
begin
lvLibObject := TBaseFactoryObject(FBeanMapList.Objects[j]);
if lvLibObject.beanFactory = nil then
begin
if FTraceLoadFile then
__beanLogger.logMessage(sLoadTrace_Factory_Init_BEGIN, [lvLibObject.namespace],
'LOAD_TRACE_');
lvLibObject.checkInitialize;
if FTraceLoadFile then
__beanLogger.logMessage(sLoadTrace_Factory_Init_END, [lvLibObject.namespace],
'LOAD_TRACE_');
end;
Result := lvLibObject.beanFactory;
end else
begin
{$IFDEF LOG_ON}
__beanLogger.logMessage(
Format('找不到对应的[%s]插件工厂', [lvBeanID]),
'LOAD_TRACE_');
{$ENDIF}
end;
except
on E:Exception do
begin
__beanLogger.logMessage(
Format('获取插件工厂[%s]出现异常', [lvBeanID]) + e.Message,
'LOAD_TRACE_');
end;
end;
end;
class function TApplicationContext.instance: TApplicationContext;
begin
Result := __instanceAppContext;
end;
class function TApplicationContext.getAbsolutePath(BasePath, RelativePath:
string): string;
var
Dest: array[0..MAX_PATH] of Char;
begin
FillChar(Dest, SizeOf(Dest), 0);
PathCombine(Dest, PChar(BasePath), PChar(RelativePath));
Result := string(Dest);
end;
function TApplicationContext.GetBeanInfos(pvBeanInfo:PAnsiChar;
pvLength:Integer): Integer;
var
i:Integer;
lvLibObject:TBaseFactoryObject;
lvJSon, lvItem:ISuperObject;
s :AnsiString;
begin
lvJSon := SO('[]');
for i := 0 to FBeanMapList.Count - 1 do
begin
lvLibObject := TBaseFactoryObject(FBeanMapList.Objects[i]);
lvItem := SO();
lvItem.S['id'] := FBeanMapList.Strings[i];
if lvLibObject is TLibFactoryObject then
begin
lvItem.s['lib'] := TLibFactoryObject(lvLibObject).libFileName;
end else
begin
lvItem.s['lib'] := lvLibObject.namespace;
end;
lvJSon.AsArray.Add(lvItem);
end;
s := UTF8Encode(lvJSon.AsJSon(True, False));
Result := Length(s);
if pvBeanInfo <> nil then
begin
if pvLength < Result then Result := pvLength;
Move(s[1], pvBeanInfo^, Result);
end;
end;
class function TApplicationContext.getFileNameList(vFileList: TStrings; const
aSearchPath: string): integer;
var dirinfo: TSearchRec;
dir, lCurrentDir: string;
begin
result := 0;
lCurrentDir := GetCurrentDir;
SetCurrentDir(ExtractFileDir(ParamStr(0)));
try
dir := ExtractFilePath(ExpandFileName(aSearchPath));
if (dir <> '') then
dir := IncludeTrailingPathDelimiter(dir);
if (FindFirst(aSearchPath, faArchive, dirinfo) = 0) then repeat
vFileList.Add(dir + dirinfo.Name);
Inc(result);
until (FindNext(dirinfo) <> 0);
SysUtils.FindClose(dirinfo);
finally
SetCurrentDir(lCurrentDir);
end;
end;
class function TApplicationContext.pathWithBackslash(const Path: string):
String;
var
ilen: Integer;
begin
Result := Path;
ilen := Length(Result);
if (ilen > 0) and
{$IFDEF UNICODE}
not CharInSet(Result[ilen], ['\', '/'])
{$ELSE}
not (Result[ilen] in ['\', '/'])
{$ENDIF}
then
Result := Result + '\';
end;
class function TApplicationContext.pathWithoutBackslash(const Path: string):
string;
var
I, ilen: Integer;
begin
Result := Path;
ilen := Length(Result);
for I := ilen downto 1 do
begin
{$IFDEF UNICODE}
if not CharInSet(Result[I], ['\', '/', ' ', #13]) then Break;
{$ELSE}
if not (Result[I] in ['\', '/', ' ', #13]) then Break;
{$ENDIF}
end;
if I <> ilen then
SetLength(Result, I);
end;
function TApplicationContext.registerBeanFactory(const pvFactory: IBeanFactory;
const pvNameSapce: PAnsiChar): Integer;
var
lvObj:TFactoryInstanceObject;
lvBeanIDs:array[1..4096] of AnsiChar;
begin
lvObj := TFactoryInstanceObject.Create;
try
lvObj.setFactoryObject(pvFactory);
lvObj.setNameSpace(String(AnsiString(pvNameSapce)));
ZeroMemory(@lvBeanIDs[1], 4096);
lvObj.beanFactory.getBeanList(@lvBeanIDs[1], 4096);
DoRegisterPluginIDS(String(AnsiString(PAnsiChar(@lvBeanIDs[1]))), lvObj);
FFactoryObjectList.AddObject(String(AnsiString(pvNameSapce)), lvObj);
Result := 0;
except
Result := -1;
end;
end;
procedure TApplicationContext.removeRegistedBeans(pvLibFile: string);
var
i:Integer;
// lvNameSpace:String;
lvObj:TBaseFactoryObject;
begin
// lvNameSpace :=ExtractFileName(pvLibFile) + '_' + IntToStr(hashOf(pvLibFile));
// if Length(lvNameSpace) = 0 then Exit;
for i := FBeanMapList.Count - 1 downto 0 do
begin
lvObj := TBaseFactoryObject(FBeanMapList.Objects[i]);
if lvObj.namespace = pvLibFile then
begin
FBeanMapList.Delete(i);
end;
end;
end;
function TApplicationContext.unLoadLibraryFile(pvLibFile: PAnsiChar;
pvRaiseException: Boolean = true): Boolean;
var
lvNameSpace:String;
i:Integer;
lvObj:TBaseFactoryObject;
begin
Result := true;
lvNameSpace :=ExtractFileName(String(AnsiString(pvLibFile))) + '_' +
IntToStr(hashOf(String(AnsiString(pvLibFile))));
if Length(lvNameSpace) = 0 then Exit;
i := FFactoryObjectList.IndexOf(lvNameSpace);
if i <> -1 then
begin
lvObj := TBaseFactoryObject(FFactoryObjectList.Objects[i]);
try
FFactoryObjectList.Delete(i);
removeRegistedBeans(String(AnsiString(pvLibFile)));
lvObj.checkFinalize;
lvObj.cleanup;
lvObj.Free;
except
on E:Exception do
begin
Result := false;
{$IFDEF LOG_ON}
__beanLogger.logMessage(
Format('卸载插件宿主文件时[%s]出现了异常' + sLineBreak + e.Message, [pvLibFile]),
'LOAD_TRACE_');
{$ENDIF}
if pvRaiseException then
begin
raise;
end;
end;
end;
end;
end;
procedure TKeyMapImpl.AfterConstruction;
begin
inherited;
FKeyIntface := TKeyInterface.Create;
end;
procedure TKeyMapImpl.cleanupObjects;
begin
FKeyIntface.clear;
end;
destructor TKeyMapImpl.Destroy;
begin
cleanupObjects;
FKeyIntface.Free;
FKeyIntface := nil;
inherited Destroy;
end;
function TKeyMapImpl.existsObject(const pvKey: PAnsiChar): Boolean;
begin
Result := FKeyIntface.exists(string(AnsiString(pvKey)));
end;
function TKeyMapImpl.getObject(const pvKey: PAnsiChar): IInterface;
begin
Result := FKeyIntface.find(string(AnsiString(pvKey)));
end;
procedure TKeyMapImpl.removeObject(const pvKey: PAnsiChar);
begin
try
FKeyIntface.remove(string(AnsiString(pvKey)));
except
end;
end;
procedure TKeyMapImpl.setObject(const pvKey: PAnsiChar;
const pvIntf: IInterface);
begin
try
FKeyIntface.put(string(AnsiString(pvKey)), pvIntf);
except
end;
end;
function TKeyMapImpl._AddRef: Integer;
begin
Result := inherited _AddRef;
end;
function TKeyMapImpl._Release: Integer;
begin
Result := inherited _Release;
end;
initialization
__beanLogger := TSafeLogger.Create;
__beanLogger.setAppender(TLogFileAppender.Create(False));
__instanceKeyMap := TKeyMapImpl.Create;
__instanceKeyMapKeyIntf := __instanceKeyMap;
__instanceAppContext := TApplicationContext.Create;
__instanceAppContextAppContextIntf := __instanceAppContext;
mybean.core.intf.appPluginContext := __instanceAppContext;
mybean.core.intf.applicationKeyMap := __instanceKeyMap;
// // 初始化
// appPluginContext.checkInitialize;
finalization
applicationContextFinalize;
// 记录未释放的情况
{$IFDEF LOG_ON}
logDebugInfo;
{$ENDIF}
__instanceAppContextAppContextIntf := nil;
__instanceKeyMapKeyIntf := nil;
__beanLogger.Free;
__beanLogger := nil;
end.