iter = parsed_options.find("ansistr_binary");
ansistr_binary_ = (iter != parsed_options.end());
iter = parsed_options.find("register_types");
- register_types_ = (iter != parsed_options.end());
+ register_types_ = (iter != parsed_options.end());
iter = parsed_options.find("constprefix");
- constprefix_ = (iter != parsed_options.end());
+ constprefix_ = (iter != parsed_options.end());
+ iter = parsed_options.find("events");
+ events_ = (iter != parsed_options.end());
out_dir_base_ = "gen-delphi";
void generate_delphi_struct(t_struct* tstruct, bool is_exception);
void generate_delphi_struct_impl( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
- void print_delphi_struct_type_factory_func( ostream& out, t_struct* tstruct);
- void generate_delphi_struct_type_factory( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
- void generate_delphi_struct_type_factory_registration( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
+ void print_delphi_struct_type_factory_func( ostream& out, t_struct* tstruct);
+ void generate_delphi_struct_type_factory( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
+ void generate_delphi_struct_type_factory_registration( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
void generate_delphi_struct_definition(std::ostream& out, t_struct* tstruct, bool is_xception=false, bool in_class=false, bool is_result=false, bool is_x_factory = false);
void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct);
void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct);
std::ostringstream s_const_impl;
std::ostringstream s_struct_impl;
std::ostringstream s_service_impl;
- std::ostringstream s_type_factory_registration;
- std::ostringstream s_type_factory_funcs;
+ std::ostringstream s_type_factory_registration;
+ std::ostringstream s_type_factory_funcs;
bool has_enum;
bool has_const;
std::string namespace_dir_;
bool is_void( t_type* type );
int indent_impl_;
bool ansistr_binary_;
- bool register_types_;
+ bool register_types_;
bool constprefix_;
+ bool events_;
void indent_up_impl(){
++indent_impl_;
};
if (register_types_)
{
- add_delphi_uses_list("Thrift.TypeRegistry");
+ add_delphi_uses_list("Thrift.TypeRegistry");
}
init_known_types_list();
f_all << "const" << endl;
indent_up();
indent(f_all) << "c" << tmp_unit << "_Option_AnsiStr_Binary = " << ( ansistr_binary_ ? "True" : "False") << ";" << endl;
+ indent(f_all) << "c" << tmp_unit << "_Option_Register_Types = " << ( register_types_ ? "True" : "False") << ";" << endl;
+ indent(f_all) << "c" << tmp_unit << "_Option_ConstPrefix = " << ( constprefix_ ? "True" : "False") << ";" << endl;
+ indent(f_all) << "c" << tmp_unit << "_Option_Events = " << ( events_ ? "True" : "False") << ";" << endl;
indent_down();
f_all << "type" << endl;
if (register_types_)
{
- f_all << endl;
- f_all << "// Type factory methods and registration" << endl;
- f_all << s_type_factory_funcs.str();
- f_all << "procedure RegisterTypeFactories;" << endl;
- f_all << "begin" << endl;
- f_all << s_type_factory_registration.str();
- f_all << "end;" << endl;
+ f_all << endl;
+ f_all << "// Type factory methods and registration" << endl;
+ f_all << s_type_factory_funcs.str();
+ f_all << "procedure RegisterTypeFactories;" << endl;
+ f_all << "begin" << endl;
+ f_all << s_type_factory_registration.str();
+ f_all << "end;" << endl;
}
f_all << endl;
f_all << "initialization" << endl;
if ( has_const ) {
- f_all << "{$IF CompilerVersion < 21.0}" << endl;
+ f_all << "{$IF CompilerVersion < 21.0}" << endl;
f_all << " " << constants_class.c_str() << "_Initialize;" << endl;
- f_all << "{$IFEND}" << endl;
+ f_all << "{$IFEND}" << endl;
}
if (register_types_) {
- f_all << " RegisterTypeFactories;" << endl;
+ f_all << " RegisterTypeFactories;" << endl;
}
f_all << endl;
f_all << "finalization" << endl;
if ( has_const ) {
- f_all << "{$IF CompilerVersion < 21.0}" << endl;
+ f_all << "{$IF CompilerVersion < 21.0}" << endl;
f_all << " " << constants_class.c_str() << "_Finalize;" << endl;
- f_all << "{$IFEND}" << endl;
+ f_all << "{$IFEND}" << endl;
}
f_all << endl << endl;
generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception);
if (register_types_) {
- generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception);
- generate_delphi_struct_type_factory_registration(s_type_factory_registration, "", tstruct, is_exception);
+ generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception);
+ generate_delphi_struct_type_factory_registration(s_type_factory_registration, "", tstruct, is_exception);
}
}
}
void t_delphi_generator::print_delphi_struct_type_factory_func( ostream& out, t_struct* tstruct) {
- string struct_intf_name = type_name(tstruct);
- out << "Create_";
- out << struct_intf_name;
- out << "_Impl";
+ string struct_intf_name = type_name(tstruct);
+ out << "Create_";
+ out << struct_intf_name;
+ out << "_Impl";
}
void t_delphi_generator::generate_delphi_struct_type_factory( ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) {
-
- if (is_exception)
- return;
- if (is_result)
- return;
- if (is_x_factory)
- return;
-
- string struct_intf_name = type_name(tstruct);
- string cls_nm = type_name(tstruct,true,false);
-
- out << "function ";
- print_delphi_struct_type_factory_func(out, tstruct);
- out << ": ";
- out << struct_intf_name;
- out << ";" << endl;
- out << "begin" << endl;
- indent_up();
- indent(out) << "Result := " << cls_nm << ".Create;" << endl;
- indent_down();
- out << "end;" << endl << endl;
+
+ if (is_exception)
+ return;
+ if (is_result)
+ return;
+ if (is_x_factory)
+ return;
+
+ string struct_intf_name = type_name(tstruct);
+ string cls_nm = type_name(tstruct,true,false);
+
+ out << "function ";
+ print_delphi_struct_type_factory_func(out, tstruct);
+ out << ": ";
+ out << struct_intf_name;
+ out << ";" << endl;
+ out << "begin" << endl;
+ indent_up();
+ indent(out) << "Result := " << cls_nm << ".Create;" << endl;
+ indent_down();
+ out << "end;" << endl << endl;
}
void t_delphi_generator::generate_delphi_struct_type_factory_registration( ostream& out, string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result, bool is_x_factory) {
- if (is_exception)
- return;
- if (is_result)
- return;
- if (is_x_factory)
- return;
+ if (is_exception)
+ return;
+ if (is_result)
+ return;
+ if (is_x_factory)
+ return;
- string struct_intf_name = type_name(tstruct);
+ string struct_intf_name = type_name(tstruct);
- indent(out) << " TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">(";
- print_delphi_struct_type_factory_func(out, tstruct);
- out << ");";
- out << endl;
+ indent(out) << " TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">(";
+ print_delphi_struct_type_factory_func(out, tstruct);
+ out << ");";
+ out << endl;
}
void t_delphi_generator::generate_delphi_struct_definition(ostream &out, t_struct* tstruct, bool is_exception, bool in_class, bool is_result, bool is_x_factory) {
indent_up();
indent(s_service) << "type" << endl;
indent_up();
- indent(s_service) << "TProcessFunction = reference to procedure( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol);" << endl;
+ indent(s_service) << "TProcessFunction = reference to procedure( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol" <<
+ (events_ ? "; const events : IRequestEvents" : "") <<
+ ");" << endl;
indent_down();
indent_down();
indent(s_service) << "protected" << endl;
indent(s_service) << "public" << endl;
indent_up();
if (extends.empty()) {
- indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol): Boolean;" << endl;
+ indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const events : IProcessorEvents): Boolean;" << endl;
} else {
- indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol): Boolean; reintroduce;" << endl;
+ indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const events : IProcessorEvents): Boolean; reintroduce;" << endl;
}
- indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; const oprot: IProtocol): Boolean;" << endl;;
+ indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; const oprot: IProtocol; const events : IProcessorEvents): Boolean;" << endl;;
indent_impl(s_service_impl) << "var" << endl;
indent_up_impl();
indent_impl(s_service_impl) << "msg : IMessage;" << endl;
indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl;
indent_impl(s_service_impl) << "x : TApplicationException;" << endl;
+ if( events_) {
+ indent_impl(s_service_impl) << "context : IRequestEvents;" << endl;
+ }
indent_down_impl();
indent_impl(s_service_impl) << "begin" << endl;
indent_up_impl();
indent_impl(s_service_impl) << "Exit;" << endl;
indent_down_impl();
indent_impl(s_service_impl) << "end;" << endl;
- indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl;
+ if( events_) {
+ indent_impl(s_service_impl) << "if events <> nil" << endl;
+ indent_impl(s_service_impl) << "then context := events.CreateRequestContext(msg.Name)" << endl;
+ indent_impl(s_service_impl) << "else context := nil;" << endl;
+ indent_impl(s_service_impl) << "try" << endl;
+ indent_up_impl();
+ indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot, context);" << endl;
+ indent_down_impl();
+ indent_impl(s_service_impl) << "finally" << endl;
+ indent_up_impl();
+ indent_impl(s_service_impl) << "if context <> nil then begin" << endl;
+ indent_up_impl();
+ indent_impl(s_service_impl) << "context.CleanupContext;" << endl;
+ indent_impl(s_service_impl) << "context := nil;" << endl;
+ indent_down_impl();
+ indent_impl(s_service_impl) << "end;" << endl;
+ indent_down_impl();
+ indent_impl(s_service_impl) << "end;" << endl;
+ } else {
+ indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl;
+ }
indent_down_impl();
indent_impl(s_service_impl) << "except" << endl;
indent_up_impl();
string result_intfnm = normalize_clsnm(org_resultname, "I");
indent(s_service) <<
- "procedure " << funcname << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol);" << endl;
+ "procedure " << funcname << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol" <<
+ (events_ ? "; const events : IRequestEvents" : "") <<
+ ");" << endl;
if (tfunction->is_oneway()) {
indent_impl(s_service_impl) << "// one way processor" << endl;
}
indent_impl(s_service_impl) <<
- "procedure " << full_cls << "." << funcname << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol);" << endl;
+ "procedure " << full_cls << "." << funcname << "_Process( seqid: Integer; const iprot: IProtocol; const oprot: IProtocol" <<
+ (events_ ? "; const events : IRequestEvents" : "") <<
+ ");" << endl;
indent_impl(s_service_impl) << "var" << endl;
indent_up_impl();
indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl;
indent_down_impl();
indent_impl(s_service_impl) << "begin" << endl;
indent_up_impl();
+
+ if( events_) {
+ indent_impl(s_service_impl) << "if events <> nil then events.PreRead;" << endl;
+ }
indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl;
indent_impl(s_service_impl) << "args.Read(iprot);" << endl;
indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
+ if( events_) {
+ indent_impl(s_service_impl) << "if events <> nil then events.PostRead;" << endl;
+ }
t_struct* xs = tfunction->get_xceptions();
const std::vector<t_field*>& xceptions = xs->get_members();
indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl;
}
- if (!tfunction->is_oneway() && xceptions.size() > 0) {
+ if (events_ || (!tfunction->is_oneway() && xceptions.size() > 0)) {
indent_impl(s_service_impl) << "try" << endl;
indent_up_impl();
}
"args." << prop_name(*f_iter) << " := " << empty_value((*f_iter)->get_type()) << ";" << endl;
}
- if (!tfunction->is_oneway() && xceptions.size() > 0) {
+ if (events_ || (!tfunction->is_oneway() && xceptions.size() > 0)) {
indent_down_impl();
indent_impl(s_service_impl) << "except" << endl;
indent_up_impl();
indent_down_impl();
indent_impl(s_service_impl) << "end;" << endl;
}
+ if( events_) {
+ indent_impl(s_service_impl) << "on E: Exception do" << endl;
+ indent_impl(s_service_impl) << "begin" << endl;
+ indent_up_impl();
+ indent_impl(s_service_impl) << "if events <> nil then events.UnhandledError(E);" << endl;
+ indent_impl(s_service_impl) << "raise; // let it bubble up" << endl;
+ indent_down_impl();
+ indent_impl(s_service_impl) << "end;" << endl;
+ }
indent_down_impl();
indent_impl(s_service_impl) << "end;" << endl;
}
if (! tfunction->is_oneway()) {
+ if (events_) {
+ indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl;
+ }
indent_impl(s_service_impl) << "msg := TMessageImpl.Create('" << tfunction->get_name() << "', TMessageType.Reply, seqid); " << endl;
indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl;
indent_impl(s_service_impl) << "ret.Write(oprot);" << endl;
indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
+ if (events_) {
+ indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl;
+ }
+ } else if (events_) {
+ indent_impl(s_service_impl) << "if events <> nil then events.OnewayComplete;" << endl;
}
indent_down_impl();
" ansistr_binary: Use AnsiString for binary datatype (default is TBytes).\n"
" register_types: Enable TypeRegistry, allows for creation of struct, union\n"
" and container instances by interface or TypeInfo()\n"
-" constprefix: Name TConstants classes after IDL to reduce ambiguities\n");
+" constprefix: Name TConstants classes after IDL to reduce ambiguities\n"
+" events: Enable and use processing events in the generated code.\n");
end;\r
\r
\r
+type\r
+ IRequestEvents = interface\r
+ ['{F926A26A-5B00-4560-86FA-2CAE3BA73DAF}']
+ // Called before reading arguments.
+ procedure PreRead;
+ // Called between reading arguments and calling the handler.
+ procedure PostRead;
+ // Called between calling the handler and writing the response.
+ procedure PreWrite;
+ // Called after writing the response.
+ procedure PostWrite;
+ // Called when an oneway (async) function call completes successfully.
+ procedure OnewayComplete;
+ // Called if the handler throws an undeclared exception.
+ procedure UnhandledError( const e : Exception);
+ // Called when a client has finished request-handling to clean up
+ procedure CleanupContext;
+ end;
+
+
+ IProcessorEvents = interface
+ ['{A8661119-657C-447D-93C5-512E36162A45}']
+ // Called when a client is about to call the processor.
+ procedure Processing( const transport : ITransport);
+ // Called on any service function invocation
+ function CreateRequestContext( const aFunctionName : string) : IRequestEvents;
+ // Called when a client has finished request-handling to clean up
+ procedure CleanupContext;
+ end;
+
+
+ IProcessor = interface
+ ['{7BAE92A5-46DA-4F13-B6EA-0EABE233EE5F}']
+ function Process( const iprot :IProtocol; const oprot: IProtocol; const events : IProcessorEvents): Boolean;
+ end;
+
+\r
+\r
implementation\r
\r
function ConvertInt64ToDouble( const n: Int64): Double;\r
Thrift.Transport;
type
+ IServerEvents = interface
+ ['{9E2A99C5-EE85-40B2-9A52-2D1722B18176}']
+ // Called before the server begins.
+ procedure PreServe;
+ // Called when the server transport is ready to accept requests
+ procedure PreAccept;
+ // Called when a new client has connected and the server is about to being processing.
+ function CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;
+ end;
+
+
IServer = interface
- ['{CF9F56C6-BB39-4C7D-877B-43B416572CE6}']
+ ['{ADC46F2D-8199-4D1C-96D2-87FD54351723}']
procedure Serve;
procedure Stop;
+
+ function GetServerEvents : IServerEvents;
+ procedure SetServerEvents( const value : IServerEvents);
+
+ property ServerEvents : IServerEvents read GetServerEvents write SetServerEvents;
end;
TServerImpl = class abstract( TInterfacedObject, IServer )
FInputProtocolFactory : IProtocolFactory;
FOutputProtocolFactory : IProtocolFactory;
FLogDelegate : TLogDelegate;
+ FServerEvents : IServerEvents;
class procedure DefaultLogDelegate( const str: string);
+ function GetServerEvents : IServerEvents;
+ procedure SetServerEvents( const value : IServerEvents);
+
procedure Serve; virtual; abstract;
procedure Stop; virtual; abstract;
public
const ALogDelegate : TLogDelegate
); overload;
- constructor Create(
+ constructor Create(
const AProcessor :IProcessor;
const AServerTransport: IServerTransport
); overload;
InputTransFactory := TTransportFactoryImpl.Create;
OutputTransFactory := TTransportFactoryImpl.Create;
- //no inherited;
+ //no inherited;
Create(
AProcessor,
AServerTransport,
const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory;
const AProtocolFactory: IProtocolFactory);
begin
- //no inherited;
+ //no inherited;
Create( AProcessor, AServerTransport,
ATransportFactory, ATransportFactory,
AProtocolFactory, AProtocolFactory,
DefaultLogDelegate);
end;
+
+function TServerImpl.GetServerEvents : IServerEvents;
+begin
+ result := FServerEvents;
+end;
+
+
+procedure TServerImpl.SetServerEvents( const value : IServerEvents);
+begin
+ // if you need more than one, provide a specialized IServerEvents implementation
+ FServerEvents := value;
+end;
+
+
{ TSimpleServer }
constructor TSimpleServer.Create( const AProcessor: IProcessor;
OutputTransport : ITransport;
InputProtocol : IProtocol;
OutputProtocol : IProtocol;
+ context : IProcessorEvents;
begin
try
FServerTransport.Listen;
end;
end;
+ if FServerEvents <> nil
+ then FServerEvents.PreServe;
+
client := nil;
while (not FStop) do
begin
InputProtocol := nil;
OutputProtocol := nil;
- client := FServerTransport.Accept;
+ client := FServerTransport.Accept( procedure
+ begin
+ if FServerEvents <> nil\r
+ then FServerEvents.PreAccept;
+ end);\r
+\r
+ if client = nil then begin\r
+ if FStop\r
+ then Abort // silent exception\r
+ else raise TTransportException.Create( 'ServerTransport.Accept() may not return NULL' );\r
+ end;\r
+\r
FLogDelegate( 'Client Connected!');
InputTransport := FInputTransportFactory.GetTransport( client );
OutputTransport := FOutputTransportFactory.GetTransport( client );
InputProtocol := FInputProtocolFactory.GetProtocol( InputTransport );
OutputProtocol := FOutputProtocolFactory.GetProtocol( OutputTransport );
- while ( FProcessor.Process( InputProtocol, OutputProtocol )) do
- begin
- if FStop then Break;
+
+ if FServerEvents <> nil
+ then context := FServerEvents.CreateProcessingContext( InputProtocol, OutputProtocol)
+ else context := nil;
+
+ while not FStop do begin
+ if context <> nil
+ then context.Processing( client);
+ if not FProcessor.Process( InputProtocol, OutputProtocol, context)
+ then Break;
end;
except
FLogDelegate( E.ToString);
end;
end;
+
+ if context <> nil
+ then begin
+ context.CleanupContext;
+ context := nil;
+ end;
+
if InputTransport <> nil then
begin
InputTransport.Close;
FClientAnonWrite : THandle;
protected
- function AcceptImpl: ITransport; override;
+ function Accept(const fnAccepting: TProc): ITransport; override;
function CreateAnonPipe : Boolean;
FTimeout : DWORD;
FHandle : THandle;
FConnected : Boolean;
-\r
-\r protected
- function AcceptImpl: ITransport; override;
+
+
+ protected
+ function Accept(const fnAccepting: TProc): ITransport; override;
function CreateNamedPipe : THandle;
function CreateTransportInstance : ITransport;
end;
-function TAnonymousPipeServerTransportImpl.AcceptImpl: ITransport;
+function TAnonymousPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
var buf : Byte;
br : DWORD;
begin
+ if Assigned(fnAccepting)
+ then fnAccepting();
+
// This 0-byte read serves merely as a blocking call.
if not ReadFile( FReadHandle, buf, 0, br, nil)
and (GetLastError() <> ERROR_MORE_DATA)
end;
-function TNamedPipeServerTransportImpl.AcceptImpl: ITransport;
+function TNamedPipeServerTransportImpl.Accept(const fnAccepting: TProc): ITransport;
var dwError, dwWait, dwDummy : DWORD;
overlapped : TOverlapped;
- event : TEvent;\r
-begin\r
+ event : TEvent;
+begin
FillChar( overlapped, SizeOf(overlapped), 0);
event := TEvent.Create( nil, TRUE, FALSE, ''); // always ManualReset, see MSDN
try
- overlapped.hEvent := event.Handle;\r
-\r
- ASSERT( not FConnected);\r
- while not FConnected do begin\r
+ overlapped.hEvent := event.Handle;
+
+ ASSERT( not FConnected);
+ while not FConnected do begin
InternalClose;
if FStopServer then Abort;
CreateNamedPipe;
+ if Assigned(fnAccepting)
+ then fnAccepting();
+
// Wait for the client to connect; if it succeeds, the
// function returns a nonzero value. If the function returns
// zero, GetLastError should return ERROR_PIPE_CONNECTED.
- if ConnectNamedPipe( Handle, @overlapped)
- then FConnected := TRUE
- else begin
- // ConnectNamedPipe() returns FALSE for OverlappedIO, even if connected.
- // We have to check GetLastError() explicitly to find out\r
- dwError := GetLastError;\r
- case dwError of\r
- ERROR_PIPE_CONNECTED : begin\r
- FConnected := TRUE; // special case: pipe immediately connected\r
- end;\r
-\r
- ERROR_IO_PENDING : begin\r
- dwWait := WaitForSingleObject( overlapped.hEvent, DEFAULT_THRIFT_PIPE_TIMEOUT);\r
- FConnected := (dwWait = WAIT_OBJECT_0)\r
- and GetOverlappedResult( Handle, overlapped, dwDummy, TRUE);\r
- end;\r
-\r
- else\r
- InternalClose;\r
- raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,\r
- 'Client connection failed');
- end;\r
- end;\r
- end;\r
+ if ConnectNamedPipe( Handle, @overlapped) then begin
+ FConnected := TRUE;
+ Break;
+ end;
+
+ // ConnectNamedPipe() returns FALSE for OverlappedIO, even if connected.
+ // We have to check GetLastError() explicitly to find out
+ dwError := GetLastError;
+ case dwError of
+ ERROR_PIPE_CONNECTED : begin
+ FConnected := not FStopServer; // special case: pipe immediately connected
+ end;
+
+ ERROR_IO_PENDING : begin
+ repeat
+ dwWait := WaitForSingleObject( overlapped.hEvent, DEFAULT_THRIFT_PIPE_TIMEOUT);
+ until (dwWait <> WAIT_TIMEOUT) or FStopServer;
+ FConnected := (dwWait = WAIT_OBJECT_0)
+ and GetOverlappedResult( Handle, overlapped, dwDummy, TRUE)
+ and not FStopServer;
+ end;
+
+ else
+ InternalClose;
+ raise TTransportException.Create( TTransportException.TExceptionType.NotOpen,
+ 'Client connection failed');
+ end;
+ end;
// create the transport impl
result := CreateTransportInstance;
finally
- event.Free;\r
+ event.Free;
end;
end;
FConnected := FALSE;
result := TNamedPipeTransportServerEndImpl.Create( hPipe, TRUE);
except
- ClosePipeHandle(hPipe);\r
- raise;\r
- end;\r
+ ClosePipeHandle(hPipe);
+ raise;
+ end;
end;
end;\r
\r
IServerTransport = interface\r
- ['{BF6B7043-DA22-47BF-8B11-2B88EC55FE12}']\r
+ ['{C43B87ED-69EA-47C4-B77C-15E288252900}']\r
procedure Listen;\r
procedure Close;\r
- function Accept: ITransport;\r
+ function Accept( const fnAccepting: TProc): ITransport;\r
end;\r
\r
TServerTransportImpl = class( TInterfacedObject, IServerTransport)\r
protected\r
- function AcceptImpl: ITransport; virtual; abstract;\r
- public\r
procedure Listen; virtual; abstract;\r
procedure Close; virtual; abstract;\r
- function Accept: ITransport;\r
+ function Accept( const fnAccepting: TProc): ITransport; virtual; abstract;\r
end;\r
\r
ITransportFactory = interface\r
FUseBufferedSocket : Boolean;\r
FOwnsServer : Boolean;\r
protected\r
- function AcceptImpl: ITransport; override;\r
+ function Accept( const fnAccepting: TProc) : ITransport; override;\r
public\r
constructor Create( const AServer: TTcpServer ); overload;\r
constructor Create( const AServer: TTcpServer; AClientTimeout: Integer); overload;\r
inherited Create(msg);\r
end;\r
\r
-{ TServerTransportImpl }\r
-\r
-function TServerTransportImpl.Accept: ITransport;\r
-begin\r
- Result := AcceptImpl;\r
- if Result = nil then\r
- begin\r
- raise TTransportException.Create( 'accept() may not return NULL' );\r
- end;\r
-end;\r
-\r
{ TTransportFactoryImpl }\r
\r
function TTransportFactoryImpl.GetTransport( const ATrans: ITransport): ITransport;\r
Create( APort, 0 );\r
end;\r
\r
-function TServerSocketImpl.AcceptImpl: ITransport;\r
+function TServerSocketImpl.Accept( const fnAccepting: TProc): ITransport;\r
var\r
- ret : TCustomIpClient;\r
- ret2 : IStreamTransport;\r
- ret3 : ITransport;\r
+ client : TCustomIpClient;\r
+ trans : IStreamTransport;\r
begin\r
if FServer = nil then\r
begin\r
end;\r
\r
try\r
- ret := TCustomIpClient.Create(nil);\r
- if ( not FServer.Accept( ret )) then\r
+ client := TCustomIpClient.Create(nil);\r
+\r
+ if Assigned(fnAccepting)\r
+ then fnAccepting();\r
+\r
+ if ( not FServer.Accept( client)) then\r
begin\r
- ret.Free;\r
+ client.Free;\r
Result := nil;\r
Exit;\r
end;\r
\r
- if ret = nil then\r
+ if client = nil then\r
begin\r
Result := nil;\r
Exit;\r
end;\r
\r
- ret2 := TSocketImpl.Create( ret );\r
- if FUseBufferedSocket then\r
- begin\r
- ret3 := TBufferedTransportImpl.Create(ret2);\r
- Result := ret3;\r
- end else\r
- begin\r
- Result := ret2;\r
- end;\r
+ trans := TSocketImpl.Create( client);\r
+ if FUseBufferedSocket\r
+ then result := TBufferedTransportImpl.Create( trans)\r
+ else result := trans;\r
\r
except\r
on E: Exception do\r
Version = '1.0.0-dev';
type
- IProcessor = interface
- ['{B1538A07-6CAC-4406-8A4C-AFED07C70A89}']
- function Process( const iprot :IProtocol; const oprot: IProtocol): Boolean;
- end;
-
TApplicationException = class( SysUtils.Exception )
public
type
Thrift.Test,
Thrift,
TestConstants,
+ TestServerEvents,
Contnrs;
type
UseBufferedSockets : Boolean;
UseFramed : Boolean;
Port : Integer;
- AnonPipe : Boolean;
+ AnonPipe, ServerEvents : Boolean;
sPipeName : string;
testHandler : ITestHandler;
testProcessor : IProcessor;
UseBufferedSockets := False;
UseFramed := False;
AnonPipe := FALSE;
+ ServerEvents := FALSE;
protType := prot_Binary;
Port := 9090;
sPipeName := '';
Break;
end;
end;
- end else
+ end
+ else if ( s = '-events' ) then
begin
+ ServerEvents := True;
+ end
+ else begin
// Fall back to the older boolean syntax
UseBufferedSockets := StrToBoolDef( args[1], UseBufferedSockets);
end
testHandler.SetServer( ServerEngine);
+ // test events?
+ if ServerEvents then begin
+ Console.WriteLine('- server events test enabled');
+ ServerEngine.ServerEvents := TServerEventsImpl.Create;
+ end;
+
// start the client now when we have the anon handles, but before the server starts
if AnonPipe
then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
--- /dev/null
+(*
+ * 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.
+ *)
+
+unit TestServerEvents;
+
+interface
+
+uses
+ SysUtils,
+ Thrift,
+ Thrift.Protocol,
+ Thrift.Transport,
+ Thrift.Server,
+ Thrift.Console;
+
+type
+ TRequestEventsImpl = class( TInterfacedObject, IRequestEvents)
+ protected
+ FStart : TDateTime;
+ // IRequestProcessingEvents
+ procedure PreRead;
+ procedure PostRead;
+ procedure PreWrite;
+ procedure PostWrite;
+ procedure OnewayComplete;
+ procedure UnhandledError( const e : Exception);
+ procedure CleanupContext;
+ public
+ constructor Create;
+ end;
+
+
+ TProcessorEventsImpl = class( TInterfacedObject, IProcessorEvents)
+ protected\r
+ FReqs : Integer;\r
+ // IProcessorEvents\r
+ procedure Processing( const transport : ITransport);\r
+ function CreateRequestContext( const aFunctionName : string) : IRequestEvents;
+ procedure CleanupContext;
+ public
+ constructor Create;
+ end;\r
+
+
+ TServerEventsImpl = class( TInterfacedObject, IServerEvents)
+ protected\r
+ // IServerEvents\r
+ procedure PreServe;\r
+ procedure PreAccept;\r
+ function CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;\r
+ end;\r
+
+
+implementation
+
+{ TServerEventsImpl }
+\r
+procedure TServerEventsImpl.PreServe;
+begin\r
+ Console.WriteLine('ServerEvents: Server starting to serve requests');\r
+end;\r
+\r
+\r
+procedure TServerEventsImpl.PreAccept;
+begin\r
+ Console.WriteLine('ServerEvents: Server transport is ready to accept incoming calls');\r
+end;\r
+\r
+\r
+function TServerEventsImpl.CreateProcessingContext(const input, output: IProtocol): IProcessorEvents;
+begin\r
+ result := TProcessorEventsImpl.Create;\r
+end;\r
+\r
+\r
+{ TProcessorEventsImpl }
+\r
+constructor TProcessorEventsImpl.Create;
+begin\r
+ inherited Create;\r
+ FReqs := 0;\r
+ Console.WriteLine('ProcessorEvents: Client connected, processing begins');\r
+end;\r
+\r
+procedure TProcessorEventsImpl.Processing(const transport: ITransport);\r
+begin\r
+ Console.WriteLine('ProcessorEvents: Processing of incoming request begins');\r
+end;\r
+\r
+\r
+function TProcessorEventsImpl.CreateRequestContext( const aFunctionName: string): IRequestEvents;\r
+begin\r
+ result := TRequestEventsImpl.Create;\r
+ Inc( FReqs);\r
+end;\r
+\r
+\r
+procedure TProcessorEventsImpl.CleanupContext;\r
+begin\r
+ Console.WriteLine( 'ProcessorEvents: completed after handling '+IntToStr(FReqs)+' requests.');\r
+end;\r
+\r
+\r
+{ TRequestEventsImpl }\r
+\r
+
+constructor TRequestEventsImpl.Create;
+begin\r
+ inherited Create;\r
+ FStart := Now;\r
+ Console.WriteLine('RequestEvents: New request');\r
+end;\r
+\r
+\r
+procedure TRequestEventsImpl.PreRead;
+begin\r
+ Console.WriteLine('RequestEvents: Reading request message ...');\r
+end;\r
+\r
+
+procedure TRequestEventsImpl.PostRead;
+begin\r
+ Console.WriteLine('RequestEvents: Reading request message completed');\r
+end;\r
+
+procedure TRequestEventsImpl.PreWrite;
+begin\r
+ Console.WriteLine('RequestEvents: Writing response message ...');\r
+end;\r
+\r
+
+procedure TRequestEventsImpl.PostWrite;
+begin\r
+ Console.WriteLine('RequestEvents: Writing response message completed');\r
+end;\r
+\r
+
+procedure TRequestEventsImpl.OnewayComplete;
+begin\r
+ Console.WriteLine('RequestEvents: Oneway message processed');\r
+end;\r
+\r
+
+procedure TRequestEventsImpl.UnhandledError(const e: Exception);
+begin\r
+ Console.WriteLine('RequestEvents: Unhandled exception of type '+e.classname);\r
+end;\r
+\r
+\r
+procedure TRequestEventsImpl.CleanupContext;\r
+var millis : Double;\r
+begin\r
+ millis := (Now - FStart) * (24*60*60*1000);\r
+ Console.WriteLine( 'Request processing completed in '+IntToStr(Round(millis))+' ms');\r
+end;\r
+\r
+\r
+end.
echo.
echo Generating code, please wait ...
cd "%TARGET%"
-for %%a in (*.thrift) do "%BIN%\thrift.exe" -v --gen delphi:ansistr_binary,register_types "%%a" 2>> "%LOGFILE%"
+for %%a in (*.thrift) do "%BIN%\thrift.exe" -v --gen delphi:ansistr_binary,register_types,constprefix,events "%%a" 2>> "%LOGFILE%"
REM * for %%a in (*.thrift) do "%BIN%\thrift.exe" -v --gen cpp "%%a" >> NUL:
cmd /c start notepad "%LOGFILE%"
cd ..
uses
SysUtils,
TestServer in 'TestServer.pas',
+ TestServerEvents in 'TestServerEvents.pas',
Thrift.Test, // in gen-delphi folder
Thrift in '..\src\Thrift.pas',
Thrift.Transport in '..\src\Thrift.Transport.pas',